From 9976397a8256a238c07b1bb513db1749811c0362 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:50:26 +0000 Subject: [PATCH 1/3] Initial Command Box FX selector Needs de-duplication, repeated functions in TableView and PhraseView --- .../Application/Instruments/CommandList.cpp | 61 +++- sources/Application/Instruments/CommandList.h | 10 +- .../Application/Views/CommandSelectorCommon.h | 297 ++++++++++++++++++ sources/Application/Views/PhraseView.cpp | 123 +++++++- sources/Application/Views/PhraseView.h | 8 + sources/Application/Views/TableView.cpp | 127 +++++++- sources/Application/Views/TableView.h | 8 + 7 files changed, 605 insertions(+), 29 deletions(-) create mode 100644 sources/Application/Views/CommandSelectorCommon.h diff --git a/sources/Application/Instruments/CommandList.cpp b/sources/Application/Instruments/CommandList.cpp index 574d12cb..812385c2 100644 --- a/sources/Application/Instruments/CommandList.cpp +++ b/sources/Application/Instruments/CommandList.cpp @@ -31,23 +31,54 @@ static FourCC _all[]= { I_CMD_VOLM } ; +int CommandList::GetCount() { return sizeof(_all) / sizeof(FourCC); } + +FourCC CommandList::GetAt(int index) { + int count = GetCount() ; + if (count <= 0) { + return I_CMD_NONE ; + } + while (index < 0) { + index += count; + } + index %= count; + return _all[index] ; +} + +int CommandList::IndexOf(FourCC current) { + for (int i=0;i= startX && x <= endX && y >= startY && y <= endY; +} + +inline int wrapIndex(int index) { + int count = getCount(); + if (count <= 0) { + return 0; + } + while (index < 0) { + index += count; + } + return index % count; +} + +inline int getSelectedIndex(FourCC command) { + int idx = CommandList::IndexOf(command); + if (idx < 0) { + return 0; + } + return idx; +} + +inline bool isCommandColumn(int col, int c1, int c2) { + return col == c1 || col == c2; +} + +inline bool isCommandColumn(int col, int c1, int c2, int c3) { + return col == c1 || col == c2 || col == c3; +} + +inline FourCC *getCommandPointerByCol(int col, int c1, FourCC *p1, int c2, + FourCC *p2) { + if (col == c1) { + return p1; + } + if (col == c2) { + return p2; + } + return 0; +} + +inline FourCC *getCommandPointerByCol(int col, int c1, FourCC *p1, int c2, + FourCC *p2, int c3, FourCC *p3) { + if (col == c1) { + return p1; + } + if (col == c2) { + return p2; + } + if (col == c3) { + return p3; + } + return 0; +} + +inline FourCC atIndex(int index) { + return CommandList::GetAt(wrapIndex(index)); +} + +inline FourCC stepHorizontal(FourCC current, int delta) { + int count = getCount(); + if (count <= 0) { + return I_CMD_NONE; + } + + int rows = getRows(); + int idx = getSelectedIndex(current); + int col = idx % kColumns; + int row = idx / kColumns; + + col += delta; + if (col < 0) { + col = kColumns - 1; + } else if (col >= kColumns) { + col = 0; + } + + int candidate = row * kColumns + col; + while (candidate >= count) { + col += (delta < 0) ? -1 : 1; + if (col < 0) { + col = kColumns - 1; + } else if (col >= kColumns) { + col = 0; + } + candidate = row * kColumns + col; + } + + return atIndex(candidate); +} + +inline FourCC stepVertical(FourCC current, int rowDelta) { + int count = getCount(); + if (count <= 0) { + return I_CMD_NONE; + } + + int rows = getRows(); + int idx = getSelectedIndex(current); + int col = idx % kColumns; + int row = idx / kColumns; + + row += rowDelta; + if (row < 0) { + row = rows - 1; + } else if (row >= rows) { + row = 0; + } + + int candidate = row * kColumns + col; + while (candidate >= count) { + row += (rowDelta < 0) ? -1 : 1; + if (row < 0) { + row = rows - 1; + } else if (row >= rows) { + row = 0; + } + candidate = row * kColumns + col; + } + + return atIndex(candidate); +} + +inline FourCC stepByDirection(FourCC current, ViewUpdateDirection direction) { + switch (direction) { + case VUD_LEFT: + return stepHorizontal(current, -1); + case VUD_RIGHT: + return stepHorizontal(current, 1); + case VUD_UP: + return stepVertical(current, -1); + case VUD_DOWN: + return stepVertical(current, 1); + } + return current; +} + +template +inline void enterSelector(bool commandColumn, GetCommandPtrFn getCommandPointer, + bool &active, FourCC &original, bool &dirty) { + if (!commandColumn) { + return; + } + FourCC *command = getCommandPointer(); + if (!command) { + return; + } + original = *command; + active = true; + dirty = true; +} + +template +inline void leaveSelector(bool commit, GetCommandPtrFn getCommandPointer, + bool &active, FourCC original, int &lastCmd, + bool &dirty) { + if (!active) { + return; + } + if (!commit) { + FourCC *command = getCommandPointer(); + if (command) { + *command = original; + lastCmd = *command; + } + } + active = false; + dirty = true; +} + +template +inline void stepSelector(ViewUpdateDirection direction, + GetCommandPtrFn getCommandPointer, bool active, + int &lastCmd, bool &dirty) { + if (!active) { + return; + } + FourCC *command = getCommandPointer(); + if (!command) { + return; + } + *command = stepByDirection(*command, direction); + lastCmd = *command; + dirty = true; +} + +template +inline void drawPopup(FourCC selectedCommand, const GUIPoint &anchor, + GUITextProperties &props, SetColorFn setColor, + DrawStringFn drawString) { + const int columns = kColumns; + const int rows = getRows(); + const int count = getCount(); + int selectedIndex = getSelectedIndex(selectedCommand); + + int startY = getPopupStartY(anchor); + int startX = getPopupStartX(); + + GUITextProperties boxProps = props; + boxProps.invert_ = false; + setColor(CD_BORDER); + + char borderTop[28]; + char borderMid[28]; + char borderBottom[28]; + borderTop[0] = '+'; + borderMid[0] = '|'; + borderBottom[0] = '+'; + int innerWidth = getPopupInnerWidth(); + for (int i = 1; i <= innerWidth; i++) { + borderTop[i] = '-'; + borderMid[i] = ' '; + borderBottom[i] = '-'; + } + borderTop[innerWidth + 1] = '+'; + borderMid[innerWidth + 1] = '|'; + borderBottom[innerWidth + 1] = '+'; + borderTop[innerWidth + 2] = 0; + borderMid[innerWidth + 2] = 0; + borderBottom[innerWidth + 2] = 0; + + drawString(startX - 1, startY - 1, borderTop, boxProps); + for (int r = 0; r < rows; r++) { + drawString(startX - 1, startY + r, borderMid, boxProps); + } + drawString(startX - 1, startY + rows, borderBottom, boxProps); + + GUITextProperties cellProps = props; + char cellStr[5]; + for (int r = 0; r < rows; r++) { + for (int c = 0; c < columns; c++) { + int index = r * columns + c; + bool isSelected = (index == selectedIndex); + + if (index < count) { + fourCC2char(CommandList::GetAt(index), cellStr); + cellStr[4] = 0; + } else { + cellStr[0] = ' '; + cellStr[1] = ' '; + cellStr[2] = ' '; + cellStr[3] = ' '; + cellStr[4] = 0; + } + + setColor(CD_NORMAL); + cellProps.invert_ = isSelected; + drawString(startX + c * kCellPitch, startY + r, cellStr, cellProps); + } + } + + setColor(CD_NORMAL); +} + +} // namespace CommandSelectorCommon + +#endif diff --git a/sources/Application/Views/PhraseView.cpp b/sources/Application/Views/PhraseView.cpp index 75ac15bf..11a5d81c 100644 --- a/sources/Application/Views/PhraseView.cpp +++ b/sources/Application/Views/PhraseView.cpp @@ -4,6 +4,7 @@ #include "Application/Model/Table.h" #include "Application/Utils/HelpLegend.h" #include "Application/Utils/char.h" +#include "Application/Views/CommandSelectorCommon.h" #include "System/Console/Trace.h" #include "UIController.h" #include @@ -25,6 +26,8 @@ PhraseView::PhraseView(GUIWindow &w, ViewData *viewData) lastInstr_ = 0; lastCmd_ = I_CMD_NONE; lastParam_ = 0; + commandSelectorActive_ = false; + commandSelectorOriginal_ = I_CMD_NONE; clipboard_.active_ = false; clipboard_.width_ = 0; @@ -41,6 +44,10 @@ PhraseView::~PhraseView() { delete cmdEditField_; }; void PhraseView::updateCursor(int dx, int dy) { + if (commandSelectorActive_ && (dx != 0 || dy != 0)) { + leaveCommandSelector(true); + } + col_ += dx; row_ += dy; if (col_ > 5) @@ -110,6 +117,51 @@ void PhraseView::stopAudition() { player->Stop(); } +bool PhraseView::isCommandColumn() const { return col_ == 2 || col_ == 4; } + +FourCC *PhraseView::getCurrentCommandPointer() { + return CommandSelectorCommon::getCommandPointerByCol( + col_, 2, phrase_->cmd1_ + (16 * viewData_->currentPhrase_ + row_), 4, + phrase_->cmd2_ + (16 * viewData_->currentPhrase_ + row_)); +} + +void PhraseView::enterCommandSelector() { + CommandSelectorCommon::enterSelector( + isCommandColumn(), [this]() { return getCurrentCommandPointer(); }, + commandSelectorActive_, commandSelectorOriginal_, isDirty_); +} + +void PhraseView::leaveCommandSelector(bool commit) { + CommandSelectorCommon::leaveSelector( + commit, [this]() { return getCurrentCommandPointer(); }, + commandSelectorActive_, commandSelectorOriginal_, lastCmd_, isDirty_); +} + +void PhraseView::stepCommandSelector(ViewUpdateDirection direction) { + CommandSelectorCommon::stepSelector( + direction, [this]() { return getCurrentCommandPointer(); }, + commandSelectorActive_, lastCmd_, isDirty_); +} + +void PhraseView::drawCommandSelector(GUITextProperties &props) { + if (!commandSelectorActive_) { + return; + } + FourCC *command = getCurrentCommandPointer(); + if (!command) { + return; + } + + GUIPoint anchor = GetAnchor(); + CommandSelectorCommon::drawPopup( + *command, anchor, props, + [this](ColorDefinition color) { SetColor(color); }, + [this](int x, int y, const char *txt, GUITextProperties &textProps) { + DrawString(x, y, txt, textProps); + }); + props.invert_ = false; +} + void PhraseView::updateCursorValue(ViewUpdateDirection direction, int xOffset, int yOffset) { @@ -759,6 +811,7 @@ void PhraseView::switchSoloMode() { void PhraseView::OnFocus() { clipboard_.active_ = false; viewMode_ = VM_NORMAL; + commandSelectorActive_ = false; updateCursor(0, 0); }; @@ -908,6 +961,29 @@ void PhraseView::processNormalButtonMask(unsigned short mask) { Player *player = Player::GetInstance(); + if (commandSelectorActive_) { + if (mask & EPBM_B) { + leaveCommandSelector(false); + return; + } + if (mask == EPBM_A) { + leaveCommandSelector(true); + return; + } + if (mask & EPBM_A) { + if (mask & EPBM_LEFT) + stepCommandSelector(VUD_LEFT); + if (mask & EPBM_RIGHT) + stepCommandSelector(VUD_RIGHT); + if (mask & EPBM_UP) + stepCommandSelector(VUD_UP); + if (mask & EPBM_DOWN) + stepCommandSelector(VUD_DOWN); + return; + } + leaveCommandSelector(true); + } + if (mask & EPBM_B) { if (mask & EPBM_LEFT) warpToNeighbour(-1); @@ -939,9 +1015,11 @@ void PhraseView::processNormalButtonMask(unsigned short mask) { player->OnStartButton(PM_AUDITION, viewData_->songX_, false, viewData_->chainRow_); } if (mask & EPBM_DOWN) - updateCursorValue(VUD_DOWN); + isCommandColumn() ? enterCommandSelector() + : updateCursorValue(VUD_DOWN); if (mask & EPBM_UP) - updateCursorValue(VUD_UP); + isCommandColumn() ? enterCommandSelector() + : updateCursorValue(VUD_UP); if (mask & EPBM_LEFT) updateCursorValue(VUD_LEFT); if (mask & EPBM_RIGHT) @@ -1370,21 +1448,26 @@ void PhraseView::DrawView() { cmdEditField_->SetFocus(); cmdEditField_->Draw(w_); }; + + drawCommandSelector(props); }; void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { + GUITextProperties props; drawNotes(); GUIPoint anchor = GetAnchor(); GUIPoint pos = anchor; pos._x -= 1; - GUITextProperties props; SetColor(CD_NORMAL); pos._y = anchor._y + lastPlayingPos_; - DrawString(pos._x, pos._y, " ", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { + DrawString(pos._x, pos._y, " ", props); + } Player *player = Player::GetInstance(); @@ -1399,12 +1482,16 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { viewData_->currentPhrase_ && viewData_->playMode_ != PM_AUDITION) { pos._y = anchor._y + viewData_->phrasePlayPos_[i]; - if (!player->IsChannelMuted(i)) { - SetColor(CD_PLAY); - DrawString(pos._x, pos._y, ">", props); - } else { - SetColor(CD_MUTE); - DrawString(pos._x, pos._y, "-", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint( + anchor, pos._x, pos._y)) { + if (!player->IsChannelMuted(i)) { + SetColor(CD_PLAY); + DrawString(pos._x, pos._y, ">", props); + } else { + SetColor(CD_MUTE); + DrawString(pos._x, pos._y, "-", props); + } } SetColor(CD_NORMAL); lastPlayingPos_ = viewData_->phrasePlayPos_[i]; @@ -1416,7 +1503,11 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { // clear any live indicator pos._y = anchor._y; - DrawString(pos._x, pos._y, " ", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, + pos._y)) { + DrawString(pos._x, pos._y, " ", props); + } // Loop on all channels to see if one has queued current chain if (player->GetSequencerMode() == SM_LIVE) { @@ -1430,7 +1521,11 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { viewData_->song_->data_ + i + 8 * songPos; if (*chain == viewData_->currentChain_) { char *indicator = player->GetLiveIndicator(i); - DrawString(pos._x, pos._y, indicator, props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint( + anchor, pos._x, pos._y)) { + DrawString(pos._x, pos._y, indicator, props); + } break; } } @@ -1438,6 +1533,10 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { } } + if (commandSelectorActive_) { + drawCommandSelector(props); + } + pos = anchor; pos._x += 200; diff --git a/sources/Application/Views/PhraseView.h b/sources/Application/Views/PhraseView.h index 1e266254..e1a2c4aa 100644 --- a/sources/Application/Views/PhraseView.h +++ b/sources/Application/Views/PhraseView.h @@ -23,6 +23,12 @@ class PhraseView : public View { void stopAudition(); void updateCursorValue(ViewUpdateDirection offset, int xOffset = 0, int yOffset = 0); + bool isCommandColumn() const; + FourCC *getCurrentCommandPointer(); + void enterCommandSelector(); + void leaveCommandSelector(bool commit); + void stepCommandSelector(ViewUpdateDirection direction); + void drawCommandSelector(GUITextProperties &props); void updateSelectionValue(ViewUpdateDirection direction); void warpToNeighbour(int offset); void warpInChain(int offset); @@ -54,6 +60,8 @@ class PhraseView : public View { int lastInstr_; int lastCmd_; int lastParam_; + bool commandSelectorActive_; + FourCC commandSelectorOriginal_; Phrase *phrase_; int lastPlayingPos_; Variable cmdEdit_; diff --git a/sources/Application/Views/TableView.cpp b/sources/Application/Views/TableView.cpp index 1fe50cad..03371f2e 100644 --- a/sources/Application/Views/TableView.cpp +++ b/sources/Application/Views/TableView.cpp @@ -3,6 +3,7 @@ #include "Application/Player/TablePlayback.h" #include "Application/Utils/HelpLegend.h" #include "Application/Utils/char.h" +#include "Application/Views/CommandSelectorCommon.h" #define FCC_EDIT MAKE_FOURCC('T', 'B', 'E', 'D') @@ -19,6 +20,8 @@ TableView::TableView(GUIWindow &w, ViewData *viewData) lastTsp_ = 0; lastCmd_ = I_CMD_NONE; lastParam_ = 0; + commandSelectorActive_ = false; + commandSelectorOriginal_ = I_CMD_NONE; clipboard_.active_ = false; clipboard_.width_ = 0; @@ -31,6 +34,7 @@ void TableView::OnFocus() { clipboard_.active_ = false; viewMode_ = VM_NORMAL; lastPosition_[0] = lastPosition_[1] = lastPosition_[2] = 0; + commandSelectorActive_ = false; updateCursor(0, 0); }; @@ -309,6 +313,11 @@ void TableView::pasteClipboard() { }; void TableView::updateCursor(int dx, int dy) { + + if (commandSelectorActive_ && (dx != 0 || dy != 0)) { + leaveCommandSelector(true); + } + col_ += dx; row_ += dy; if (col_ > 5) @@ -503,6 +512,55 @@ void TableView::updateCursorValue(int offset) { isDirty_ = true; } +bool TableView::isCommandColumn() const { + return CommandSelectorCommon::isCommandColumn(col_, 0, 2, 4); +} + +FourCC *TableView::getCurrentCommandPointer() { + Table &table = + TableHolder::GetInstance()->GetTable(viewData_->currentTable_); + return CommandSelectorCommon::getCommandPointerByCol( + col_, 0, table.cmd1_ + row_, 2, table.cmd2_ + row_, 4, + table.cmd3_ + row_); +} + +void TableView::enterCommandSelector() { + CommandSelectorCommon::enterSelector( + isCommandColumn(), [this]() { return getCurrentCommandPointer(); }, + commandSelectorActive_, commandSelectorOriginal_, isDirty_); +} + +void TableView::leaveCommandSelector(bool commit) { + CommandSelectorCommon::leaveSelector( + commit, [this]() { return getCurrentCommandPointer(); }, + commandSelectorActive_, commandSelectorOriginal_, lastCmd_, isDirty_); +} + +void TableView::stepCommandSelector(ViewUpdateDirection direction) { + CommandSelectorCommon::stepSelector( + direction, [this]() { return getCurrentCommandPointer(); }, + commandSelectorActive_, lastCmd_, isDirty_); +} + +void TableView::drawCommandSelector(GUITextProperties &props) { + if (!commandSelectorActive_) { + return; + } + FourCC *command = getCurrentCommandPointer(); + if (!command) { + return; + } + + GUIPoint anchor = GetAnchor(); + CommandSelectorCommon::drawPopup( + *command, anchor, props, + [this](ColorDefinition color) { SetColor(color); }, + [this](int x, int y, const char *txt, GUITextProperties &textProps) { + DrawString(x, y, txt, textProps); + }); + props.invert_ = false; +} + void TableView::pasteLast() { uint *i = 0; @@ -574,6 +632,29 @@ void TableView::processNormalButtonMask(unsigned short mask) { Player *player = Player::GetInstance(); + if (commandSelectorActive_) { + if (mask & EPBM_B) { + leaveCommandSelector(false); + return; + } + if (mask == EPBM_A) { + leaveCommandSelector(true); + return; + } + if (mask & EPBM_A) { + if (mask & EPBM_LEFT) + stepCommandSelector(VUD_LEFT); + if (mask & EPBM_RIGHT) + stepCommandSelector(VUD_RIGHT); + if (mask & EPBM_UP) + stepCommandSelector(VUD_UP); + if (mask & EPBM_DOWN) + stepCommandSelector(VUD_DOWN); + return; + } + leaveCommandSelector(true); + } + if (mask & EPBM_B) { if (mask & EPBM_LEFT) warpToNeighbour(-1); @@ -594,9 +675,11 @@ void TableView::processNormalButtonMask(unsigned short mask) { if (mask & EPBM_A) { if (mask & EPBM_DOWN) - updateCursorValue(-0x10); + isCommandColumn() ? enterCommandSelector() + : updateCursorValue(-0x10); if (mask & EPBM_UP) - updateCursorValue(0x10); + isCommandColumn() ? enterCommandSelector() + : updateCursorValue(0x10); if (mask & EPBM_LEFT) updateCursorValue(-0x01); if (mask & EPBM_RIGHT) @@ -915,6 +998,8 @@ void TableView::DrawView() { if (player->IsRunning()) { OnPlayerUpdate(PET_UPDATE); }; + + drawCommandSelector(props); } void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { @@ -925,15 +1010,24 @@ void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { pos._x = anchor._x - 1; pos._y = anchor._y + lastPosition_[0]; - DrawString(pos._x, pos._y, " ", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { + DrawString(pos._x, pos._y, " ", props); + } pos._x += 10; pos._y = anchor._y + lastPosition_[1]; - DrawString(pos._x, pos._y, " ", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { + DrawString(pos._x, pos._y, " ", props); + } pos._x += 10; pos._y = anchor._y + lastPosition_[2]; - DrawString(pos._x, pos._y, " ", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { + DrawString(pos._x, pos._y, " ", props); + } TableHolder *th = TableHolder::GetInstance(); // Get current channel @@ -951,18 +1045,33 @@ void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { pos._x = anchor._x - 1; pos._y = anchor._y + lastPosition_[0]; - SetColor(CD_PLAY); - DrawString(pos._x, pos._y, ">", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, + pos._y)) { + SetColor(CD_PLAY); + DrawString(pos._x, pos._y, ">", props); + } pos._x += 10; pos._y = anchor._y + lastPosition_[1]; - DrawString(pos._x, pos._y, ">", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, + pos._y)) { + DrawString(pos._x, pos._y, ">", props); + } pos._x += 10; pos._y = anchor._y + lastPosition_[2]; - DrawString(pos._x, pos._y, ">", props); + if (!commandSelectorActive_ || + !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, + pos._y)) { + DrawString(pos._x, pos._y, ">", props); + } }; drawNotes(); + if (commandSelectorActive_) { + drawCommandSelector(props); + } } void TableView::printHelpLegend(FourCC command, GUITextProperties props) { diff --git a/sources/Application/Views/TableView.h b/sources/Application/Views/TableView.h index db11ca99..4866265e 100644 --- a/sources/Application/Views/TableView.h +++ b/sources/Application/Views/TableView.h @@ -31,6 +31,12 @@ class TableView : public View { void updateCursor(int dx, int dy); void updateCursorValue(int offset); + bool isCommandColumn() const; + FourCC *getCurrentCommandPointer(); + void enterCommandSelector(); + void leaveCommandSelector(bool commit); + void stepCommandSelector(ViewUpdateDirection direction); + void drawCommandSelector(GUITextProperties &props); void setTextProps(GUITextProperties &props, int row, int col, bool restore); void warpToNeighbour(int dir); @@ -44,6 +50,8 @@ class TableView : public View { uchar lastTsp_; int lastCmd_; int lastParam_; + bool commandSelectorActive_; + FourCC commandSelectorOriginal_; Variable cmdEdit_; UIBigHexVarField *cmdEditField_; From 9b32c158ed2e4d6239aa6710be0f413bdee0fcf1 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 23 Apr 2026 19:28:09 +0000 Subject: [PATCH 2/3] Re-design using ModalDialog Remove a lot of dead code and duplication --- projects/Makefile | 2 +- .../Application/Views/CommandSelectorCommon.h | 231 +----------------- .../ModalDialogs/CommandSelectorModal.cpp | 178 ++++++++++++++ .../Views/ModalDialogs/CommandSelectorModal.h | 38 +++ sources/Application/Views/PhraseView.cpp | 128 ++++------ sources/Application/Views/PhraseView.h | 10 +- sources/Application/Views/TableView.cpp | 122 ++++----- sources/Application/Views/TableView.h | 8 +- 8 files changed, 320 insertions(+), 397 deletions(-) create mode 100644 sources/Application/Views/ModalDialogs/CommandSelectorModal.cpp create mode 100644 sources/Application/Views/ModalDialogs/CommandSelectorModal.h diff --git a/projects/Makefile b/projects/Makefile index f735c9d7..9fc7e43d 100644 --- a/projects/Makefile +++ b/projects/Makefile @@ -252,7 +252,7 @@ COMMONFILES := \ View.o ModalView.o FieldView.o UIField.o UIIntField.o \ UIIntVarOffField.o UIIntVarField.o ViewEvent.o I_Action.o\ UITempoField.o UIActionField.o \ - MessageBox.o \ + MessageBox.o CommandSelectorModal.o \ GrooveView.o UINoteVarField.o UIBigHexVarField.o \ SRPUpdaters.o UIStaticField.o \ Song.o Chain.o Phrase.o Project.o Scale.o \ diff --git a/sources/Application/Views/CommandSelectorCommon.h b/sources/Application/Views/CommandSelectorCommon.h index 89f9c4d0..07927f2b 100644 --- a/sources/Application/Views/CommandSelectorCommon.h +++ b/sources/Application/Views/CommandSelectorCommon.h @@ -2,23 +2,20 @@ #define _COMMAND_SELECTOR_COMMON_H_ #include "Application/Instruments/CommandList.h" -#include "Application/Utils/char.h" #include "Application/Views/BaseClasses/View.h" namespace CommandSelectorCommon { static const int kColumns = 5; + static const int kCellPitch = 5; static const int kScreenCenterX = 20; - inline int getPopupInnerWidth() { return kColumns * kCellPitch; } - inline int getPopupStartX() { return kScreenCenterX - (getPopupInnerWidth() / 2); } - -inline int getCount() { return CommandList::GetCount(); } +inline int getDisplayCount() { return CommandList::GetCount() - 1; } inline int getRows() { - int count = getCount(); + int count = getDisplayCount(); return (count + kColumns - 1) / kColumns; } @@ -36,30 +33,11 @@ inline int getPopupStartY(const GUIPoint &anchor) { inline bool popupContainsPoint(const GUIPoint &anchor, int x, int y) { int startX = getPopupStartX() - 1; int endX = getPopupStartX() + getPopupInnerWidth(); - int startY = getPopupStartY(anchor) - 1; - int endY = getPopupStartY(anchor) + getRows(); + int startY = getPopupStartY(anchor) - 4; // Magic number for top border + int endY = getPopupStartY(anchor) + getRows() - 1; // Magic number for bottom border return x >= startX && x <= endX && y >= startY && y <= endY; } -inline int wrapIndex(int index) { - int count = getCount(); - if (count <= 0) { - return 0; - } - while (index < 0) { - index += count; - } - return index % count; -} - -inline int getSelectedIndex(FourCC command) { - int idx = CommandList::IndexOf(command); - if (idx < 0) { - return 0; - } - return idx; -} - inline bool isCommandColumn(int col, int c1, int c2) { return col == c1 || col == c2; } @@ -93,205 +71,6 @@ inline FourCC *getCommandPointerByCol(int col, int c1, FourCC *p1, int c2, return 0; } -inline FourCC atIndex(int index) { - return CommandList::GetAt(wrapIndex(index)); -} - -inline FourCC stepHorizontal(FourCC current, int delta) { - int count = getCount(); - if (count <= 0) { - return I_CMD_NONE; - } - - int rows = getRows(); - int idx = getSelectedIndex(current); - int col = idx % kColumns; - int row = idx / kColumns; - - col += delta; - if (col < 0) { - col = kColumns - 1; - } else if (col >= kColumns) { - col = 0; - } - - int candidate = row * kColumns + col; - while (candidate >= count) { - col += (delta < 0) ? -1 : 1; - if (col < 0) { - col = kColumns - 1; - } else if (col >= kColumns) { - col = 0; - } - candidate = row * kColumns + col; - } - - return atIndex(candidate); -} - -inline FourCC stepVertical(FourCC current, int rowDelta) { - int count = getCount(); - if (count <= 0) { - return I_CMD_NONE; - } - - int rows = getRows(); - int idx = getSelectedIndex(current); - int col = idx % kColumns; - int row = idx / kColumns; - - row += rowDelta; - if (row < 0) { - row = rows - 1; - } else if (row >= rows) { - row = 0; - } - - int candidate = row * kColumns + col; - while (candidate >= count) { - row += (rowDelta < 0) ? -1 : 1; - if (row < 0) { - row = rows - 1; - } else if (row >= rows) { - row = 0; - } - candidate = row * kColumns + col; - } - - return atIndex(candidate); -} - -inline FourCC stepByDirection(FourCC current, ViewUpdateDirection direction) { - switch (direction) { - case VUD_LEFT: - return stepHorizontal(current, -1); - case VUD_RIGHT: - return stepHorizontal(current, 1); - case VUD_UP: - return stepVertical(current, -1); - case VUD_DOWN: - return stepVertical(current, 1); - } - return current; -} - -template -inline void enterSelector(bool commandColumn, GetCommandPtrFn getCommandPointer, - bool &active, FourCC &original, bool &dirty) { - if (!commandColumn) { - return; - } - FourCC *command = getCommandPointer(); - if (!command) { - return; - } - original = *command; - active = true; - dirty = true; -} - -template -inline void leaveSelector(bool commit, GetCommandPtrFn getCommandPointer, - bool &active, FourCC original, int &lastCmd, - bool &dirty) { - if (!active) { - return; - } - if (!commit) { - FourCC *command = getCommandPointer(); - if (command) { - *command = original; - lastCmd = *command; - } - } - active = false; - dirty = true; -} - -template -inline void stepSelector(ViewUpdateDirection direction, - GetCommandPtrFn getCommandPointer, bool active, - int &lastCmd, bool &dirty) { - if (!active) { - return; - } - FourCC *command = getCommandPointer(); - if (!command) { - return; - } - *command = stepByDirection(*command, direction); - lastCmd = *command; - dirty = true; -} - -template -inline void drawPopup(FourCC selectedCommand, const GUIPoint &anchor, - GUITextProperties &props, SetColorFn setColor, - DrawStringFn drawString) { - const int columns = kColumns; - const int rows = getRows(); - const int count = getCount(); - int selectedIndex = getSelectedIndex(selectedCommand); - - int startY = getPopupStartY(anchor); - int startX = getPopupStartX(); - - GUITextProperties boxProps = props; - boxProps.invert_ = false; - setColor(CD_BORDER); - - char borderTop[28]; - char borderMid[28]; - char borderBottom[28]; - borderTop[0] = '+'; - borderMid[0] = '|'; - borderBottom[0] = '+'; - int innerWidth = getPopupInnerWidth(); - for (int i = 1; i <= innerWidth; i++) { - borderTop[i] = '-'; - borderMid[i] = ' '; - borderBottom[i] = '-'; - } - borderTop[innerWidth + 1] = '+'; - borderMid[innerWidth + 1] = '|'; - borderBottom[innerWidth + 1] = '+'; - borderTop[innerWidth + 2] = 0; - borderMid[innerWidth + 2] = 0; - borderBottom[innerWidth + 2] = 0; - - drawString(startX - 1, startY - 1, borderTop, boxProps); - for (int r = 0; r < rows; r++) { - drawString(startX - 1, startY + r, borderMid, boxProps); - } - drawString(startX - 1, startY + rows, borderBottom, boxProps); - - GUITextProperties cellProps = props; - char cellStr[5]; - for (int r = 0; r < rows; r++) { - for (int c = 0; c < columns; c++) { - int index = r * columns + c; - bool isSelected = (index == selectedIndex); - - if (index < count) { - fourCC2char(CommandList::GetAt(index), cellStr); - cellStr[4] = 0; - } else { - cellStr[0] = ' '; - cellStr[1] = ' '; - cellStr[2] = ' '; - cellStr[3] = ' '; - cellStr[4] = 0; - } - - setColor(CD_NORMAL); - cellProps.invert_ = isSelected; - drawString(startX + c * kCellPitch, startY + r, cellStr, cellProps); - } - } - - setColor(CD_NORMAL); -} - } // namespace CommandSelectorCommon #endif diff --git a/sources/Application/Views/ModalDialogs/CommandSelectorModal.cpp b/sources/Application/Views/ModalDialogs/CommandSelectorModal.cpp new file mode 100644 index 00000000..e74d170f --- /dev/null +++ b/sources/Application/Views/ModalDialogs/CommandSelectorModal.cpp @@ -0,0 +1,178 @@ +#include "CommandSelectorModal.h" +#include "Application/Utils/HelpLegend.h" +#include "Application/Utils/char.h" + +static int GetDisplayCommandCount() { + int count = CommandList::GetCount() - 1; + return (count > 0) ? count : 0; +} + +static FourCC GetDisplayCommandAt(int index) { + return CommandList::GetAt(index + 1); +} + +CommandSelectorModal::CommandSelectorModal(View &parentView, + FourCC *liveTarget, + ModalViewCallback previewCb): + ModalView(parentView), + selectedRow_(0), + selectedCol_(0), + selectedCommand_(I_CMD_NONE), + parentView_(parentView), + liveTarget_(liveTarget), + savedCmd_(liveTarget ? *liveTarget : I_CMD_NONE), + previewCb_(previewCb) { + FourCC initial = liveTarget_ ? *liveTarget_ : I_CMD_NONE; + if (initial != I_CMD_NONE) { + moveToCommand(initial); + } else { + moveToCommand(I_CMD_ARPG); + } +} + +CommandSelectorModal::~CommandSelectorModal() {} + +int CommandSelectorModal::commandToRow(FourCC command) const { + int idx = CommandList::IndexOf(command) - 1; + if (idx < 0) { + return 0; + } + return idx / GRID_COLUMNS; +} + +int CommandSelectorModal::commandToCol(FourCC command) const { + int idx = CommandList::IndexOf(command) - 1; + if (idx < 0) { + return 0; + } + return idx % GRID_COLUMNS; +} + +FourCC CommandSelectorModal::cellAtGridPos(int row, int col) const { + int count = GetDisplayCommandCount(); + int index = row * GRID_COLUMNS + col; + if (index >= count || index < 0) { + return I_CMD_NONE; + } + return GetDisplayCommandAt(index); +} + +void CommandSelectorModal::moveToCommand(FourCC command) { + int idx = CommandList::IndexOf(command); + if (idx < 0) { + command = I_CMD_ARPG; + } + selectedCommand_ = command; + selectedRow_ = commandToRow(command); + selectedCol_ = commandToCol(command); +} + +void CommandSelectorModal::navigateGrid(int deltaRow, int deltaCol) { + int count = GetDisplayCommandCount(); + int rows = (count + GRID_COLUMNS - 1) / GRID_COLUMNS; + + int newRow = selectedRow_; + int newCol = selectedCol_; + int tries = rows * GRID_COLUMNS; + + while (tries-- > 0) { + newRow += deltaRow; + newCol += deltaCol; + + if (newRow < 0) { + newRow = rows - 1; + } else if (newRow >= rows) { + newRow = 0; + } + + if (newCol < 0) { + newCol = GRID_COLUMNS - 1; + } else if (newCol >= GRID_COLUMNS) { + newCol = 0; + } + + FourCC candidate = cellAtGridPos(newRow, newCol); + if (candidate != I_CMD_NONE) { + selectedRow_ = newRow; + selectedCol_ = newCol; + selectedCommand_ = candidate; + if (liveTarget_) { + *liveTarget_ = selectedCommand_; + } + if (previewCb_) { + previewCb_(parentView_, *this); + } + return; + } + } +} + +void CommandSelectorModal::ProcessButtonMask(unsigned short mask, bool pressed) { + if (!pressed) { + return; + } + + if (mask & EPBM_UP) { + navigateGrid(-1, 0); + isDirty_ = true; + } else if (mask & EPBM_DOWN) { + navigateGrid(1, 0); + isDirty_ = true; + } else if (mask & EPBM_LEFT) { + navigateGrid(0, -1); + isDirty_ = true; + } else if (mask & EPBM_RIGHT) { + navigateGrid(0, 1); + isDirty_ = true; + } else if (mask & EPBM_A) { + EndModal(1); // Confirm selection + } else if (mask & EPBM_B) { + if (liveTarget_) { + *liveTarget_ = savedCmd_; + } + EndModal(0); // Cancel + } +} + +void CommandSelectorModal::DrawView() { + int count = GetDisplayCommandCount(); + int rows = (count + GRID_COLUMNS - 1) / GRID_COLUMNS; + int width = GRID_COLUMNS * 5; + + SetWindow(width, rows); + + GUITextProperties props; + + // Draw grid + char cellStr[6]; + for (int r = 0; r < rows; r++) { + for (int c = 0; c < GRID_COLUMNS; c++) { + FourCC cmd = cellAtGridPos(r, c); + if (cmd == I_CMD_NONE) { + continue; + } + bool isSelected = (r == selectedRow_ && c == selectedCol_); + + fourCC2char(cmd, cellStr); + cellStr[4] = 0; + + props.invert_ = isSelected; + SetColor(isSelected ? CD_HILITE2 : CD_NORMAL); + DrawString(c * 5, r, cellStr, props); + } + } + + props.invert_ = false; + SetColor(CD_NORMAL); + + std::string *cmdStr = getHelpLegend(selectedCommand_); + for (int i = 0; i < 3; i++) { + // Clear legend area first so shorter lines don't leave stale text. + View::DrawString(10, i, " ", props); + View::DrawString(10, i, cmdStr[i].c_str(), props); + + } +} + +void CommandSelectorModal::OnPlayerUpdate(PlayerEventType, unsigned int) {} +void CommandSelectorModal::OnFocus() {} diff --git a/sources/Application/Views/ModalDialogs/CommandSelectorModal.h b/sources/Application/Views/ModalDialogs/CommandSelectorModal.h new file mode 100644 index 00000000..f0e8d889 --- /dev/null +++ b/sources/Application/Views/ModalDialogs/CommandSelectorModal.h @@ -0,0 +1,38 @@ +#ifndef _COMMAND_SELECTOR_MODAL_H_ +#define _COMMAND_SELECTOR_MODAL_H_ + +#include "Application/Views/BaseClasses/ModalView.h" +#include "Application/Views/BaseClasses/View.h" +#include "Application/Instruments/CommandList.h" +#include "Application/Views/CommandSelectorCommon.h" + +class CommandSelectorModal : public ModalView { + public: + CommandSelectorModal(View &parentView, FourCC *liveTarget, + ModalViewCallback previewCb = 0); + virtual ~CommandSelectorModal(); + + virtual void ProcessButtonMask(unsigned short mask, bool pressed); + virtual void DrawView(); + virtual void OnPlayerUpdate(PlayerEventType, unsigned int tick = 0); + virtual void OnFocus(); + + private: + void navigateGrid(int deltaRow, int deltaCol); + void moveToCommand(FourCC command); + int commandToRow(FourCC command) const; + int commandToCol(FourCC command) const; + FourCC cellAtGridPos(int row, int col) const; + + int selectedRow_; + int selectedCol_; + FourCC selectedCommand_; + View &parentView_; + FourCC *liveTarget_; + FourCC savedCmd_; + ModalViewCallback previewCb_; + + static const int GRID_COLUMNS = CommandSelectorCommon::kColumns; +}; + +#endif diff --git a/sources/Application/Views/PhraseView.cpp b/sources/Application/Views/PhraseView.cpp index 11a5d81c..fcb0055c 100644 --- a/sources/Application/Views/PhraseView.cpp +++ b/sources/Application/Views/PhraseView.cpp @@ -5,6 +5,7 @@ #include "Application/Utils/HelpLegend.h" #include "Application/Utils/char.h" #include "Application/Views/CommandSelectorCommon.h" +#include "Application/Views/ModalDialogs/CommandSelectorModal.h" #include "System/Console/Trace.h" #include "UIController.h" #include @@ -12,6 +13,14 @@ short PhraseView::offsets_[2][4] = {-1, 1, 12, -12, -1, 1, 16, -16}; +static void CommandSelectorCallback(View &v, ModalView &d) { + ((PhraseView &)v).onCommandSelectorResult(d); +} + +static void CommandSelectorPreviewCallback(View &v, ModalView &d) { + ((PhraseView &)v).onCommandSelectorPreview(d); +} + PhraseView::PhraseView(GUIWindow &w, ViewData *viewData) : View(w, viewData), cmdEdit_("edit", FCC_EDIT, 0) { phrase_ = viewData_->song_->phrase_; @@ -26,8 +35,7 @@ PhraseView::PhraseView(GUIWindow &w, ViewData *viewData) lastInstr_ = 0; lastCmd_ = I_CMD_NONE; lastParam_ = 0; - commandSelectorActive_ = false; - commandSelectorOriginal_ = I_CMD_NONE; + commandSelectorModalActive_ = false; clipboard_.active_ = false; clipboard_.width_ = 0; @@ -44,10 +52,6 @@ PhraseView::~PhraseView() { delete cmdEditField_; }; void PhraseView::updateCursor(int dx, int dy) { - if (commandSelectorActive_ && (dx != 0 || dy != 0)) { - leaveCommandSelector(true); - } - col_ += dx; row_ += dy; if (col_ > 5) @@ -126,40 +130,32 @@ FourCC *PhraseView::getCurrentCommandPointer() { } void PhraseView::enterCommandSelector() { - CommandSelectorCommon::enterSelector( - isCommandColumn(), [this]() { return getCurrentCommandPointer(); }, - commandSelectorActive_, commandSelectorOriginal_, isDirty_); + FourCC *cmdPtr = getCurrentCommandPointer(); + if (!cmdPtr) return; + commandSelectorModalActive_ = true; + DoModal(new CommandSelectorModal(*this, cmdPtr, CommandSelectorPreviewCallback), + CommandSelectorCallback); } -void PhraseView::leaveCommandSelector(bool commit) { - CommandSelectorCommon::leaveSelector( - commit, [this]() { return getCurrentCommandPointer(); }, - commandSelectorActive_, commandSelectorOriginal_, lastCmd_, isDirty_); -} - -void PhraseView::stepCommandSelector(ViewUpdateDirection direction) { - CommandSelectorCommon::stepSelector( - direction, [this]() { return getCurrentCommandPointer(); }, - commandSelectorActive_, lastCmd_, isDirty_); +void PhraseView::onCommandSelectorResult(ModalView &d) { + commandSelectorModalActive_ = false; + CommandSelectorModal &modal = (CommandSelectorModal &)d; + if (modal.GetReturnCode() == 1) { + FourCC *cmd = getCurrentCommandPointer(); + if (cmd) { + lastCmd_ = *cmd; + } + } + isDirty_ = true; } -void PhraseView::drawCommandSelector(GUITextProperties &props) { - if (!commandSelectorActive_) { - return; - } - FourCC *command = getCurrentCommandPointer(); - if (!command) { - return; +void PhraseView::onCommandSelectorPreview(ModalView &) { + isDirty_ = true; + Player *player = Player::GetInstance(); + if (!player->IsRunning()) { + player->OnStartButton(PM_AUDITION, viewData_->songX_, false, + viewData_->chainRow_); } - - GUIPoint anchor = GetAnchor(); - CommandSelectorCommon::drawPopup( - *command, anchor, props, - [this](ColorDefinition color) { SetColor(color); }, - [this](int x, int y, const char *txt, GUITextProperties &textProps) { - DrawString(x, y, txt, textProps); - }); - props.invert_ = false; } void PhraseView::updateCursorValue(ViewUpdateDirection direction, int xOffset, @@ -811,7 +807,6 @@ void PhraseView::switchSoloMode() { void PhraseView::OnFocus() { clipboard_.active_ = false; viewMode_ = VM_NORMAL; - commandSelectorActive_ = false; updateCursor(0, 0); }; @@ -961,29 +956,6 @@ void PhraseView::processNormalButtonMask(unsigned short mask) { Player *player = Player::GetInstance(); - if (commandSelectorActive_) { - if (mask & EPBM_B) { - leaveCommandSelector(false); - return; - } - if (mask == EPBM_A) { - leaveCommandSelector(true); - return; - } - if (mask & EPBM_A) { - if (mask & EPBM_LEFT) - stepCommandSelector(VUD_LEFT); - if (mask & EPBM_RIGHT) - stepCommandSelector(VUD_RIGHT); - if (mask & EPBM_UP) - stepCommandSelector(VUD_UP); - if (mask & EPBM_DOWN) - stepCommandSelector(VUD_DOWN); - return; - } - leaveCommandSelector(true); - } - if (mask & EPBM_B) { if (mask & EPBM_LEFT) warpToNeighbour(-1); @@ -1014,12 +986,19 @@ void PhraseView::processNormalButtonMask(unsigned short mask) { Player *player = Player::GetInstance(); player->OnStartButton(PM_AUDITION, viewData_->songX_, false, viewData_->chainRow_); } - if (mask & EPBM_DOWN) - isCommandColumn() ? enterCommandSelector() - : updateCursorValue(VUD_DOWN); - if (mask & EPBM_UP) - isCommandColumn() ? enterCommandSelector() - : updateCursorValue(VUD_UP); + + if (mask & EPBM_DOWN) { + if (isCommandColumn()) + enterCommandSelector(); + else + updateCursorValue(VUD_DOWN); + } + if (mask & EPBM_UP) { + if (isCommandColumn()) + enterCommandSelector(); + else + updateCursorValue(VUD_UP); + } if (mask & EPBM_LEFT) updateCursorValue(VUD_LEFT); if (mask & EPBM_RIGHT) @@ -1448,8 +1427,6 @@ void PhraseView::DrawView() { cmdEditField_->SetFocus(); cmdEditField_->Draw(w_); }; - - drawCommandSelector(props); }; void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { @@ -1464,7 +1441,7 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { SetColor(CD_NORMAL); pos._y = anchor._y + lastPlayingPos_; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, " ", props); } @@ -1477,12 +1454,11 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { for (int i = 0; i < SONG_CHANNEL_COUNT; i++) { if (player->IsChannelPlaying(i)) { - if (viewData_->currentPlayPhrase_[i] == viewData_->currentPhrase_ && viewData_->playMode_ != PM_AUDITION) { pos._y = anchor._y + viewData_->phrasePlayPos_[i]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint( anchor, pos._x, pos._y)) { if (!player->IsChannelMuted(i)) { @@ -1501,13 +1477,7 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { } // clear any live indicator - pos._y = anchor._y; - if (!commandSelectorActive_ || - !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, - pos._y)) { - DrawString(pos._x, pos._y, " ", props); - } // Loop on all channels to see if one has queued current chain if (player->GetSequencerMode() == SM_LIVE) { @@ -1521,7 +1491,7 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { viewData_->song_->data_ + i + 8 * songPos; if (*chain == viewData_->currentChain_) { char *indicator = player->GetLiveIndicator(i); - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint( anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, indicator, props); @@ -1533,10 +1503,6 @@ void PhraseView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { } } - if (commandSelectorActive_) { - drawCommandSelector(props); - } - pos = anchor; pos._x += 200; diff --git a/sources/Application/Views/PhraseView.h b/sources/Application/Views/PhraseView.h index e1a2c4aa..6afdd2e1 100644 --- a/sources/Application/Views/PhraseView.h +++ b/sources/Application/Views/PhraseView.h @@ -17,6 +17,8 @@ class PhraseView : public View { virtual void DrawView(); virtual void OnPlayerUpdate(PlayerEventType, unsigned int tick = 0); virtual void OnFocus(); + void onCommandSelectorResult(ModalView &d); + void onCommandSelectorPreview(ModalView &d); protected: void updateCursor(int dx, int dy); @@ -25,10 +27,6 @@ class PhraseView : public View { int yOffset = 0); bool isCommandColumn() const; FourCC *getCurrentCommandPointer(); - void enterCommandSelector(); - void leaveCommandSelector(bool commit); - void stepCommandSelector(ViewUpdateDirection direction); - void drawCommandSelector(GUITextProperties &props); void updateSelectionValue(ViewUpdateDirection direction); void warpToNeighbour(int offset); void warpInChain(int offset); @@ -60,13 +58,13 @@ class PhraseView : public View { int lastInstr_; int lastCmd_; int lastParam_; - bool commandSelectorActive_; - FourCC commandSelectorOriginal_; + bool commandSelectorModalActive_; Phrase *phrase_; int lastPlayingPos_; Variable cmdEdit_; UIBigHexVarField *cmdEditField_; void printHelpLegend(FourCC command, GUITextProperties props); + void enterCommandSelector(); struct clipboard { bool active_; diff --git a/sources/Application/Views/TableView.cpp b/sources/Application/Views/TableView.cpp index 03371f2e..970d30d0 100644 --- a/sources/Application/Views/TableView.cpp +++ b/sources/Application/Views/TableView.cpp @@ -4,9 +4,18 @@ #include "Application/Utils/HelpLegend.h" #include "Application/Utils/char.h" #include "Application/Views/CommandSelectorCommon.h" +#include "Application/Views/ModalDialogs/CommandSelectorModal.h" #define FCC_EDIT MAKE_FOURCC('T', 'B', 'E', 'D') +static void CommandSelectorCallback(View &v, ModalView &d) { + ((TableView &)v).onCommandSelectorResult(d); +} + +static void CommandSelectorPreviewCallback(View &v, ModalView &d) { + ((TableView &)v).onCommandSelectorPreview(d); +} + TableView::TableView(GUIWindow &w, ViewData *viewData) : View(w, viewData), cmdEdit_("edit", FCC_EDIT, 0) { row_ = 0; @@ -20,8 +29,7 @@ TableView::TableView(GUIWindow &w, ViewData *viewData) lastTsp_ = 0; lastCmd_ = I_CMD_NONE; lastParam_ = 0; - commandSelectorActive_ = false; - commandSelectorOriginal_ = I_CMD_NONE; + commandSelectorModalActive_ = false; clipboard_.active_ = false; clipboard_.width_ = 0; @@ -34,7 +42,6 @@ void TableView::OnFocus() { clipboard_.active_ = false; viewMode_ = VM_NORMAL; lastPosition_[0] = lastPosition_[1] = lastPosition_[2] = 0; - commandSelectorActive_ = false; updateCursor(0, 0); }; @@ -314,10 +321,6 @@ void TableView::pasteClipboard() { void TableView::updateCursor(int dx, int dy) { - if (commandSelectorActive_ && (dx != 0 || dy != 0)) { - leaveCommandSelector(true); - } - col_ += dx; row_ += dy; if (col_ > 5) @@ -525,42 +528,27 @@ FourCC *TableView::getCurrentCommandPointer() { } void TableView::enterCommandSelector() { - CommandSelectorCommon::enterSelector( - isCommandColumn(), [this]() { return getCurrentCommandPointer(); }, - commandSelectorActive_, commandSelectorOriginal_, isDirty_); -} - -void TableView::leaveCommandSelector(bool commit) { - CommandSelectorCommon::leaveSelector( - commit, [this]() { return getCurrentCommandPointer(); }, - commandSelectorActive_, commandSelectorOriginal_, lastCmd_, isDirty_); + FourCC *cmdPtr = getCurrentCommandPointer(); + if (!cmdPtr) return; + commandSelectorModalActive_ = true; + DoModal(new CommandSelectorModal(*this, cmdPtr, CommandSelectorPreviewCallback), + CommandSelectorCallback); } -void TableView::stepCommandSelector(ViewUpdateDirection direction) { - CommandSelectorCommon::stepSelector( - direction, [this]() { return getCurrentCommandPointer(); }, - commandSelectorActive_, lastCmd_, isDirty_); -} - -void TableView::drawCommandSelector(GUITextProperties &props) { - if (!commandSelectorActive_) { - return; - } - FourCC *command = getCurrentCommandPointer(); - if (!command) { - return; +void TableView::onCommandSelectorResult(ModalView &d) { + commandSelectorModalActive_ = false; + CommandSelectorModal &modal = (CommandSelectorModal &)d; + if (modal.GetReturnCode() == 1) { + FourCC *cmd = getCurrentCommandPointer(); + if (cmd) { + lastCmd_ = *cmd; + } } - - GUIPoint anchor = GetAnchor(); - CommandSelectorCommon::drawPopup( - *command, anchor, props, - [this](ColorDefinition color) { SetColor(color); }, - [this](int x, int y, const char *txt, GUITextProperties &textProps) { - DrawString(x, y, txt, textProps); - }); - props.invert_ = false; + isDirty_ = true; } +void TableView::onCommandSelectorPreview(ModalView &) { isDirty_ = true; } + void TableView::pasteLast() { uint *i = 0; @@ -632,29 +620,6 @@ void TableView::processNormalButtonMask(unsigned short mask) { Player *player = Player::GetInstance(); - if (commandSelectorActive_) { - if (mask & EPBM_B) { - leaveCommandSelector(false); - return; - } - if (mask == EPBM_A) { - leaveCommandSelector(true); - return; - } - if (mask & EPBM_A) { - if (mask & EPBM_LEFT) - stepCommandSelector(VUD_LEFT); - if (mask & EPBM_RIGHT) - stepCommandSelector(VUD_RIGHT); - if (mask & EPBM_UP) - stepCommandSelector(VUD_UP); - if (mask & EPBM_DOWN) - stepCommandSelector(VUD_DOWN); - return; - } - leaveCommandSelector(true); - } - if (mask & EPBM_B) { if (mask & EPBM_LEFT) warpToNeighbour(-1); @@ -674,12 +639,18 @@ void TableView::processNormalButtonMask(unsigned short mask) { // A modifier if (mask & EPBM_A) { - if (mask & EPBM_DOWN) - isCommandColumn() ? enterCommandSelector() - : updateCursorValue(-0x10); - if (mask & EPBM_UP) - isCommandColumn() ? enterCommandSelector() - : updateCursorValue(0x10); + if (mask & EPBM_DOWN) { + if (isCommandColumn()) + enterCommandSelector(); + else + updateCursorValue(-0x10); + } + if (mask & EPBM_UP) { + if (isCommandColumn()) + enterCommandSelector(); + else + updateCursorValue(0x10); + } if (mask & EPBM_LEFT) updateCursorValue(-0x01); if (mask & EPBM_RIGHT) @@ -998,8 +969,6 @@ void TableView::DrawView() { if (player->IsRunning()) { OnPlayerUpdate(PET_UPDATE); }; - - drawCommandSelector(props); } void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { @@ -1010,21 +979,21 @@ void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { pos._x = anchor._x - 1; pos._y = anchor._y + lastPosition_[0]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, " ", props); } pos._x += 10; pos._y = anchor._y + lastPosition_[1]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, " ", props); } pos._x += 10; pos._y = anchor._y + lastPosition_[2]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, " ", props); } @@ -1045,7 +1014,7 @@ void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { pos._x = anchor._x - 1; pos._y = anchor._y + lastPosition_[0]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { SetColor(CD_PLAY); @@ -1054,7 +1023,7 @@ void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { pos._x += 10; pos._y = anchor._y + lastPosition_[1]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, ">", props); @@ -1062,16 +1031,13 @@ void TableView::OnPlayerUpdate(PlayerEventType eventType, unsigned int tick) { pos._x += 10; pos._y = anchor._y + lastPosition_[2]; - if (!commandSelectorActive_ || + if (!commandSelectorModalActive_ || !CommandSelectorCommon::popupContainsPoint(anchor, pos._x, pos._y)) { DrawString(pos._x, pos._y, ">", props); } }; drawNotes(); - if (commandSelectorActive_) { - drawCommandSelector(props); - } } void TableView::printHelpLegend(FourCC command, GUITextProperties props) { diff --git a/sources/Application/Views/TableView.h b/sources/Application/Views/TableView.h index 4866265e..d71310ec 100644 --- a/sources/Application/Views/TableView.h +++ b/sources/Application/Views/TableView.h @@ -14,6 +14,8 @@ class TableView : public View { virtual void DrawView(); virtual void OnPlayerUpdate(PlayerEventType, unsigned int tick = 0); virtual void OnFocus(); + void onCommandSelectorResult(ModalView &d); + void onCommandSelectorPreview(ModalView &d); protected: void processNormalButtonMask(unsigned short mask); @@ -34,9 +36,6 @@ class TableView : public View { bool isCommandColumn() const; FourCC *getCurrentCommandPointer(); void enterCommandSelector(); - void leaveCommandSelector(bool commit); - void stepCommandSelector(ViewUpdateDirection direction); - void drawCommandSelector(GUITextProperties &props); void setTextProps(GUITextProperties &props, int row, int col, bool restore); void warpToNeighbour(int dir); @@ -50,8 +49,7 @@ class TableView : public View { uchar lastTsp_; int lastCmd_; int lastParam_; - bool commandSelectorActive_; - FourCC commandSelectorOriginal_; + bool commandSelectorModalActive_; Variable cmdEdit_; UIBigHexVarField *cmdEditField_; From a1aa20be59ad7838a5ef12f17d0997e749f33031 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 24 Apr 2026 19:25:18 +0000 Subject: [PATCH 3/3] Actually add in vcproj and xcode proj --- projects/lgpt.vcproj | 8 ++++++++ projects/lgpt64.xcodeproj/project.pbxproj | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/projects/lgpt.vcproj b/projects/lgpt.vcproj index d50935b8..f65adeb8 100644 --- a/projects/lgpt.vcproj +++ b/projects/lgpt.vcproj @@ -1051,6 +1051,14 @@ RelativePath="..\sources\Application\Views\ModalDialogs\SelectProjectDialog.h" > + + + +