From 07de0c30c300e144a56aa71c5624e9c6bf1d63f4 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:49:26 +0000 Subject: [PATCH 01/12] QWERTY keyboard on new project Pressing A + up on character selection in new project enters qwerty keyboard mode. --- CHANGELOG | 3 + docs/wiki/What-is-LittlePiggyTracker.md | 2 +- sources/Application/Model/Project.h | 4 +- .../Views/ModalDialogs/NewProjectDialog.cpp | 205 ++++++++++++++++-- .../Views/ModalDialogs/NewProjectDialog.h | 6 + 5 files changed, 201 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2be5d1f0..6e9dda89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +1.6.0-bacon4 + QWERTY keyboard name entry for new projects + 1.5.0-bacon3 Contributions: purelygrey diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index 13641f55..93ee7edc 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -51,7 +51,7 @@ After that you can copy additional wavs to the lgptRoot/lgptProject/samples dire ## New project -When creating a new project, use the regen button to generate a random name. Generate a new name with Regen or edit it manually selecting characters with A and pressing up/down +When creating a new project, use the regen button to generate a random name. Generate a new name with Regen or edit it manually selecting characters with A and pressing up/down to enter the QWERTY keyboard. Exit QWERTY mode with B ## Multiple Projects diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index f75454d6..669b123f 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -19,8 +19,8 @@ #define VAR_SCALE MAKE_FOURCC('S', 'C', 'A', 'L') #define PROJECT_NUMBER "1" -#define PROJECT_RELEASE "5" -#define BUILD_COUNT "0" +#define PROJECT_RELEASE "6" +#define BUILD_COUNT "0-bacon4" #define MAX_TAP 3 diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 3be2afcc..6551a32d 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -10,18 +10,69 @@ static char *buttonText[BUTTONS_LENGTH] = { #define DIALOG_WIDTH 20 +// QWERTY keyboard layout (5 rows) +static const char* keyboardLayout[] = { + "1234567890", + "QWERTYUIOP", + "ASDFGHJKL", + "qwertyuiop", + "asdfghjkl", + "zxcvbnm.-_", + "[____] <-" +}; + +static const int keyboardRows = 7; + NewProjectDialog::NewProjectDialog(View &view):ModalView(view) {} NewProjectDialog::~NewProjectDialog() { } +char NewProjectDialog::getKeyAtPosition(int row, int col) { + if (row < 0 || row >= keyboardRows) return '\0'; + const char* rowStr = keyboardLayout[row]; + + // Handle special row with [____] and <- + if (row == 6) { + if (col >= 0 && col < 7) return ' '; // [____] (space) + if (col >= 8 && col < 12) return '\b'; // <- (backspace) + return '\0'; + } + + int len = strlen(rowStr); + if (col < 0 || col >= len) return '\0'; + return rowStr[col]; +} + +void NewProjectDialog::findCharacterInKeyboard(char ch, int &outRow, int &outCol) { + // Search for character in keyboard layout + for (int row = 0; row < keyboardRows - 1; row++) { // Exclude special row + const char* rowStr = keyboardLayout[row]; + int len = strlen(rowStr); + for (int col = 0; col < len; col++) { + if (rowStr[col] == ch) { + outRow = row; + outCol = col; + return; + } + } + } + // Handle space specially + if (ch == ' ') { + outRow = 6; + outCol = 0; + return; + } + // Character not found, don't change position +} + void NewProjectDialog::DrawView() { - SetWindow(DIALOG_WIDTH,5) ; + SetWindow(DIALOG_WIDTH, keyboardMode_ ? 12 : 5); - GUITextProperties props ; + GUITextProperties props; - SetColor(CD_NORMAL) ; + SetColor(CD_NORMAL); // Draw string @@ -30,11 +81,43 @@ void NewProjectDialog::DrawView() { char buffer[2]; buffer[1]=0 ; for (int i=0;i= 8); + DrawString(startX + 8, 4 + row, "<-", props); + } else { + for (int col = 0; col < len; col++) { + props.invert_ = (row == keyboardRow_ && col == keyboardCol_); + buffer[0] = rowStr[col]; + DrawString(startX + col, 4 + row, buffer, props); + } + } + } + // Draw cursor indicator when in keyboard mode + DrawString(x + currentChar_, 3, "-", props); + props.invert_ = false; + return; // Don't draw buttons in keyboard mode + } + // Draw buttons SetColor(CD_NORMAL) ; @@ -57,13 +140,99 @@ void NewProjectDialog::OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) void NewProjectDialog::OnFocus() { selected_=currentChar_=0; memset(name_,' ',MAX_NAME_LENGTH+1) ; - lastChar_ = 'A'; + lastChar_ = 'A'; + keyboardMode_ = false; + keyboardRow_ = 1; // Start on QWERTY row + keyboardCol_ = 0; }; void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { if (!pressed) return ; + // Handle keyboard mode navigation first + if (keyboardMode_) { + if (mask == EPBM_A) { + // Insert character at current position + char ch = getKeyAtPosition(keyboardRow_, keyboardCol_); + if (ch == '\b') { + // Backspace: delete character and move cursor left + if (currentChar_ > 0) { + currentChar_--; + name_[currentChar_] = ' '; + } + } else if (ch != '\0') { + name_[currentChar_] = ch; + lastChar_ = ch; + if (currentChar_ < MAX_NAME_LENGTH - 1) { + currentChar_++; + // Jump keyboard cursor to the character at new position + char nextChar = name_[currentChar_]; + if (nextChar != ' ') { + findCharacterInKeyboard(nextChar, keyboardRow_, keyboardCol_); + } + } + } + isDirty_ = true; + return; + } + if (mask == EPBM_UP) { + keyboardRow_ = (keyboardRow_ - 1 + keyboardRows) % keyboardRows; + // Clamp column to valid range for new row + if (keyboardRow_ == 6) { + // Special row: [____] is 0-6, <- is 8-11 + if (keyboardCol_ >= 7) keyboardCol_ = 8; // Move to <- + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + if (keyboardCol_ > maxCol) keyboardCol_ = maxCol; + } + isDirty_ = true; + return; + } + if (mask == EPBM_DOWN) { + keyboardRow_ = (keyboardRow_ + 1) % keyboardRows; + // Clamp column to valid range for new row + if (keyboardRow_ == 6) { + // Special row: [____] is 0-6, <- is 8-11 + if (keyboardCol_ >= 7) keyboardCol_ = 8; // Move to <- + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + if (keyboardCol_ > maxCol) keyboardCol_ = maxCol; + } + isDirty_ = true; + return; + } + if (mask == EPBM_LEFT) { + if (keyboardRow_ == 6) { + // Special row: toggle between [____] and <- + keyboardCol_ = (keyboardCol_ < 8) ? 8 : 0; + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + keyboardCol_ = (keyboardCol_ - 1 + maxCol + 1) % (maxCol + 1); + } + isDirty_ = true; + return; + } + if (mask == EPBM_RIGHT) { + if (keyboardRow_ == 6) { + // Special row: toggle between [____] and <- + keyboardCol_ = (keyboardCol_ < 8) ? 8 : 0; + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + keyboardCol_ = (keyboardCol_ + 1) % (maxCol + 1); + } + isDirty_ = true; + return; + } + // Exit keyboard mode with B + if (mask == EPBM_B) { + keyboardMode_ = false; + isDirty_ = true; + return; + } + return; + } + if (mask&EPBM_B) { } else { @@ -94,16 +263,20 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { break; } } - if (mask&EPBM_UP) { - name_[currentChar_]+=1; - lastChar_=name_[currentChar_] ; - isDirty_=true ; - } - if (mask&EPBM_DOWN) { - name_[currentChar_]-=1; - lastChar_=name_[currentChar_] ; - isDirty_=true ; - } + if ((mask & EPBM_UP) || (mask & EPBM_DOWN)) { + // Toggle keyboard mode with A+UP or A+DOWN + if (selected_ == 0) { + keyboardMode_ = !keyboardMode_; + // When entering keyboard mode, jump to current character + if (keyboardMode_) { + char currentCh = name_[currentChar_]; + if (currentCh != ' ') { + findCharacterInKeyboard(currentCh, keyboardRow_, keyboardCol_); + } + } + isDirty_ = true; + } + } } else { // R Modifier diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.h b/sources/Application/Views/ModalDialogs/NewProjectDialog.h index ba1aa9c7..a6c573ba 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.h +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.h @@ -23,6 +23,12 @@ class NewProjectDialog:public ModalView { int lastChar_ ; char name_[MAX_NAME_LENGTH+1] ; int currentChar_ ; + bool keyboardMode_; + int keyboardRow_ ; + int keyboardCol_ ; + + char getKeyAtPosition(int row, int col) ; + void findCharacterInKeyboard(char ch, int &outRow, int &outCol) ; } ; #endif From c083c8556b96217851e2580b7896e92c151a41a4 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:49:26 +0000 Subject: [PATCH 02/12] QWERTY keyboard on new project Pressing A + up on character selection in new project enters qwerty keyboard mode. --- .../Views/ModalDialogs/NewProjectDialog.cpp | 220 +++++++++--------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 6551a32d..323ddcf4 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -80,7 +80,7 @@ void NewProjectDialog::DrawView() { char buffer[2]; buffer[1]=0 ; - for (int i=0;i 0) - currentChar_--; - break; - case 1: - case 2: - case 3: - if (selected_ > 0) - selected_--; - break; - } - isDirty_ = true; - } - if (mask == EPBM_RIGHT) { - switch (selected_) { - case 0: - if (currentChar_ < MAX_NAME_LENGTH - 1) - currentChar_++; - else - selected_++; - break; - case 1: - case 2: - case 3: - if (selected_ < BUTTONS_LENGTH) - selected_++; - break; - } - isDirty_ = true; - } - } - } + if (mask & EPBM_B) { + + } else { + + // A modifier + if (mask & EPBM_A) { + if (mask == EPBM_A) { + std::string randomName = getRandomName(); + switch (selected_) { + case 0: + if (name_[currentChar_] == ' ') { + name_[currentChar_] = lastChar_; + } + isDirty_ = true; + break; + case 1: + std::fill(name_ + randomName.length(), + name_ + sizeof(name_) / sizeof(name_[0]), ' '); + strncpy(name_, randomName.c_str(), randomName.length()); + lastChar_ = currentChar_ = randomName.length() - 1; + isDirty_ = true; + break; + case 2: + EndModal(1); + break; + case 3: + EndModal(0); + break; + } + } + if ((mask & EPBM_UP) || (mask & EPBM_DOWN)) { + // Toggle keyboard mode with A+UP or A+DOWN + if (selected_ == 0) { + keyboardMode_ = !keyboardMode_; + // When entering keyboard mode, jump to current character + if (keyboardMode_) { + char currentCh = name_[currentChar_]; + if (currentCh != ' ') { + findCharacterInKeyboard(currentCh, keyboardRow_, + keyboardCol_); + } + } + isDirty_ = true; + } + } + } else { + + // R Modifier + + if (mask & EPBM_R) { + } else { + // No modifier + if (mask == EPBM_UP) { + selected_ = (selected_ == 0) ? 1 : 0; + isDirty_ = true; + } + if (mask == EPBM_DOWN) { + selected_ = (selected_ == 0) ? 1 : 0; + isDirty_ = true; + } + + if (mask == EPBM_LEFT) { + switch (selected_) { + case 0: + if (currentChar_ > 0) + currentChar_--; + break; + case 1: + case 2: + case 3: + if (selected_ > 0) + selected_--; + break; + } + isDirty_ = true; + } + if (mask == EPBM_RIGHT) { + switch (selected_) { + case 0: + if (currentChar_ < MAX_NAME_LENGTH - 1) + currentChar_++; + else + selected_++; + break; + case 1: + case 2: + case 3: + if (selected_ < BUTTONS_LENGTH) + selected_++; + break; + } + isDirty_ = true; + } + } + } } }; - std::string NewProjectDialog::GetName() { for (int i = MAX_NAME_LENGTH; i >= 0; i--) { if (name_[i]==' ') { From f13d17dbe471ac7bed77fffb6d72cd7356b5978b Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Tue, 25 Nov 2025 18:10:59 +0000 Subject: [PATCH 03/12] clang-format --- sources/Application/Views/ModalDialogs/NewProjectDialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 323ddcf4..995f1173 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -44,8 +44,9 @@ char NewProjectDialog::getKeyAtPosition(int row, int col) { return rowStr[col]; } -void NewProjectDialog::findCharacterInKeyboard(char ch, int &outRow, int &outCol) { - // Search for character in keyboard layout +void NewProjectDialog::findCharacterInKeyboard(char ch, int &outRow, + int &outCol) { + // Search for character in keyboard layout for (int row = 0; row < keyboardRows - 1; row++) { // Exclude special row const char* rowStr = keyboardLayout[row]; int len = strlen(rowStr); From 56d37fe00042f8319e9201026949a5c2573deca7 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Tue, 25 Nov 2025 18:55:23 +0000 Subject: [PATCH 04/12] clang-format --- .../Views/ModalDialogs/NewProjectDialog.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 995f1173..7d553429 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -200,22 +200,22 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; if (keyboardCol_ > maxCol) keyboardCol_ = maxCol; } - isDirty_ = true; - return; + isDirty_ = true; + return; } if (mask == EPBM_LEFT) { - if (keyboardRow_ == 6) { - // Special row: toggle between [____] and <- + if (keyboardRow_ == 6) { + // Special row: toggle between [____] and <- keyboardCol_ = (keyboardCol_ < 8) ? 8 : 0; - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; keyboardCol_ = (keyboardCol_ - 1 + maxCol + 1) % (maxCol + 1); - } - isDirty_ = true; + } + isDirty_ = true; return; } - if (mask == EPBM_RIGHT) { - if (keyboardRow_ == 6) { + if (mask == EPBM_RIGHT) { + if (keyboardRow_ == 6) { // Special row: toggle between [____] and <- keyboardCol_ = (keyboardCol_ < 8) ? 8 : 0; } else { @@ -224,15 +224,15 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { } isDirty_ = true; return; - } - // Exit keyboard mode with B - if (mask == EPBM_B) { + } + // Exit keyboard mode with B + if (mask == EPBM_B) { keyboardMode_ = false; isDirty_ = true; return; } - return; - } + return; + } if (mask & EPBM_B) { From 7831c49aff1c1991bfdcdda6da029b0e1d2cb464 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Tue, 25 Nov 2025 19:06:11 +0000 Subject: [PATCH 05/12] clang-format --- sources/Application/Views/ModalDialogs/NewProjectDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 7d553429..287f8711 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -187,8 +187,8 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; if (keyboardCol_ > maxCol) keyboardCol_ = maxCol; } - isDirty_ = true; - return; + isDirty_ = true; + return; } if (mask == EPBM_DOWN) { keyboardRow_ = (keyboardRow_ + 1) % keyboardRows; From f211ab0119112e3f08dc3b4b5aa2577a7b31c36c Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:00:00 +0000 Subject: [PATCH 06/12] Working typing refactored Keyboard still in NewProjectDialog --- .../Views/ModalDialogs/NewProjectDialog.cpp | 324 ++++++++++-------- 1 file changed, 182 insertions(+), 142 deletions(-) diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 287f8711..26d34968 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -2,74 +2,69 @@ #include "NewProjectDialog.h" #include "Application/Utils/RandomNames.h" -static char *buttonText[BUTTONS_LENGTH] = { - (char *)"Regen", - (char *)"Ok", - (char *)"Cancel" -} ; +static char *buttonText[BUTTONS_LENGTH] = {(char *)"Random", (char *)"Ok", + (char *)"Cancel"}; #define DIALOG_WIDTH 20 +#define SPACE_ROW 7 -// QWERTY keyboard layout (5 rows) -static const char* keyboardLayout[] = { - "1234567890", - "QWERTYUIOP", - "ASDFGHJKL", - "qwertyuiop", - "asdfghjkl", - "zxcvbnm.-_", - "[____] <-" -}; +#define KEYBOARD_ROWS (SPACE_ROW + 1) + +#define SPCE_START 0 +#define SPCE_END 3 +#define BACK_START 4 +#define BACK_END 6 +#define DONE_START 8 +#define DONE_END 10 -static const int keyboardRows = 7; +static const char *keyboardLayout[] = {"1234567890", "QWERTYUIOP", "ASDFGHJKL@", + "ZXCVBNM,?>", "qwertyuiop", "asdfghjkl|", + "zxcvbnm-_<", "[_] <- OK"}; NewProjectDialog::NewProjectDialog(View &view):ModalView(view) {} -NewProjectDialog::~NewProjectDialog() { -} +NewProjectDialog::~NewProjectDialog() {} char NewProjectDialog::getKeyAtPosition(int row, int col) { - if (row < 0 || row >= keyboardRows) return '\0'; - const char* rowStr = keyboardLayout[row]; - - // Handle special row with [____] and <- - if (row == 6) { - if (col >= 0 && col < 7) return ' '; // [____] (space) - if (col >= 8 && col < 12) return '\b'; // <- (backspace) + if (row < 0 || row >= KEYBOARD_ROWS) + return '\0'; + const char *rowStr = keyboardLayout[row]; + + // Handle special row with SPC and <- + if (row == SPACE_ROW) { + if (col >= 0 && col < SPCE_END) + return ' '; // [_] (space) + if (col >= BACK_START && col < BACK_END) return '\b'; // <- (backspace) + if (col >= DONE_START && col < DONE_END) return '\r'; // END (carriage return) return '\0'; - } - - int len = strlen(rowStr); - if (col < 0 || col >= len) return '\0'; + } + + int len = strlen(rowStr); + if (col < 0 || col >= len) return '\0'; return rowStr[col]; } void NewProjectDialog::findCharacterInKeyboard(char ch, int &outRow, int &outCol) { - // Search for character in keyboard layout - for (int row = 0; row < keyboardRows - 1; row++) { // Exclude special row + if (ch == ' ') + return; // Skip blankspace character + // Search for character in keyboard layout + for (int row = 0; row < SPACE_ROW; row++) { // Exclude special row const char* rowStr = keyboardLayout[row]; int len = strlen(rowStr); for (int col = 0; col < len; col++) { if (rowStr[col] == ch) { outRow = row; outCol = col; - return; - } - } - } - // Handle space specially - if (ch == ' ') { - outRow = 6; - outCol = 0; - return; - } - // Character not found, don't change position + return; + } + } + } } void NewProjectDialog::DrawView() { - SetWindow(DIALOG_WIDTH, keyboardMode_ ? 12 : 5); + SetWindow(DIALOG_WIDTH, keyboardMode_ ? 15 : 5); GUITextProperties props; @@ -80,54 +75,58 @@ void NewProjectDialog::DrawView() { int x = (DIALOG_WIDTH - MAX_NAME_LENGTH) / 3; char buffer[2]; - buffer[1]=0 ; + buffer[1] = 0; for (int i = 0; i < MAX_NAME_LENGTH; i++) { - props.invert_ = - ((i == currentChar_) && (selected_ == 0) && !keyboardMode_); + props.invert_ = ((i == currentChar_) && (selected_ == 0)); buffer[0]=name_[i] ; DrawString(x + i, 2, buffer, props); } // Draw keyboard if in keyboard mode if (keyboardMode_) { - SetColor(CD_NORMAL); - for (int row = 0; row < keyboardRows; row++) { - const char* rowStr = keyboardLayout[row]; - int len = strlen(rowStr); - int startX = (DIALOG_WIDTH - len) / 2; - - // Special handling for last row with [____] and <- - if (row == 6) { - // Draw [____] - props.invert_ = (row == keyboardRow_ && keyboardCol_ < 7); - DrawString(startX, 4 + row, "[____]", props); - - // Draw <- - props.invert_ = (row == keyboardRow_ && keyboardCol_ >= 8); - DrawString(startX + 8, 4 + row, "<-", props); - } else { + SetColor(CD_NORMAL); + for (int row = 0; row < KEYBOARD_ROWS; row++) { + const char* rowStr = keyboardLayout[row]; + int len = strlen(rowStr); + int startX = (DIALOG_WIDTH - len) / 2; + + // Special handling for last row with SPC and <- + if (row == SPACE_ROW) { + // Draw SPACE + props.invert_ = (row == keyboardRow_ && keyboardCol_ < SPCE_END); + DrawString(startX, 4 + row, "[_]", props); + + // Draw <- + props.invert_ = (row == keyboardRow_ && keyboardCol_ >= BACK_START && keyboardCol_ < BACK_END); + DrawString(startX + 4, 4 + row, "<-", props); + + // Draw END + props.invert_ = + (row == keyboardRow_ && keyboardCol_ >= DONE_START); + DrawString(startX + 8, 4 + row, "OK", props); + } else { for (int col = 0; col < len; col++) { props.invert_ = (row == keyboardRow_ && col == keyboardCol_); - buffer[0] = rowStr[col]; - DrawString(startX + col, 4 + row, buffer, props); - } - } - } - // Draw cursor indicator when in keyboard mode - DrawString(x + currentChar_, 3, "-", props); + buffer[0] = rowStr[col]; + DrawString(startX + col, 4 + row, buffer, props); + } + } + } props.invert_ = false; + int xOffset = 0, yOffset = 13; + DrawString(x + xOffset, yOffset, "A=input, B=erase", props); + DrawString(x + xOffset, yOffset + 2, "L, R=move cursor", props); return; // Don't draw buttons in keyboard mode } // Draw buttons - SetColor(CD_NORMAL) ; - props.invert_=false ; - + SetColor(CD_NORMAL); + props.invert_=false ; - int offset = DIALOG_WIDTH / (BUTTONS_LENGTH + 1); + int offset = DIALOG_WIDTH / (BUTTONS_LENGTH + 1); - for (int i = 0; i < BUTTONS_LENGTH; i++) { + for (int i = 0; i < BUTTONS_LENGTH; i++) { const char *text = buttonText[i]; x = (offset * (i + 1) - strlen(text) / BUTTONS_LENGTH) - 2; props.invert_=(selected_==i+1) ; @@ -143,8 +142,8 @@ void NewProjectDialog::OnFocus() { memset(name_, ' ', MAX_NAME_LENGTH + 1); lastChar_ = 'A'; keyboardMode_ = false; - keyboardRow_ = 1; // Start on QWERTY row - keyboardCol_ = 0; + keyboardRow_ = 2; + keyboardCol_ = 0; }; void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { @@ -153,85 +152,141 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { // Handle keyboard mode navigation first if (keyboardMode_) { - if (mask == EPBM_A) { - // Insert character at current position - char ch = getKeyAtPosition(keyboardRow_, keyboardCol_); + if (mask == EPBM_A) { + // Insert character at current position + char ch = getKeyAtPosition(keyboardRow_, keyboardCol_); if (ch == '\b') { // Backspace: delete character and move cursor left if (currentChar_ > 0) { currentChar_--; name_[currentChar_] = ' '; - } - } else if (ch != '\0') { - name_[currentChar_] = ch; + } + } else if (ch == '\r') { + // END key: exit keyboard mode (same as START) + keyboardMode_ = false; + isDirty_ = true; + // EndModal(0); + return; + } else if (ch != '\0') { + name_[currentChar_] = ch; lastChar_ = ch; if (currentChar_ < MAX_NAME_LENGTH - 1) { - currentChar_++; - // Jump keyboard cursor to the character at new position - char nextChar = name_[currentChar_]; - if (nextChar != ' ') { - findCharacterInKeyboard(nextChar, keyboardRow_, keyboardCol_); - } + currentChar_++; + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, + keyboardCol_); } } isDirty_ = true; - return; + return; + } else if (mask == EPBM_B) { + // Backspace: delete character and move cursor left + if (currentChar_ > 0) { + currentChar_--; + name_[currentChar_] = ' '; + isDirty_ = true; + } + } else if (mask == EPBM_L) { + // Move cursor left + if (currentChar_ > 0) { + currentChar_--; + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); + isDirty_ = true; + return; + } + } else if (mask == EPBM_R) { + // Move cursor right + if (currentChar_ < MAX_NAME_LENGTH - 1) { + currentChar_++; + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); + isDirty_ = true; + return; + } } if (mask == EPBM_UP) { - keyboardRow_ = (keyboardRow_ - 1 + keyboardRows) % keyboardRows; - // Clamp column to valid range for new row - if (keyboardRow_ == 6) { - // Special row: [____] is 0-6, <- is 8-11 - if (keyboardCol_ >= 7) keyboardCol_ = 8; // Move to <- - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - if (keyboardCol_ > maxCol) keyboardCol_ = maxCol; - } + keyboardRow_ = (keyboardRow_ - 1 + KEYBOARD_ROWS) % KEYBOARD_ROWS; + // Clamp column to valid range for new row + if (keyboardRow_ == SPACE_ROW) { + if (keyboardCol_ < SPCE_END) keyboardCol_ = SPCE_START; // Move to [_] + if (keyboardCol_ >= SPCE_END && keyboardCol_ <= BACK_END) keyboardCol_ = BACK_START; // Move to <- + if (keyboardCol_ > BACK_END) keyboardCol_ = DONE_START; // Move to DONE + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + if (keyboardCol_ > maxCol) keyboardCol_ = 0; + } isDirty_ = true; return; } if (mask == EPBM_DOWN) { - keyboardRow_ = (keyboardRow_ + 1) % keyboardRows; - // Clamp column to valid range for new row - if (keyboardRow_ == 6) { - // Special row: [____] is 0-6, <- is 8-11 - if (keyboardCol_ >= 7) keyboardCol_ = 8; // Move to <- - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - if (keyboardCol_ > maxCol) keyboardCol_ = maxCol; - } + keyboardRow_ = (keyboardRow_ + 1) % KEYBOARD_ROWS; + // Clamp column to valid range for new row + if (keyboardRow_ == SPACE_ROW) { + // Special row: SPC is 0-6, <- is 8-11 + if (keyboardCol_ < SPCE_END) + keyboardCol_ = SPCE_START; // Move to [_] + if (keyboardCol_ >= SPCE_END && keyboardCol_ <= BACK_END) keyboardCol_ = BACK_START; // Move to <- + if (keyboardCol_ > BACK_END) keyboardCol_ = DONE_START; // Move to DONE + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + if (keyboardCol_ > maxCol) + keyboardCol_ = 0; + } isDirty_ = true; return; } if (mask == EPBM_LEFT) { - if (keyboardRow_ == 6) { - // Special row: toggle between [____] and <- - keyboardCol_ = (keyboardCol_ < 8) ? 8 : 0; + if (keyboardRow_ == SPACE_ROW) { + // Cycle backward: END -> BACK -> SPACE -> END ... + if (keyboardCol_ < SPCE_END) { + keyboardCol_ = DONE_START; // Move to DONE + } else if (keyboardCol_ >= SPCE_END && + keyboardCol_ < DONE_START) { + keyboardCol_ = SPCE_START; // Move to SPACE + } else if (keyboardCol_ >= DONE_START) { + keyboardCol_ = BACK_START; // Move to BACK + } } else { int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - keyboardCol_ = (keyboardCol_ - 1 + maxCol + 1) % (maxCol + 1); + keyboardCol_ = (keyboardCol_ - 1 + maxCol + 1) % (maxCol + 1); } isDirty_ = true; - return; - } - if (mask == EPBM_RIGHT) { - if (keyboardRow_ == 6) { - // Special row: toggle between [____] and <- - keyboardCol_ = (keyboardCol_ < 8) ? 8 : 0; - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - keyboardCol_ = (keyboardCol_ + 1) % (maxCol + 1); - } - isDirty_ = true; - return; + return; } - // Exit keyboard mode with B - if (mask == EPBM_B) { - keyboardMode_ = false; - isDirty_ = true; + if (mask == EPBM_RIGHT) { + if (keyboardRow_ == SPACE_ROW) { + // Cycle forward: SPACE -> BACK -> END -> SPACE ... + if (keyboardCol_ >= BACK_START && keyboardCol_ < BACK_END) { + keyboardCol_ = DONE_START; // Move to DONE + } else if (keyboardCol_ >= DONE_START) { + keyboardCol_ = SPCE_START; // Move to SPACE + } else if (keyboardCol_ >= SPCE_START && + keyboardCol_ < BACK_END) { + keyboardCol_ = BACK_START; // Move to BACK + } + } else { + int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; + keyboardCol_ = (keyboardCol_ + 1) % (maxCol + 1); + } + isDirty_ = true; + return; + } // Exit keyboard mode with Start + if (mask == EPBM_START) { + keyboardMode_ = false; + isDirty_ = true; + // EndModal(1); // We want to clear out the keyboard mode in the background too return; } return; + } else if ((mask == EPBM_A)) { + // Toggle keyboard mode with A + if (selected_ == 0) { + keyboardMode_ = !keyboardMode_; + // When entering keyboard mode, jump to current character + if (keyboardMode_) { + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, + keyboardCol_); + } + isDirty_ = true; + } } if (mask & EPBM_B) { @@ -264,21 +319,6 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { break; } } - if ((mask & EPBM_UP) || (mask & EPBM_DOWN)) { - // Toggle keyboard mode with A+UP or A+DOWN - if (selected_ == 0) { - keyboardMode_ = !keyboardMode_; - // When entering keyboard mode, jump to current character - if (keyboardMode_) { - char currentCh = name_[currentChar_]; - if (currentCh != ' ') { - findCharacterInKeyboard(currentCh, keyboardRow_, - keyboardCol_); - } - } - isDirty_ = true; - } - } } else { // R Modifier From d56edac04332773f596dfc7b5929efabb83f5d2f Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 18 Dec 2025 21:00:00 +0000 Subject: [PATCH 07/12] Extract KeyboardLayout to its own header --- projects/lgpt.vcxproj | 1 + projects/lgptest.dev | 11 +- sources/Application/Utils/KeyboardLayout.h | 100 ++++++++++ .../Views/ModalDialogs/NewProjectDialog.cpp | 185 +++++------------- .../Views/ModalDialogs/NewProjectDialog.h | 11 +- 5 files changed, 162 insertions(+), 146 deletions(-) create mode 100644 sources/Application/Utils/KeyboardLayout.h diff --git a/projects/lgpt.vcxproj b/projects/lgpt.vcxproj index e6f588df..24ee5329 100644 --- a/projects/lgpt.vcxproj +++ b/projects/lgpt.vcxproj @@ -440,6 +440,7 @@ + diff --git a/projects/lgptest.dev b/projects/lgptest.dev index e877c121..e3e0ef5b 100644 --- a/projects/lgptest.dev +++ b/projects/lgptest.dev @@ -2937,7 +2937,6 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= - [Unit288] FileName=..\sources\Application\utils\RandomNames.h CompileCpp=1 @@ -2948,3 +2947,13 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit289] +FileName=..\sources\Application\utils\KeyboardLayout.h +CompileCpp=1 +Folder=Application/Utils +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/sources/Application/Utils/KeyboardLayout.h b/sources/Application/Utils/KeyboardLayout.h new file mode 100644 index 00000000..c260c1cc --- /dev/null +++ b/sources/Application/Utils/KeyboardLayout.h @@ -0,0 +1,100 @@ +#ifndef _KEYBOARD_LAYOUT_H_ +#define _KEYBOARD_LAYOUT_H_ + +#include + +// Keyboard layout configuration +#define SPACE_ROW 7 +#define KEYBOARD_ROWS (SPACE_ROW + 1) + +#define SPCE_START 0 +#define SPCE_END 3 +#define BACK_START 4 +#define BACK_END 6 +#define DONE_START 8 +#define DONE_END 10 + +static const char* keyboardLayout[] = { + "1234567890", + "QWERTYUIOP", + "ASDFGHJKL@", + "ZXCVBNM,?>", + "qwertyuiop", + "asdfghjkl|", + "zxcvbnm-_<", + "[_] <- OK" +}; + +// Helper functions for special row section detection +inline bool isInSpaceSection(int col) { return col < SPCE_END; } +inline bool isInBackSection(int col) { return col >= BACK_START && col < BACK_END; } +inline bool isInDoneSection(int col) { return col >= DONE_START; } + +// Get the character at a specific keyboard position +inline char getKeyAtPosition(int row, int col) { + if (row < 0 || row >= KEYBOARD_ROWS) return '\0'; + const char* rowStr = keyboardLayout[row]; + + // Handle special row with SPC, BACK, and DONE + if (row == SPACE_ROW) { + if (col >= 0 && col < SPCE_END) return ' '; // [_] (space) + if (col >= BACK_START && col < BACK_END) return '\b'; // <- (backspace) + if (col >= DONE_START && col < DONE_END) return '\r'; // OK (carriage return) + return '\0'; + } + + int len = strlen(rowStr); + if (col < 0 || col >= len) return '\0'; + return rowStr[col]; +} + +// Find a character's position in the keyboard layout +inline void findCharacterInKeyboard(char ch, int &outRow, int &outCol) { + if (ch == ' ') return; // Skip space character + + // Search for character in keyboard layout (excluding special row) + for (int row = 0; row < SPACE_ROW; row++) { + const char* rowStr = keyboardLayout[row]; + int len = strlen(rowStr); + for (int col = 0; col < len; col++) { + if (rowStr[col] == ch) { + outRow = row; + outCol = col; + return; + } + } + } + // Character not found, don't change position +} + +// Clamp keyboard column to valid range for current row +inline void clampKeyboardColumn(int row, int& col) { + if (row == SPACE_ROW) { + if (col < SPCE_END) col = SPCE_START; + else if (col <= BACK_END) col = BACK_START; + else col = DONE_START; + } else { + int maxCol = strlen(keyboardLayout[row]) - 1; + if (col > maxCol) col = 0; + } +} + +// Cycle keyboard column left (-1) or right (+1) within current row +inline void cycleKeyboardColumn(int row, int direction, int& col) { + if (row == SPACE_ROW) { + if (direction < 0) { // LEFT + if (isInSpaceSection(col)) col = DONE_START; + else if (isInBackSection(col)) col = SPCE_START; + else col = BACK_START; + } else { // RIGHT + if (isInBackSection(col)) col = DONE_START; + else if (isInDoneSection(col)) col = SPCE_START; + else col = BACK_START; + } + } else { + int maxCol = strlen(keyboardLayout[row]) - 1; + col = (col + direction + maxCol + 1) % (maxCol + 1); + } +} + +#endif diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 26d34968..579197f8 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -1,64 +1,23 @@ #include "NewProjectDialog.h" +#include "Application/Utils/KeyboardLayout.h" #include "Application/Utils/RandomNames.h" static char *buttonText[BUTTONS_LENGTH] = {(char *)"Random", (char *)"Ok", (char *)"Cancel"}; #define DIALOG_WIDTH 20 -#define SPACE_ROW 7 - -#define KEYBOARD_ROWS (SPACE_ROW + 1) - -#define SPCE_START 0 -#define SPCE_END 3 -#define BACK_START 4 -#define BACK_END 6 -#define DONE_START 8 -#define DONE_END 10 - -static const char *keyboardLayout[] = {"1234567890", "QWERTYUIOP", "ASDFGHJKL@", - "ZXCVBNM,?>", "qwertyuiop", "asdfghjkl|", - "zxcvbnm-_<", "[_] <- OK"}; NewProjectDialog::NewProjectDialog(View &view):ModalView(view) {} NewProjectDialog::~NewProjectDialog() {} -char NewProjectDialog::getKeyAtPosition(int row, int col) { - if (row < 0 || row >= KEYBOARD_ROWS) - return '\0'; - const char *rowStr = keyboardLayout[row]; - - // Handle special row with SPC and <- - if (row == SPACE_ROW) { - if (col >= 0 && col < SPCE_END) - return ' '; // [_] (space) - if (col >= BACK_START && col < BACK_END) return '\b'; // <- (backspace) - if (col >= DONE_START && col < DONE_END) return '\r'; // END (carriage return) - return '\0'; - } - - int len = strlen(rowStr); - if (col < 0 || col >= len) return '\0'; - return rowStr[col]; -} - -void NewProjectDialog::findCharacterInKeyboard(char ch, int &outRow, - int &outCol) { - if (ch == ' ') - return; // Skip blankspace character - // Search for character in keyboard layout - for (int row = 0; row < SPACE_ROW; row++) { // Exclude special row - const char* rowStr = keyboardLayout[row]; - int len = strlen(rowStr); - for (int col = 0; col < len; col++) { - if (rowStr[col] == ch) { - outRow = row; - outCol = col; - return; - } - } +// Move text cursor left (-1) or right (+1) and update keyboard position +void NewProjectDialog::moveCursor(int direction) { + int newPos = currentChar_ + direction; + if (newPos >= 0 && newPos < MAX_NAME_LENGTH) { + currentChar_ = newPos; + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); } } @@ -91,22 +50,25 @@ void NewProjectDialog::DrawView() { int startX = (DIALOG_WIDTH - len) / 2; // Special handling for last row with SPC and <- - if (row == SPACE_ROW) { - // Draw SPACE - props.invert_ = (row == keyboardRow_ && keyboardCol_ < SPCE_END); - DrawString(startX, 4 + row, "[_]", props); + if (row == SPACE_ROW) { + // Draw SPACE + props.invert_ = + (row == keyboardRow_ && isInSpaceSection(keyboardCol_)); + DrawString(startX, 4 + row, "[_]", props); // Draw <- - props.invert_ = (row == keyboardRow_ && keyboardCol_ >= BACK_START && keyboardCol_ < BACK_END); + props.invert_ = + (row == keyboardRow_ && isInBackSection(keyboardCol_)); DrawString(startX + 4, 4 + row, "<-", props); // Draw END props.invert_ = - (row == keyboardRow_ && keyboardCol_ >= DONE_START); + (row == keyboardRow_ && isInDoneSection(keyboardCol_)); DrawString(startX + 8, 4 + row, "OK", props); } else { - for (int col = 0; col < len; col++) { - props.invert_ = (row == keyboardRow_ && col == keyboardCol_); + for (int col = 0; col < len; col++) { + props.invert_ = + (row == keyboardRow_ && col == keyboardCol_); buffer[0] = rowStr[col]; DrawString(startX + col, 4 + row, buffer, props); } @@ -146,20 +108,21 @@ void NewProjectDialog::OnFocus() { keyboardCol_ = 0; }; -void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { +void NewProjectDialog::ProcessButtonMask(unsigned short mask, bool pressed) { - if (!pressed) return ; + if (!pressed) + return; // Handle keyboard mode navigation first if (keyboardMode_) { if (mask == EPBM_A) { // Insert character at current position char ch = getKeyAtPosition(keyboardRow_, keyboardCol_); - if (ch == '\b') { - // Backspace: delete character and move cursor left - if (currentChar_ > 0) { - currentChar_--; - name_[currentChar_] = ' '; + if (ch == '\b') { + // Backspace: delete character and move cursor left + if (currentChar_ > 0) { + currentChar_--; + name_[currentChar_] = ' '; } } else if (ch == '\r') { // END key: exit keyboard mode (same as START) @@ -169,8 +132,8 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { return; } else if (ch != '\0') { name_[currentChar_] = ch; - lastChar_ = ch; - if (currentChar_ < MAX_NAME_LENGTH - 1) { + lastChar_ = ch; + if (currentChar_ < MAX_NAME_LENGTH - 1) { currentChar_++; findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); @@ -185,96 +148,40 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { name_[currentChar_] = ' '; isDirty_ = true; } + return; } else if (mask == EPBM_L) { // Move cursor left - if (currentChar_ > 0) { - currentChar_--; - findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); - isDirty_ = true; - return; - } + moveCursor(-1); + isDirty_ = true; + return; } else if (mask == EPBM_R) { // Move cursor right - if (currentChar_ < MAX_NAME_LENGTH - 1) { - currentChar_++; - findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); - isDirty_ = true; - return; - } - } - if (mask == EPBM_UP) { + moveCursor(1); + isDirty_ = true; + return; + } else if (mask == EPBM_UP) { keyboardRow_ = (keyboardRow_ - 1 + KEYBOARD_ROWS) % KEYBOARD_ROWS; - // Clamp column to valid range for new row - if (keyboardRow_ == SPACE_ROW) { - if (keyboardCol_ < SPCE_END) keyboardCol_ = SPCE_START; // Move to [_] - if (keyboardCol_ >= SPCE_END && keyboardCol_ <= BACK_END) keyboardCol_ = BACK_START; // Move to <- - if (keyboardCol_ > BACK_END) keyboardCol_ = DONE_START; // Move to DONE - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - if (keyboardCol_ > maxCol) keyboardCol_ = 0; - } + clampKeyboardColumn(keyboardRow_, keyboardCol_); isDirty_ = true; return; - } - if (mask == EPBM_DOWN) { + } else if (mask == EPBM_DOWN) { keyboardRow_ = (keyboardRow_ + 1) % KEYBOARD_ROWS; - // Clamp column to valid range for new row - if (keyboardRow_ == SPACE_ROW) { - // Special row: SPC is 0-6, <- is 8-11 - if (keyboardCol_ < SPCE_END) - keyboardCol_ = SPCE_START; // Move to [_] - if (keyboardCol_ >= SPCE_END && keyboardCol_ <= BACK_END) keyboardCol_ = BACK_START; // Move to <- - if (keyboardCol_ > BACK_END) keyboardCol_ = DONE_START; // Move to DONE - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - if (keyboardCol_ > maxCol) - keyboardCol_ = 0; - } + clampKeyboardColumn(keyboardRow_, keyboardCol_); isDirty_ = true; return; - } - if (mask == EPBM_LEFT) { - if (keyboardRow_ == SPACE_ROW) { - // Cycle backward: END -> BACK -> SPACE -> END ... - if (keyboardCol_ < SPCE_END) { - keyboardCol_ = DONE_START; // Move to DONE - } else if (keyboardCol_ >= SPCE_END && - keyboardCol_ < DONE_START) { - keyboardCol_ = SPCE_START; // Move to SPACE - } else if (keyboardCol_ >= DONE_START) { - keyboardCol_ = BACK_START; // Move to BACK - } - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - keyboardCol_ = (keyboardCol_ - 1 + maxCol + 1) % (maxCol + 1); - } + } else if (mask == EPBM_LEFT) { + cycleKeyboardColumn(keyboardRow_, -1, keyboardCol_); isDirty_ = true; return; - } - if (mask == EPBM_RIGHT) { - if (keyboardRow_ == SPACE_ROW) { - // Cycle forward: SPACE -> BACK -> END -> SPACE ... - if (keyboardCol_ >= BACK_START && keyboardCol_ < BACK_END) { - keyboardCol_ = DONE_START; // Move to DONE - } else if (keyboardCol_ >= DONE_START) { - keyboardCol_ = SPCE_START; // Move to SPACE - } else if (keyboardCol_ >= SPCE_START && - keyboardCol_ < BACK_END) { - keyboardCol_ = BACK_START; // Move to BACK - } - } else { - int maxCol = strlen(keyboardLayout[keyboardRow_]) - 1; - keyboardCol_ = (keyboardCol_ + 1) % (maxCol + 1); - } + } else if (mask == EPBM_RIGHT) { + cycleKeyboardColumn(keyboardRow_, 1, keyboardCol_); isDirty_ = true; return; - } // Exit keyboard mode with Start - if (mask == EPBM_START) { + } else if (mask == EPBM_START) { keyboardMode_ = false; isDirty_ = true; - // EndModal(1); // We want to clear out the keyboard mode in the background too - return; - } + return; + } return; } else if ((mask == EPBM_A)) { // Toggle keyboard mode with A diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.h b/sources/Application/Views/ModalDialogs/NewProjectDialog.h index a6c573ba..ae32e8df 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.h +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.h @@ -1,6 +1,7 @@ #ifndef _NEW_PROJECT_DIALOG_H_ #define _NEW_PROJECT_DIALOG_H_ +#include "Application/Utils/KeyboardLayout.h" #include "Application/Views/BaseClasses/ModalView.h" #include @@ -24,11 +25,9 @@ class NewProjectDialog:public ModalView { char name_[MAX_NAME_LENGTH+1] ; int currentChar_ ; bool keyboardMode_; - int keyboardRow_ ; - int keyboardCol_ ; - - char getKeyAtPosition(int row, int col) ; - void findCharacterInKeyboard(char ch, int &outRow, int &outCol) ; -} ; + int keyboardRow_; + int keyboardCol_ ; + void moveCursor(int direction); +}; #endif From d790cd6ae952893457120a607812f3e08e6921f6 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 18 Dec 2025 21:30:00 +0000 Subject: [PATCH 08/12] Update CHANGELOG and docs --- CHANGELOG | 7 +++++++ docs/wiki/What-is-LittlePiggyTracker.md | 19 ++++++++++++++++++- docs/wiki/tips_and_tricks.md | 17 +++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 6e9dda89..b28f1cdb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,12 @@ 1.6.0-bacon4 QWERTY keyboard name entry for new projects + * Press A on the project name field to enter QWERTY keyboard mode + * Navigate the on-screen keyboard with D-PAD/arrows + * Press A to input the selected character + * Press B to backspace + * Press L/R to move the text cursor left/right + * Press START or select OK to exit keyboard mode + * All keyboard navigation logic extracted to reusable KeyboardLayout.h utility 1.5.0-bacon3 Contributions: diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index 93ee7edc..1473d585 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -51,7 +51,24 @@ After that you can copy additional wavs to the lgptRoot/lgptProject/samples dire ## New project -When creating a new project, use the regen button to generate a random name. Generate a new name with Regen or edit it manually selecting characters with A and pressing up/down to enter the QWERTY keyboard. Exit QWERTY mode with B +When creating a new project, you have several options for naming: + +**Random Name Generation:** +- Select the "Random" button and press A to generate a random name + +**QWERTY Keyboard Entry:** +- Move to the name field and press A to enter QWERTY keyboard mode +- An on-screen keyboard will appear with these controls: + - **D-PAD/Arrows:** Navigate the keyboard + - **A:** Input the selected character + - **B:** Backspace (delete character) + - **L/R:** Move the text cursor left/right within your project name + - **START or OK key:** Exit keyboard mode and return to the dialog +- The keyboard includes: + - Numbers (0-9) + - Uppercase and lowercase letters (A-Z, a-z) + - Special characters (@ | - _ < > ? ,) + - Space bar, backspace, and OK (done) buttons on the bottom row ## Multiple Projects diff --git a/docs/wiki/tips_and_tricks.md b/docs/wiki/tips_and_tricks.md index 470e2a87..15d84b16 100644 --- a/docs/wiki/tips_and_tricks.md +++ b/docs/wiki/tips_and_tricks.md @@ -1,3 +1,20 @@ +# Project Naming with QWERTY Keyboard + +Since version 1.6.0, you can use an on-screen QWERTY keyboard when creating new projects: + +**Quick Tips:** +- Press A on the project name to enter keyboard mode +- The keyboard cursor will jump to the character under your text cursor unless it's a space +- Use L/R shoulder buttons to move through your project name +- Erase with B and exit with Start + +**Keyboard Layout:** +The on-screen keyboard is organized like this: +- Numbers +- Uppercase (A-Q + extra characters) +- Lowercase (a-q + extra characters) +- Special [Space] [Erase] [Done] + # Delays and Echoes ## Simulating LSDj's D command From f732abdd5564a72569fccfea706eb385be2869af Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:24:57 +0000 Subject: [PATCH 09/12] clang-format --- sources/Application/Model/Project.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 669b123f..0004b196 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -56,15 +56,14 @@ class Project: public Persistent,public VariableContainer,I_Observer { void LoadFirstGen(const char *root); protected: - void buildMidiDeviceList() ; -private: - InstrumentBank *instrumentBank_ ; - char **midiDeviceList_ ; - int midiDeviceListSize_ ; - int tempoNudge_ ; - unsigned long lastTap_[MAX_TAP] ; - unsigned int tempoTapCount_ ; -} ; + void buildMidiDeviceList(); +private: + InstrumentBank *instrumentBank_; + char **midiDeviceList_; + int midiDeviceListSize_; + int tempoNudge_; + unsigned long lastTap_[MAX_TAP]; + unsigned int tempoTapCount_; +}; #endif - From b1ec1923ca2268582b197da6930ea46063ed7824 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sat, 27 Dec 2025 15:27:42 +0100 Subject: [PATCH 10/12] Uplift from master --- CHANGELOG | 40 +++-- README.md | 8 +- docs/wiki/What-is-LittlePiggyTracker.md | 9 + .../Instruments/SoundFontManager.cpp | 15 +- .../Application/Views/BaseClasses/View.cpp | 20 ++- sources/Application/Views/BaseClasses/View.h | 5 +- .../Views/ModalDialogs/NewProjectDialog.cpp | 68 ++++++-- .../Views/ModalDialogs/NewProjectDialog.h | 31 ++-- .../ModalDialogs/SelectProjectDialog.cpp | 128 +++++++------- sources/Application/Views/PhraseView.cpp | 72 +++++++- sources/Application/Views/PhraseView.h | 1 + sources/Application/Views/TableView.cpp | 59 ++++++- sources/Application/Views/TableView.h | 1 + sources/Externals/Soundfont/DATATYPE.H | 156 ++++++++++-------- sources/Externals/Soundfont/HYDRA.H | 8 +- sources/Externals/Soundfont/RIFF.CPP | 59 ++++--- sources/Externals/Soundfont/RIFF.H | 2 +- sources/Externals/Soundfont/SFDATA.H | 8 +- sources/Externals/Soundfont/SFNAV.CPP | 17 +- sources/Externals/Soundfont/SFREADER.CPP | 58 ++++--- 20 files changed, 487 insertions(+), 278 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b28f1cdb..79791722 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,18 @@ * Press START or select OK to exit keyboard mode * All keyboard navigation logic extracted to reusable KeyboardLayout.h utility +1.6.0-bacon2 + Interpolate values in tables and phrases + R + B on single-column selection will fill values from lowest to highest + + Contributions: + drbscl + Add 64 bit soundfont support (#211) + + Fixes: + Add 64 bit soundfont support (#211) + Skip randomly generated project name if a directory with that name already exists (#175) + 1.5.0-bacon3 Contributions: purelygrey @@ -25,9 +37,9 @@ * instrumentation by clsource simotek - Add color options for Border Play and Mute (#143) + Add color options for Border Play and Mute (#143) * Adds different color for the > play and _ mute indicators - Fix rg35xx mapping (#139) + Fix rg35xx mapping (#139) * rshoulder and lshoulder were the wrong way kompadre @@ -50,7 +62,7 @@ Nudge functionality (#130) * In Project view, select tempo and hold B+LEFT/RIGHT to nudge slower/faster * In Song view, pressing LT+LEFT/RIGHT will do the same - + Printable fx in InstrumentView (#155) * Uses ffmpeg to print reverb to currently selected sample * New sample with fx is created and assigned to the current instrument @@ -73,7 +85,7 @@ Set songview b jumping length to 16 rows in correspondence with LSDJ and M8 Scales no longer affect instrument numbers ([djdiskmachine/LittleGPTracker#172](https://github.com/djdiskmachine/LittleGPTracker/issues/172)) Bug in Variable:SetString [djdiskmachine/LittleGPTracker#169](https://github.com/djdiskmachine/LittleGPTracker/issues/169) - + Issue in deep clone (#135) Was possible to accidentally deep clone position into another position @@ -118,27 +130,27 @@ Fixes: RG35XX no longer segfaults on boot USB MIDI disabled due to missing OS dependencies - + 1.4.0 Adds: Automated build for bittboy, Win32, PSP, Miyoo, Deb32, RG35XX Shoutout to xquader for the initial RG35XX port (https://boosty.to/xquader) License changed from CC-BY-SA-NC to GPL-3 - * MVEL cmd + * MVEL cmd Set step velocity for MIDI instruments https://github.com/democloid/picoTracker/pull/163 - + Author: @maks@fluttercommunity.social Co-authored-by: djdiskmachine * Config option to set major beat color in phrase screen Author: koisignal - + * Deep clone Clones selected chain and the phrases within - + Author: koisignal Co-authored-by: djdiskmachine @@ -200,29 +212,29 @@ 1.3o-beta-1 Pingpong loop now stable - Courtesy of djdiskmachine + Courtesy of djdiskmachine Add ability to change font USAGE: ./mkfont.py FONT_BMP [OUTPUT_FILE] FONT_BMP must be a black/white (#000000, #FFFFFF) 128x64px bmp if OUTPUT_FILE is omitted, will print to stdout - Courtesy of subnixr + Courtesy of subnixr Adds Miyoo mini build Courtesy of Nine-H Changes filter attenuation to attenuation - Adjust volume post scream filter + Adjust volume post scream filter https://github.com/Mdashdotdashn/LittleGPTracker/issues/22 Missing wiki content dumped to repo - Courtesy of Peter Swimm + Courtesy of Peter Swimm 1.3o-alpha-5 Adds native SteamOS build Adds Bittboy/RS97/RG350 builds Merge of Gameblaba, CalebCDE and RafaVicos work - Shoutouts! + Shoutouts! 1.3o-alpha-4 Adds Save As menu item - save a copy of your project with a new name Courtesy of yoyz (https://github.com/yoyz), biggup! diff --git a/README.md b/README.md index ce6d7ee7..a53b7ca7 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ Recommended reading to get you started: |-------------|---------------|--------------|------------|--------------------------------------| | PSP | NO | NO | YES | [See notes](projects/resources/PSP/INSTALL_HOW_TO.txt) | | DEB | YES | YES | YES | | -| X64 | YES | YES | NO | | +| X64 | YES | YES | MAYBE | | | X86 | YES | YES | YES | | -| STEAM | YES | YES | NO | | +| STEAM | YES | YES | MAYBE | | | MIYOO | NO | NO | YES | Port by [Nine-H](https://ninethehacker.xyz) | | W32 | YES | YES | YES | Built in VS2008 with love | | RASPI | YES | YES | YES | Versatile platform | @@ -55,10 +55,8 @@ Recommended reading to get you started: | GARLIC | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| | GARLICPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| | RG35XXPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| -| MACOS | YES | YES | NO | Port by [clsource](https://genserver.social/clsource) | +| MACOS | YES | YES | MAYBE | Port by [clsource](https://genserver.social/clsource) | - -* **Soundfont library is currently not ported for 64bit OS** * **MIDI functionality __greatly__ depends on kernel support, please feature request your favourite OS maintainer =)** * **Install ffmpeg by following install instructions for your platform [here](https://www.ffmpeg.org/download.html)** * **PrintFX requires full ffmpeg. If marked as TBA, it requires a redesign using [libav](https://trac.ffmpeg.org/wiki/Using%20libav*)** diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index 1473d585..83b4f86b 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -134,6 +134,7 @@ Note: CTRL Key mappings of RT and LT are inverted. Since the keyboard's Arrow Ke - B+LEFT/RIGHT: Next/Previous Channel in Chain/Phrase Screen. Navigation +/- 1 in Instrument/Table Screen. Switch between Song and Live Modes in Song Screen. - RT+ARROWS: Navigate between the Screens. - LT+UP/DOWN: Jump up/down to next populated row after a blank row (great for live mode entire row queuing!) +- RT+B: in chains or tables, a single-column selection will fill values from lowest to highest ## Selections @@ -153,6 +154,14 @@ And then: - LT+A: paste the clipboard content at current location +- RT+B: in chains or tables, a single-column selection will fill values from lowest to highest + +00 01 00 01 +01 -- => 01 02 +02 -- 02 03 +03 04 03 04 + + ## Playback Modes and Controls There are two modes for playback, Song and Live. The controls in each mode differ slightly. diff --git a/sources/Application/Instruments/SoundFontManager.cpp b/sources/Application/Instruments/SoundFontManager.cpp index 0acec549..d56a4efc 100644 --- a/sources/Application/Instruments/SoundFontManager.cpp +++ b/sources/Application/Instruments/SoundFontManager.cpp @@ -2,10 +2,6 @@ #include "System/System/System.h" #include "System/FileSystem/FileSystem.h" -#ifdef _64BIT -#include -#endif - SoundFontManager::SoundFontManager() { } ; @@ -66,14 +62,11 @@ sfBankID SoundFontManager::LoadBank(const char *path) { current.dwEnd=(current.dwEnd-current.dwStart) ; current.dwStartloop=(current.dwStartloop-current.dwStart) ; current.dwEndloop=(current.dwEndloop-current.dwStart) ; -#ifdef _64BIT - current.dwStart=(intptr_t)buffer ; -#else - current.dwStart=(DWORD)buffer ; -#endif + // ADDR is pointer-sized, works on both 32-bit and 64-bit + current.dwStart = (ADDR)buffer; - sampleData_.push_back(buffer) ; - } + sampleData_.push_back(buffer); + } fin->Close() ; SAFE_DELETE(fin) ; diff --git a/sources/Application/Views/BaseClasses/View.cpp b/sources/Application/Views/BaseClasses/View.cpp index 625fa1b9..689ae8ef 100644 --- a/sources/Application/Views/BaseClasses/View.cpp +++ b/sources/Application/Views/BaseClasses/View.cpp @@ -243,18 +243,22 @@ void View::EnableNotification() { if ((SDL_GetTicks() - notificationTime_) <= NOTIFICATION_TIMEOUT) { SetColor(CD_NORMAL); GUITextProperties props; - DrawString(10, 2, displayNotification_, props); - } else { + int xOffset = 4; + DrawString(xOffset, notiDistY_, displayNotification_.c_str(), props); + } else { displayNotification_ = ""; } } /* - Set displayed notification and save the current time + Set displayed notification + Saves the current time + Optionally set display y offset if not in a project (default == 2) + Allows negative offsets, use with care! */ -void View::SetNotification(const char *notification) { - notificationTime_ = SDL_GetTicks(); - displayNotification_ = (char*) notification; - isDirty_ = true; +void View::SetNotification(const char *notification, int offset) { + notificationTime_ = SDL_GetTicks(); + displayNotification_ = notification; + notiDistY_ = offset; + isDirty_ = true; } - diff --git a/sources/Application/Views/BaseClasses/View.h b/sources/Application/Views/BaseClasses/View.h index b7fff153..3d0f787f 100644 --- a/sources/Application/Views/BaseClasses/View.h +++ b/sources/Application/Views/BaseClasses/View.h @@ -119,7 +119,7 @@ class View : public Observable { void DoModal(ModalView *view, ModalViewCallback cb = 0); void EnableNotification(); - void SetNotification(const char *notification); + void SetNotification(const char *notification, int offset = 2); protected: virtual void ProcessButtonMask(unsigned short mask, bool pressed) = 0; @@ -161,7 +161,8 @@ class View : public Observable { bool locked_; uint32_t notificationTime_; uint16_t NOTIFICATION_TIMEOUT; - char *displayNotification_; + std::string displayNotification_; + int notiDistY_; static bool initPrivate_; ModalView *modalView_; ModalViewCallback modalViewCallback_; diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 579197f8..48366734 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -8,7 +8,8 @@ static char *buttonText[BUTTONS_LENGTH] = {(char *)"Random", (char *)"Ok", #define DIALOG_WIDTH 20 -NewProjectDialog::NewProjectDialog(View &view):ModalView(view) {} +NewProjectDialog::NewProjectDialog(View &view, Path currentPath) + : ModalView(view), currentPath_(currentPath) {} NewProjectDialog::~NewProjectDialog() {} @@ -94,10 +95,11 @@ void NewProjectDialog::DrawView() { props.invert_=(selected_==i+1) ; DrawString(x, 4, text, props); } -}; + View::EnableNotification(); +} -void NewProjectDialog::OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) { -}; +void NewProjectDialog::OnPlayerUpdate(PlayerEventType, + unsigned int currentTick) {}; void NewProjectDialog::OnFocus() { selected_=currentChar_=0; @@ -183,21 +185,53 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask, bool pressed) { return; } return; - } else if ((mask == EPBM_A)) { - // Toggle keyboard mode with A - if (selected_ == 0) { - keyboardMode_ = !keyboardMode_; - // When entering keyboard mode, jump to current character - if (keyboardMode_) { - findCharacterInKeyboard(name_[currentChar_], keyboardRow_, - keyboardCol_); + } else if (mask & EPBM_A) { + if (mask == EPBM_A) { + std::string randomName = ""; + switch (selected_) { + case 0: + // Toggle keyboard mode + keyboardMode_ = !keyboardMode_; + // When entering keyboard mode, jump to current character + if (keyboardMode_) { + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, + keyboardCol_); + } + isDirty_ = true; + break; + case 1: + do { + randomName = getRandomName(); + std::fill(name_ + randomName.length(), + name_ + sizeof(name_) / sizeof(name_[0]), ' '); + strncpy(name_, randomName.c_str(), randomName.length()); + lastChar_ = currentChar_ = randomName.length() - 1; + } while (currentPath_.Descend(GetName()).Exists()); + isDirty_ = true; + break; + case 2: + if (currentPath_.Descend(GetName()).Exists()) { + std::string res("Name " + std::string(name_) + " busy"); + View::SetNotification(res.c_str(), -6); + } else { + EndModal(1); + } + break; + case 3: + EndModal(0); + break; } - isDirty_ = true; } - } - - if (mask & EPBM_B) { - + if (mask & EPBM_UP) { + name_[currentChar_]+=1; + lastChar_=name_[currentChar_] ; + isDirty_=true ; + } + if (mask&EPBM_DOWN) { + name_[currentChar_]-=1; + lastChar_=name_[currentChar_] ; + isDirty_=true ; + } } else { // A modifier diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.h b/sources/Application/Views/ModalDialogs/NewProjectDialog.h index ae32e8df..917e2953 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.h +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.h @@ -10,24 +10,25 @@ class NewProjectDialog:public ModalView { public: - NewProjectDialog(View &view) ; - virtual ~NewProjectDialog() ; + NewProjectDialog(View &view, Path currentPath = ""); + virtual ~NewProjectDialog(); - virtual void DrawView() ; - virtual void OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) ; - virtual void OnFocus() ; - virtual void ProcessButtonMask(unsigned short mask,bool pressed) ; + virtual void DrawView(); + virtual void OnPlayerUpdate(PlayerEventType, unsigned int currentTick); + virtual void OnFocus(); + virtual void ProcessButtonMask(unsigned short mask, bool pressed); - std::string GetName() ; -private: - int selected_ ; - int lastChar_ ; - char name_[MAX_NAME_LENGTH+1] ; - int currentChar_ ; - bool keyboardMode_; - int keyboardRow_; - int keyboardCol_ ; + std::string GetName(); +private: + Path currentPath_; + int selected_; + int lastChar_; + char name_[MAX_NAME_LENGTH + 1]; + int currentChar_; + bool keyboardMode_; + int keyboardRow_; + int keyboardCol_ ; void moveCursor(int direction); }; #endif diff --git a/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp b/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp index 218050f4..7c0dc506 100644 --- a/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp @@ -9,11 +9,7 @@ #define LIST_SIZE 20 #define LIST_WIDTH 32 -static char *buttonText[3]= { - "Load", - "New", - "Exit" -} ; +static char *buttonText[3] = {"Load", "New", "Exit"}; Path SelectProjectDialog::lastFolder_("root:") ; int SelectProjectDialog::lastProject_ = 0 ; @@ -25,12 +21,11 @@ static void NewProjectCallback(View &v,ModalView &dialog) { std::string selected=npd.GetName() ; SelectProjectDialog &spd=(SelectProjectDialog&)v ; Result result = spd.OnNewProject(selected) ; - if (result.Failed()) - { - Trace::Error(result.GetDescription().c_str()); + if (result.Failed()) { + Trace::Error(result.GetDescription().c_str()); + } } - } -} ; +}; SelectProjectDialog::SelectProjectDialog(View &view):ModalView(view),content_(true) { } @@ -45,16 +40,17 @@ void SelectProjectDialog::DrawView() { GUITextProperties props ; SetColor(CD_NORMAL) ; + View::EnableNotification(); -// Draw projects + // Draw projects - int x=1 ; - int y=1 ; + int x = 1; + int y = 1; - if (currentProject_=topIndex_+LIST_SIZE) { + if (currentProject_ < topIndex_) { + topIndex_ = currentProject_; + }; + if (currentProject_>=topIndex_+LIST_SIZE) { topIndex_=currentProject_-LIST_SIZE+1 ; } ; @@ -113,12 +109,11 @@ void SelectProjectDialog::DrawView() { x=offset*(i+1)-strlen(text)/2 ; props.invert_=(i==selected_)?true:false ; DrawString(x,y,text,props) ; - } - + } }; -void SelectProjectDialog::OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) { -}; +void SelectProjectDialog::OnPlayerUpdate(PlayerEventType, + unsigned int currentTick) {}; void SelectProjectDialog::OnFocus() { @@ -129,29 +124,30 @@ void SelectProjectDialog::OnFocus() { void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { if (!pressed) return ; - - if (mask&EPBM_B) { - if (mask&EPBM_UP) warpToNextProject(-LIST_SIZE) ; - if (mask&EPBM_DOWN) warpToNextProject(LIST_SIZE) ; - } else { - - // A modifier - if (mask&EPBM_A) { - switch(selected_) { + + if (mask&EPBM_B) { + if (mask & EPBM_UP) + warpToNextProject(-LIST_SIZE); + if (mask&EPBM_DOWN) warpToNextProject(LIST_SIZE) ; + } else { + + // A modifier + if (mask & EPBM_A) { + switch (selected_) { case 0: // load { - //locate folder user had selected when they hit a - int count=0 ; - Path *current=0 ; - - IteratorPtr it(content_.GetIterator()) ; - for(it->Begin();!it->IsDone();it->Next()) { - if (count==currentProject_) { - current=&it->CurrentItem() ; - break ; - } - count++ ; - } + // locate folder user had selected when they hit a + int count = 0; + Path *current = 0; + + IteratorPtr it(content_.GetIterator()); + for (it->Begin(); !it->IsDone(); it->Next()) { + if (count == currentProject_) { + current = &it->CurrentItem(); + break; + } + count++; + } //check if folder is a project, indicated by 'lgpt' being the first 4 characters of the folder name std::string name = current->GetName() ; @@ -178,20 +174,21 @@ void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { } case 1: // new { - NewProjectDialog *npd=new NewProjectDialog(*this) ; - DoModal(npd,NewProjectCallback) ; + NewProjectDialog *npd = + new NewProjectDialog(*this, currentPath_); + DoModal(npd,NewProjectCallback) ; break ; - } - case 2: // Exit ; - EndModal(0) ; + } + case 2: // Exit ; + EndModal(0) ; break ; } - } else { + } else { - // R Modifier + // R Modifier - if (mask&EPBM_R) { - } else { + if (mask & EPBM_R) { + } else { // No modifier if (mask==EPBM_UP) warpToNextProject(-1) ; if (mask==EPBM_DOWN) warpToNextProject(1) ; @@ -204,16 +201,16 @@ void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { selected_=(selected_+1)%3 ; isDirty_=true ; } - } - } - } + } + } + } }; void SelectProjectDialog::warpToNextProject(int amount) { - int offset=currentProject_-topIndex_ ; - int size=content_.Size() ; - currentProject_+=amount ; + int offset = currentProject_ - topIndex_; + int size = content_.Size(); + currentProject_+=amount ; if (currentProject_<0) currentProject_+=size ; if (currentProject_>=size) currentProject_-=size ; @@ -223,8 +220,7 @@ void SelectProjectDialog::warpToNextProject(int amount) { topIndex_=0 ; } ; } - isDirty_=true ; - + isDirty_ = true; } Path SelectProjectDialog::GetSelection() { @@ -233,8 +229,14 @@ Path SelectProjectDialog::GetSelection() { Result SelectProjectDialog::OnNewProject(std::string &name) { - Path path = currentPath_.Descend(name); - Trace::Log("TMP","creating project at %s",path.GetPath().c_str()); + Path path = currentPath_.Descend(name); + if (path.Exists()) { + Trace::Log("SelectProjectDialog:OnNewProj","path already exists %s", path.GetPath().c_str()); + std::string res("Name " + name + " busy"); + View::SetNotification(res.c_str(), 0); + return Result(res); + } + Trace::Log("TMP","creating project at %s",path.GetPath().c_str()); selection_ = path ; Result result = FileSystem::GetInstance()->MakeDir(path.GetPath().c_str()) ; RETURN_IF_FAILED(result, ("Failed to create project dir for '%s", path.GetPath().c_str())); @@ -289,7 +291,5 @@ void SelectProjectDialog::setCurrentFolder(Path &path) { //reset & redraw screen topIndex_=0 ; currentProject_=0 ; - isDirty_=true ; + isDirty_ = true; } - - diff --git a/sources/Application/Views/PhraseView.cpp b/sources/Application/Views/PhraseView.cpp index c95bfb46..f370306a 100644 --- a/sources/Application/Views/PhraseView.cpp +++ b/sources/Application/Views/PhraseView.cpp @@ -505,6 +505,72 @@ void PhraseView::extendSelection() { isDirty_ = true; } } + +/****************************************************** + interpolateSelection: + expands the lowest value of selection to the highest + ******************************************************/ +void PhraseView::interpolateSelection() { + if (!clipboard_.active_) { + return; + } + + GUIRect rect = getSelectionRect(); + // Only interpolate if we're in note (0) or param (3, 5) columns + int col = rect.Left(); + if (col != rect.Right() || (col != 0 && col != 3 && col != 5)) { + return; + } + + int startRow = rect.Top(); + int endRow = rect.Bottom(); + // Need at least 2 rows to interpolate + if (endRow - startRow < 1) { + return; + } + + // Select the appropriate data array based on column + if (col == 0) { + // Note column + uchar *noteData = phrase_->note_ + (16 * viewData_->currentPhrase_); + + uchar startNote = noteData[startRow]; + uchar endNote = noteData[endRow]; + + if (startNote == 0xFF || endNote == 0xFF) { + View::SetNotification("No note info"); + return; + } + + int numSteps = endRow - startRow; + int noteDiff = (int)endNote - (int)startNote; + + for (int step = 0; step <= numSteps; step++) { + int row = startRow + step; + int value = startNote + (2 * noteDiff * step + numSteps) / (2 * numSteps); + noteData[row] = (uchar)value; + } + } else { + // Parameter columns (3 or 5) + ushort *paramData = (col == 3) ? + phrase_->param1_ + (16 * viewData_->currentPhrase_) : + phrase_->param2_ + (16 * viewData_->currentPhrase_); + + ushort startParam = paramData[startRow]; + ushort endParam = paramData[endRow]; + + int numSteps = endRow - startRow; + int paramDiff = (int)endParam - (int)startParam; + + for (int step = 0; step <= numSteps; step++) { + int row = startRow + step; + int value = startParam + (2 * paramDiff * step + numSteps) / (2 * numSteps); + paramData[row] = (ushort)value; + } + } + isDirty_ = true; +} + /****************************************************** copySelection: copies data in the current selection to the @@ -992,6 +1058,8 @@ void PhraseView::processSelectionButtonMask(unsigned short mask) { if (mask & EPBM_B) { if (mask & EPBM_L) { extendSelection(); + } else if (mask & EPBM_R) { + interpolateSelection(); } else { copySelection(); } @@ -1210,7 +1278,7 @@ void PhraseView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 2, j, true); pos._y++; - if (j == row_ && (col_ == 2 || col_ == 3)) { + if (j == row_ && col_ == 2) { printHelpLegend(command, props); } } @@ -1257,7 +1325,7 @@ void PhraseView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 4, j, true); pos._y++; - if (j == row_ && (col_ == 4 || col_ == 5)) { + if (j == row_ && col_ == 4) { printHelpLegend(command, props); } } diff --git a/sources/Application/Views/PhraseView.h b/sources/Application/Views/PhraseView.h index 7693164d..1e266254 100644 --- a/sources/Application/Views/PhraseView.h +++ b/sources/Application/Views/PhraseView.h @@ -33,6 +33,7 @@ class PhraseView : public View { GUIRect getSelectionRect(); void fillClipboardData(); + void interpolateSelection(); void copySelection(); void cutSelection(); void pasteClipboard(); diff --git a/sources/Application/Views/TableView.cpp b/sources/Application/Views/TableView.cpp index f16355d8..1fe50cad 100644 --- a/sources/Application/Views/TableView.cpp +++ b/sources/Application/Views/TableView.cpp @@ -119,6 +119,57 @@ void TableView::extendSelection() { } } +/****************************************************** + interpolateSelection: + expands the lowest value of selection to the highest + ******************************************************/ +void TableView::interpolateSelection() { + if (!clipboard_.active_) { + return; + } + + GUIRect rect = getSelectionRect(); + + // Only interpolate if we're in param columns (1, 3, 5) + int col = rect.Left(); + if (col != rect.Right() || (col != 1 && col != 3 && col != 5)) { + return; + } + + int startRow = rect.Top(); + int endRow = rect.Bottom(); + + // Need at least 2 rows to interpolate + if (endRow - startRow < 1) { + return; + } + + Table &table = TableHolder::GetInstance()->GetTable(viewData_->currentTable_); + + ushort *paramData; + if (col == 1) { + paramData = table.param1_; + } else if (col == 3) { + paramData = table.param2_; + } else { + paramData = table.param3_; + } + + ushort startParam = paramData[startRow]; + ushort endParam = paramData[endRow]; + + int numSteps = endRow - startRow; + int paramDiff = (int)endParam - (int)startParam; + + for (int step = 0; step <= numSteps; step++) { + int row = startRow + step; + int value = startParam + (2 * paramDiff * step + numSteps) / (2 * numSteps); + paramData[row] = (ushort)value; + } + + isDirty_ = true; +} + void TableView::copySelection() { // Keep up with row,col of selection coz @@ -619,6 +670,8 @@ void TableView::processSelectionButtonMask(unsigned short mask) { if (mask & EPBM_B) { if (mask & EPBM_L) { extendSelection(); + } else if (mask & EPBM_R) { + interpolateSelection(); } else { copySelection(); } @@ -750,7 +803,7 @@ void TableView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 0, j, true); pos._y++; - if (j == row_ && (col_ == 0 || col_ == 1)) { + if (j == row_ && col_ == 0) { printHelpLegend(command, props); } } @@ -788,7 +841,7 @@ void TableView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 2, j, true); pos._y++; - if (j == row_ && (col_ == 2 || col_ == 3)) { + if (j == row_ && col_ == 2) { printHelpLegend(command, props); } } @@ -826,7 +879,7 @@ void TableView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 4, j, true); pos._y++; - if (j == row_ && (col_ == 4 || col_ == 5)) { + if (j == row_ && col_ == 5) { printHelpLegend(command, props); } } diff --git a/sources/Application/Views/TableView.h b/sources/Application/Views/TableView.h index 38a68a53..db11ca99 100644 --- a/sources/Application/Views/TableView.h +++ b/sources/Application/Views/TableView.h @@ -21,6 +21,7 @@ class TableView : public View { void cutPosition(); void pasteLast(); + void interpolateSelection(); void copySelection(); void cutSelection(); void pasteClipboard(); diff --git a/sources/Externals/Soundfont/DATATYPE.H b/sources/Externals/Soundfont/DATATYPE.H index ef5bcf23..06d6d6e8 100644 --- a/sources/Externals/Soundfont/DATATYPE.H +++ b/sources/Externals/Soundfont/DATATYPE.H @@ -36,13 +36,25 @@ #include +#if defined(_MSC_VER) && _MSC_VER < 1600 + /* Workaround for MSVC 2008 and earlier */ + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; +#ifdef _WIN64 + typedef unsigned __int64 uintptr_t; +#else + typedef unsigned __int32 uintptr_t; +#endif +#else +#include +#endif -/************ -* Defines -************/ + /************ + * Defines + ************/ -#ifndef __BYTE_INCOHERENT /* Big Endian (IE 680x0) */ -#define __BYTE_COHERENT /* Little Endian (IE 80x86) */ +#ifndef __BYTE_INCOHERENT /* Big Endian (IE 680x0) */ +#define __BYTE_COHERENT /* Little Endian (IE 80x86) */ #endif #ifdef _UNIX_STUB_ @@ -51,90 +63,92 @@ #endif #ifdef EMU_WINDOWS - #include +#include #else - #define _export +#define _export #endif -/* Expected data values */ -#define CHAR_MINVAL -127 -#define CHAR_MAXVAL 127 -#define BYTE_MAXVAL 255 -#define SHRT_MINVAL -32767 -#define SHRT_MAXVAL 32767 -#define LONG_MINVAL -2147483647L -#define LONG_MAXVAL 2147483647L -#define DWORD_MAXVAL 4294967295L + /* Expected data values */ +#define CHAR_MINVAL -127 +#define CHAR_MAXVAL 127 +#define BYTE_MAXVAL 255 +#define SHRT_MINVAL -32767 +#define SHRT_MAXVAL 32767 +#define LONG_MINVAL -2147483647L +#define LONG_MAXVAL 2147483647L +#define DWORD_MAXVAL 4294967295L #ifndef FALSE - #define FALSE 0 +#define FALSE 0 #endif #ifndef TRUE - #define TRUE 1 +#define TRUE 1 #endif #ifndef EMU_WINDOWS // windows.h defines these already -// #define LOBYTE(x) ((x) & 0x00FF) -// #define HIBYTE(x) (((x) & 0xFF00) >> 8) + // #define LOBYTE(x) ((x) & 0x00FF) + // #define HIBYTE(x) (((x) & 0xFF00) >> 8) #endif + /************* + * Typedefs + *************/ -/************* -* Typedefs -*************/ - -typedef char CHAR; /* 8 bit signed value */ -typedef short SHORT; /* 16 bit signed value was: INT */ + typedef char CHAR; /* 8 bit signed value */ + typedef short SHORT; /* 16 bit signed value was: INT */ #ifdef EMU_WINDOWS - /***************************************************************** - * These idiosyncratic pointer definitions for memory allocations - * which are greater than 64K and are Intel-centric compiling - * environment necessities, at least for Windows environments. - * Perhaps, however, Windows NT will eliminate the 'huge' keyword - * requirement altogether. - *****************************************************************/ - typedef BYTE huge* BYTEPTR; - typedef WORD huge* UINTPTR; - typedef DWORD huge* DWORDPTR; - typedef void huge* VOIDPTR; + /***************************************************************** + * These idiosyncratic pointer definitions for memory allocations + * which are greater than 64K and are Intel-centric compiling + * environment necessities, at least for Windows environments. + * Perhaps, however, Windows NT will eliminate the 'huge' keyword + * requirement altogether. + *****************************************************************/ + typedef BYTE huge *BYTEPTR; + typedef WORD huge *UINTPTR; + typedef DWORD huge *DWORDPTR; + typedef void huge *VOIDPTR; + /* Pointer-sized type for runtime memory addresses (32 or 64-bit) */ + typedef uintptr_t ADDR; #else - typedef unsigned char BYTE; /* 8 bit unsigned value */ + typedef unsigned char BYTE; /* 8 bit unsigned value */ #ifndef BOOL - typedef int BOOL; /* 16 bit signed value */ + typedef int BOOL; /* 16 bit signed value */ #endif - typedef unsigned short WORD; /* 16 bit signed value */ - typedef signed long LONG; /* 32 bit signed value */ - typedef unsigned long DWORD; /* 32 bit unsigned value */ - typedef float FLOAT; /* 32 bit floating point value */ - typedef double DOUBLE; /* 64 bit floating point value */ - typedef long double LDOUBLE; /* 80 bit floating point value */ - - typedef BYTE* BYTEPTR; - typedef WORD* UINTPTR; - typedef DWORD* DWORDPTR; - typedef void* VOIDPTR; + typedef unsigned short WORD; /* 16 bit unsigned value */ + typedef int32_t LONG; /* 32 bit signed value (fixed-size) */ + typedef uint32_t DWORD; /* 32 bit unsigned value (fixed-size) */ + typedef float FLOAT; /* 32 bit floating point value */ + typedef double DOUBLE; /* 64 bit floating point value */ + typedef long double LDOUBLE; /* 80 bit floating point value */ + + /* Pointer-sized type for runtime memory addresses (32 or 64-bit) */ + typedef uintptr_t ADDR; + + typedef BYTE *BYTEPTR; + typedef WORD *UINTPTR; + typedef DWORD *DWORDPTR; + typedef void *VOIDPTR; #endif /* EMU_WINDOWS */ -/******************************************************************** -* This 16 bit unsigned value is used for routines which return -* standard E-mu error codes (see emuerrs.h) -********************************************************************/ -typedef unsigned short EMUSTAT; + /******************************************************************** + * This 16 bit unsigned value is used for routines which return + * standard E-mu error codes (see emuerrs.h) + ********************************************************************/ + typedef unsigned short EMUSTAT; #ifdef __BYTE_COHERENT -/******************************************************************** -* Convenient union datatypes to use for byte swapping or extracting -* bytes and/or shorts within a short or long value without using -* bit shifting. -********************************************************************/ -typedef struct twoBytesTag -{ - BYTE by0; - BYTE by1; -} twoBytes; - + /******************************************************************** + * Convenient union datatypes to use for byte swapping or extracting + * bytes and/or shorts within a short or long value without using + * bit shifting. + ********************************************************************/ + typedef struct twoBytesTag { + BYTE by0; + BYTE by1; + } twoBytes; typedef struct fourBytesTag { @@ -153,12 +167,10 @@ typedef struct twoWordsTag #elif defined(__BYTE_INCOHERENT) -typedef struct twoBytesTag -{ - BYTE by1; - BYTE by0; -} twoBytes; - + typedef struct twoBytesTag { + BYTE by1; + BYTE by0; + } twoBytes; typedef struct fourBytesTag { diff --git a/sources/Externals/Soundfont/HYDRA.H b/sources/Externals/Soundfont/HYDRA.H index 23d4672a..3f686570 100644 --- a/sources/Externals/Soundfont/HYDRA.H +++ b/sources/Externals/Soundfont/HYDRA.H @@ -206,10 +206,10 @@ typedef struct sfSampleHdrTag { CHAR achSampleName[SAMPLENAMESIZE]; - DWORD dwStart; // Sample addresses - DWORD dwEnd; - DWORD dwStartloop; - DWORD dwEndloop; + ADDR dwStart; // Sample addresses + ADDR dwEnd; + ADDR dwStartloop; + ADDR dwEndloop; DWORD dwSampleRate; // In Hz, IE 44100, 22050, etc BYTE byOriginalKey; // MIDI Key, 0 to 127 CHAR chFineCorrection; // Tuning correction in cents diff --git a/sources/Externals/Soundfont/RIFF.CPP b/sources/Externals/Soundfont/RIFF.CPP index cc092bd5..494c087e 100644 --- a/sources/Externals/Soundfont/RIFF.CPP +++ b/sources/Externals/Soundfont/RIFF.CPP @@ -235,10 +235,9 @@ WORD RIFFClass::OpenRIFF(CHAR* pName) { byWhereIsRIFFData = RIFF_ONDISK; - if ((RIFFOpen((LONG)pName) != SUCCESS ) || (pFile == NULL)) - { - SetError(errno); // Set inside RIFFOpen - return (uiErrorNdx = RIFF_OPENFILEERROR); + if ((RIFFOpen((ADDR)pName) != SUCCESS) || (pFile == NULL)) { + SetError(errno); // Set inside RIFFOpen + return (uiErrorNdx = RIFF_OPENFILEERROR); } return (InitRIFF()); @@ -253,10 +252,10 @@ WORD RIFFClass::OpenRIFF(CHAR* pName) WORD RIFFClass::OpenRIFF(FSSpec* pSpecifier) { byWhereIsRIFFData = RIFF_ONMACDISK; - - if (RIFFOpen((LONG)pSpecifier) != SUCCESS) - return (RIFF_OPENFILEERROR); - + + if (RIFFOpen((ADDR)pSpecifier) != SUCCESS) + return (RIFF_OPENFILEERROR); + return(InitRIFF()); } #endif // USE_MACINTOSH @@ -443,28 +442,26 @@ DWORD RIFFClass::GetCkFormID(void) { return (dwLastFormID); } // is a pointer to the File System Specifier (FSSpec) // data structure. //*************************************************** -SHORT RIFFClass::RIFFOpen(LONG lPointer) -{ - //*************************************************** - // Keep in mind that whenever a system call is made and - // _no_ error takes place, errno is _not_ set to 0. - // Obviously, this means that any previous system call - // will set errno upon an error, one which is innocuous, - // but will cause fopen to _appear_ as though it failed. - // For example, open a temporary file which might not - // exist: - // - // fopen("tempfile", "wb"); - // - // If it doesn't exist, errno become 2 (in DOS, at - // least). Now call the fopen below for a preexisting - // RIFF file. Guess what! If you didn't reset errno - // to 0, your return value will be 2, an apparent error. - //*************************************************** - errno = 0; - - switch (byWhereIsRIFFData) - { +SHORT RIFFClass::RIFFOpen(ADDR lPointer) { + //*************************************************** + // Keep in mind that whenever a system call is made and + // _no_ error takes place, errno is _not_ set to 0. + // Obviously, this means that any previous system call + // will set errno upon an error, one which is innocuous, + // but will cause fopen to _appear_ as though it failed. + // For example, open a temporary file which might not + // exist: + // + // fopen("tempfile", "wb"); + // + // If it doesn't exist, errno become 2 (in DOS, at + // least). Now call the fopen below for a preexisting + // RIFF file. Guess what! If you didn't reset errno + // to 0, your return value will be 2, an apparent error. + //*************************************************** + errno = 0; + + switch (byWhereIsRIFFData) { case RIFF_ONDISK: pFile = fopen((CHAR *)lPointer, "rb"); return (errno); @@ -476,7 +473,7 @@ SHORT RIFFClass::RIFFOpen(LONG lPointer) default: return (1); - } + } } SHORT RIFFClass::RIFFClose() diff --git a/sources/Externals/Soundfont/RIFF.H b/sources/Externals/Soundfont/RIFF.H index ff12655d..0763b5ec 100644 --- a/sources/Externals/Soundfont/RIFF.H +++ b/sources/Externals/Soundfont/RIFF.H @@ -191,7 +191,7 @@ class RIFFClass DWORD RIFFTell(void); DWORD RIFFTellAbs(void); - SHORT RIFFOpen(LONG); + SHORT RIFFOpen(ADDR); SHORT RIFFClose(void); diff --git a/sources/Externals/Soundfont/SFDATA.H b/sources/Externals/Soundfont/SFDATA.H index 1c4ff1c8..9540f8e3 100644 --- a/sources/Externals/Soundfont/SFDATA.H +++ b/sources/Externals/Soundfont/SFDATA.H @@ -53,10 +53,10 @@ typedef enum sfSampleFlagsTag typedef struct sfDataTag { //// Oscillator //// - DWORD dwStart; //// sample start address - DWORD dwEnd; - DWORD dwStartloop; //// loop start address - DWORD dwEndloop; //// loop end address + ADDR dwStart; //// sample start address (pointer-sized for 64-bit) + ADDR dwEnd; + ADDR dwStartloop; //// loop start address (pointer-sized for 64-bit) + ADDR dwEndloop; //// loop end address (pointer-sized for 64-bit) DWORD dwSampleRate; SHORT shOrigKeyAndCorr; SHORT shSampleModes; diff --git a/sources/Externals/Soundfont/SFNAV.CPP b/sources/Externals/Soundfont/SFNAV.CPP index d16cc892..af023797 100644 --- a/sources/Externals/Soundfont/SFNAV.CPP +++ b/sources/Externals/Soundfont/SFNAV.CPP @@ -468,8 +468,8 @@ void SoundFontNavigator::Navigate(WORD uiSFID, WORD uiKey, WORD uiVel) // This step necessary for Big Endian systems if (uiInstGenOper <= endloopAddrsOffset) - *(LONG*)((BYTE*)&(psfVectorCurrOsc->dwStart) + - soundFontLookup[uiInstGenOper]) = (LONG)iInstGenAmt; + *(ADDR *)((BYTE *)&(psfVectorCurrOsc->dwStart) + + soundFontLookup[uiInstGenOper]) = (ADDR)iInstGenAmt; else *(SHORT*)((BYTE*)&(psfVectorCurrOsc->dwStart) + soundFontLookup[uiInstGenOper]) = iInstGenAmt; @@ -520,8 +520,8 @@ void SoundFontNavigator::Navigate(WORD uiSFID, WORD uiKey, WORD uiVel) // Necessary for 'byte-incoherent' systems if (uiGenOper <= endloopAddrsOffset) - *(LONG*)((BYTE*)&sfCurrPreset.dwStart + - soundFontLookup[uiGenOper]) = (LONG)iGenAmt; + *(ADDR *)((BYTE *)&sfCurrPreset.dwStart + + soundFontLookup[uiGenOper]) = (ADDR)iGenAmt; else *(SHORT*)((BYTE*)&sfCurrPreset.dwStart + soundFontLookup[uiGenOper]) = iGenAmt; @@ -815,8 +815,13 @@ SoundFontNavigator::AddSoundFonts(sfData * sfSoundFontReturned, { uiOffset = (WORD) soundFontLookup[wCount]; - *(SHORT*)((BYTE*)&(sfSoundFontReturned->dwStart) + uiOffset) += - *(SHORT*)((BYTE*)&(sfSFPresetAdd->dwStart) + uiOffset); + if (wCount <= endloopAddrsOffset) { + *(ADDR *)((BYTE *)&(sfSoundFontReturned->dwStart) + uiOffset) += + *(ADDR *)((BYTE *)&(sfSFPresetAdd->dwStart) + uiOffset); + } else { + *(SHORT *)((BYTE *)&(sfSoundFontReturned->dwStart) + uiOffset) += + *(SHORT *)((BYTE *)&(sfSFPresetAdd->dwStart) + uiOffset); + } } } diff --git a/sources/Externals/Soundfont/SFREADER.CPP b/sources/Externals/Soundfont/SFREADER.CPP index 5004ae16..94e4d368 100644 --- a/sources/Externals/Soundfont/SFREADER.CPP +++ b/sources/Externals/Soundfont/SFREADER.CPP @@ -667,11 +667,27 @@ ReadSFBData (CHAR * pchReqdWaveTable) //// Sample Headers //// for (uiCount = 0; uiCount < hf->awStructSize[sampHdr]; uiCount++) { - - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwStart); - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwEnd); - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwStartloop); - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwEndloop); + // For ADDR fields, we need to swap using temporary 32-bit variables + // since the file format uses 32-bit values but we store in pointer-sized + // fields + { + DWORD tmp; + tmp = (DWORD)hf->pSHdr[uiCount].dwStart; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwStart = tmp; + + tmp = (DWORD)hf->pSHdr[uiCount].dwEnd; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwEnd = tmp; + + tmp = (DWORD)hf->pSHdr[uiCount].dwStartloop; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwStartloop = tmp; + + tmp = (DWORD)hf->pSHdr[uiCount].dwEndloop; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwEndloop = tmp; + } tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwSampleRate); @@ -794,25 +810,29 @@ WORD mono = monoSample; // Element for element read of data, to serve as an example of a possible // issue with cross platform code. See comments below. // - for(WORD curHdr=0; curHdr < hf->awStructSize[iHydraSymbol]; curHdr++) { + for (WORD curHdr = 0; curHdr < hf->awStructSize[iHydraSymbol]; curHdr++) { + + rcnt = 0; - rcnt = 0; + rcnt += tRIFF.RIFFRead((VOIDPTR) & + ((sfSampleHdr *)pData)[curHdr].achSampleName, + 1, SAMPLENAMESIZE); - rcnt += tRIFF.RIFFRead((VOIDPTR) - &((sfSampleHdr*)pData)[curHdr].achSampleName, - 1, SAMPLENAMESIZE); + // Read 32-bit file values into temporaries, then assign to + // pointer-sized fields + uint32_t tmp_dwStart, tmp_dwEnd, tmp_dwStartloop, tmp_dwEndloop; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwStart, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwStart, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwStart = tmp_dwStart; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwEnd, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwEnd, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwEnd = tmp_dwEnd; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwStartloop, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwStartloop, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwStartloop = tmp_dwStartloop; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwEndloop, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwEndloop, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwEndloop = tmp_dwEndloop; rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwSampleRate, 1, sizeof(DWORD)); @@ -837,7 +857,7 @@ WORD mono = monoSample; SetError(SF_INVALIDBANK); return (NULL); } - }// end for all elements + } // end for all elements } // do sampleHdr reading, else { From 556034dd1c4ad473d9773cd5b5ad6e4061492199 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Wed, 7 Jan 2026 19:00:34 +0000 Subject: [PATCH 11/12] Remove duplicate code --- .../Views/ModalDialogs/NewProjectDialog.cpp | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 48366734..94669911 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -231,35 +231,7 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask, bool pressed) { name_[currentChar_]-=1; lastChar_=name_[currentChar_] ; isDirty_=true ; - } - } else { - - // A modifier - if (mask & EPBM_A) { - if (mask == EPBM_A) { - std::string randomName = getRandomName(); - switch (selected_) { - case 0: - if (name_[currentChar_] == ' ') { - name_[currentChar_] = lastChar_; - } - isDirty_ = true; - break; - case 1: - std::fill(name_ + randomName.length(), - name_ + sizeof(name_) / sizeof(name_[0]), ' '); - strncpy(name_, randomName.c_str(), randomName.length()); - lastChar_ = currentChar_ = randomName.length() - 1; - isDirty_ = true; - break; - case 2: - EndModal(1); - break; - case 3: - EndModal(0); - break; - } - } + } } else { // R Modifier @@ -309,7 +281,6 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask, bool pressed) { isDirty_ = true; } } - } } }; From 6aa401195a9f600eb034729fd74355d58c5fc1a9 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 8 Jan 2026 18:59:19 +0000 Subject: [PATCH 12/12] Minor cleanup and formatting --- sources/Application/Utils/KeyboardLayout.h | 36 ++++++++++--------- .../Views/ModalDialogs/NewProjectDialog.cpp | 4 +-- .../Views/ModalDialogs/NewProjectDialog.h | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/sources/Application/Utils/KeyboardLayout.h b/sources/Application/Utils/KeyboardLayout.h index c260c1cc..c6ae7704 100644 --- a/sources/Application/Utils/KeyboardLayout.h +++ b/sources/Application/Utils/KeyboardLayout.h @@ -7,8 +7,8 @@ #define SPACE_ROW 7 #define KEYBOARD_ROWS (SPACE_ROW + 1) -#define SPCE_START 0 -#define SPCE_END 3 +#define SPACE_START 0 +#define SPACE_END 3 #define BACK_START 4 #define BACK_END 6 #define DONE_START 8 @@ -26,7 +26,7 @@ static const char* keyboardLayout[] = { }; // Helper functions for special row section detection -inline bool isInSpaceSection(int col) { return col < SPCE_END; } +inline bool isInSpaceSection(int col) { return col < SPACE_END; } inline bool isInBackSection(int col) { return col >= BACK_START && col < BACK_END; } inline bool isInDoneSection(int col) { return col >= DONE_START; } @@ -37,8 +37,9 @@ inline char getKeyAtPosition(int row, int col) { // Handle special row with SPC, BACK, and DONE if (row == SPACE_ROW) { - if (col >= 0 && col < SPCE_END) return ' '; // [_] (space) - if (col >= BACK_START && col < BACK_END) return '\b'; // <- (backspace) + if (col >= 0 && col < SPACE_END) + return ' '; // [_] (space) + if (col >= BACK_START && col < BACK_END) return '\b'; // <- (backspace) if (col >= DONE_START && col < DONE_END) return '\r'; // OK (carriage return) return '\0'; } @@ -69,29 +70,30 @@ inline void findCharacterInKeyboard(char ch, int &outRow, int &outCol) { // Clamp keyboard column to valid range for current row inline void clampKeyboardColumn(int row, int& col) { - if (row == SPACE_ROW) { - if (col < SPCE_END) col = SPCE_START; + if (row == SPACE_ROW) { + if (col < SPACE_END) col = SPACE_START; else if (col <= BACK_END) col = BACK_START; else col = DONE_START; - } else { - int maxCol = strlen(keyboardLayout[row]) - 1; + } else { + int maxCol = strlen(keyboardLayout[row]) - 1; if (col > maxCol) col = 0; - } + } } // Cycle keyboard column left (-1) or right (+1) within current row inline void cycleKeyboardColumn(int row, int direction, int& col) { if (row == SPACE_ROW) { if (direction < 0) { // LEFT - if (isInSpaceSection(col)) col = DONE_START; - else if (isInBackSection(col)) col = SPCE_START; + if (isInSpaceSection(col)) + col = DONE_START; + else if (isInBackSection(col)) col = SPACE_START; else col = BACK_START; - } else { // RIGHT - if (isInBackSection(col)) col = DONE_START; - else if (isInDoneSection(col)) col = SPCE_START; + } else { // RIGHT + if (isInBackSection(col)) col = DONE_START; + else if (isInDoneSection(col)) col = SPACE_START; else col = BACK_START; - } - } else { + } + } else { int maxCol = strlen(keyboardLayout[row]) - 1; col = (col + direction + maxCol + 1) % (maxCol + 1); } diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 94669911..1f4d7649 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -18,7 +18,8 @@ void NewProjectDialog::moveCursor(int direction) { int newPos = currentChar_ + direction; if (newPos >= 0 && newPos < MAX_NAME_LENGTH) { currentChar_ = newPos; - findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, + keyboardCol_); } } @@ -130,7 +131,6 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask, bool pressed) { // END key: exit keyboard mode (same as START) keyboardMode_ = false; isDirty_ = true; - // EndModal(0); return; } else if (ch != '\0') { name_[currentChar_] = ch; diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.h b/sources/Application/Views/ModalDialogs/NewProjectDialog.h index 917e2953..fa159cac 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.h +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.h @@ -29,6 +29,6 @@ class NewProjectDialog:public ModalView { bool keyboardMode_; int keyboardRow_; int keyboardCol_ ; - void moveCursor(int direction); + void moveCursor(int direction); }; #endif