Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
1.6.0-bacon6
Delete project from SelectProjectDialog
* Press A + B on a project in the project selection screen to delete it
* A confirmation dialog will appear asking to confirm deletion
* The entire project directory and all contents will be removed
* List position is preserved after deletion

1.6.0-bacon5
Auto-load last project on startup
* Application can now load the last project automatically on startup
* Disable by setting AUTO_LOAD_LAST=NO in config.xml

1.6.0-bacon4
QWERTY keyboard name entry for new projects
* Press A on the project name field to enter QWERTY keyboard mode
Expand Down
17 changes: 17 additions & 0 deletions docs/wiki/quick_start_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,23 @@ to save, piggy playback must be stopped (so hit `start` if need be). navigate to

don't forget to come back later and keep butchering the pig :)

## managing your projects

### deleting a project

If you ever need to delete an entire project, you can do so from the Project Selection screen.

To delete a project:

1. from the Project Selection screen, position your cursor on the project you wish to delete
2. press `A + B`
3. a confirmation dialog will appear showing the project name and asking you to confirm the deletion
4. select `yes` to delete the project permanently, or `no` to cancel

**be careful!** deletion is permanent and cannot be undone. make sure you have backed up your work if you wish to keep it. the entire project directory will be removed, including all songs, chains, phrases, and any associated data.

it's always a good idea to keep backups of important projects before deleting anything!

## live mode & muting

![](https://web.archive.org/web/20190513041654im_/http://wiki.littlegptracker.com/lib/exe/fetch.php?media=quick:start14_1.1f.png)
Expand Down
14 changes: 14 additions & 0 deletions docs/wiki/tips_and_tricks.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ The on-screen keyboard is organized like this:
- Lowercase (a-q + extra characters)
- Special [Space] [Erase] [Done]

# Project Management

## Safely Deleting Projects

Since version 1.6.0, you can delete projects directly from the Project Selection screen by pressing `A+B`. This is a convenient way to clean up old or unwanted projects.

**Best Practices:**
- **Always back up important projects** before deleting. Use your operating system's file manager to copy project directories to an external drive or backup location.
- The deletion will remove the entire project directory permanently - this cannot be undone!
- A confirmation dialog will appear showing the project name before deletion proceeds, giving you a chance to cancel if you selected the wrong project.
- After deletion, the project list will refresh automatically and the cursor will stay near its previous position for your convenience.

**Pro Tip:** Use Save As to store a duplicate of the project if you're uncertain if you should delete something

# Delays and Echoes
## Simulating LSDj's D command

Expand Down
2 changes: 1 addition & 1 deletion sources/Application/Model/Project.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#define PROJECT_NUMBER "1"
#define PROJECT_RELEASE "6"
#define BUILD_COUNT "0-bacon5"
#define BUILD_COUNT "0-bacon6"

#define MAX_TAP 3

Expand Down
133 changes: 129 additions & 4 deletions sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,61 @@ static void NewProjectCallback(View &v,ModalView &dialog) {
Trace::Error(result.GetDescription().c_str());
}
}
};
}

SelectProjectDialog::SelectProjectDialog(View &view):ModalView(view),content_(true) {
static void DeleteProjectCallback(View &v, ModalView &dialog) {
SelectProjectDialog &spd = (SelectProjectDialog&) v;
if (dialog.GetReturnCode() == MBL_YES) {
Path projectPath = spd.GetCurrentProjectPath();
Result result = spd.OnDeleteProject(projectPath);
if (result.Failed()) {
Trace::Error(result.GetDescription().c_str());
}
}
}

// Recursive helper to delete directory and all contents
static void RecursiveDeleteDirectory(const Path &dirPath) {
FileSystem *fs = FileSystem::GetInstance();
FileType type = fs->GetFileType(dirPath.GetPath().c_str());

if (type == FT_DIR) {
I_Dir *dir = fs->Open(dirPath.GetPath().c_str());
if (dir) {
dir->GetContent("*");

// Collect all items first to avoid iterator invalidation
T_SimpleList<Path> itemsToDelete(false);
IteratorPtr<Path> it(dir->GetIterator());

for (it->Begin(); !it->IsDone(); it->Next()) {
Path itemCopy = it->CurrentItem();
std::string name = itemCopy.GetName();

// Skip . and .. entries
if (name != "." && name != "..") {
Path *ptrCopy = new Path(itemCopy);
itemsToDelete.Insert(ptrCopy);
}
}

delete dir;

// Now delete all collected items
IteratorPtr<Path> deleteIt(itemsToDelete.GetIterator());
for (deleteIt->Begin(); !deleteIt->IsDone(); deleteIt->Next()) {
const Path &item = deleteIt->CurrentItem();
RecursiveDeleteDirectory(item);
}
}
}

fs->Delete(dirPath.GetPath().c_str());
}

SelectProjectDialog::SelectProjectDialog(View &view)
: ModalView(view), content_(true) {}

SelectProjectDialog::~SelectProjectDialog() {
}

Expand Down Expand Up @@ -118,14 +168,37 @@ void SelectProjectDialog::OnPlayerUpdate(PlayerEventType,
void SelectProjectDialog::OnFocus() {

setCurrentFolder(lastFolder_) ;
currentProject_=lastProject_ ;

currentProject_ = lastProject_;
};

void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) {
if (!pressed) return ;

if (mask&EPBM_B) {
// Handle A + B combination for delete
if (mask & EPBM_A) {
int count = 0;
Path *current = 0;

IteratorPtr<Path> it(content_.GetIterator());
for (it->Begin(); !it->IsDone(); it->Next()) {
if (count == currentProject_) {
current = &it->CurrentItem();
break;
}
count++;
}

if (current != 0) {
std::string message =
"Delete project '" + current->GetName() + "' ?";
MessageBox *mb =
new MessageBox(*this, message.c_str(), MBBF_YES | MBBF_NO);
DoModal(mb, DeleteProjectCallback);
DrawView();
}
return;
}
if (mask & EPBM_UP)
warpToNextProject(-LIST_SIZE);
if (mask&EPBM_DOWN) warpToNextProject(LIST_SIZE) ;
Expand Down Expand Up @@ -250,6 +323,46 @@ Result SelectProjectDialog::OnNewProject(std::string &name) {
return Result::NoError;
} ;

Result SelectProjectDialog::OnDeleteProject(const Path &projectPath) {

Trace::Log("SelectProjectDialog:OnDelProj","deleting project at %s", projectPath.GetPath().c_str());

// Make a non-const copy to check existence
Path pathCopy = projectPath;

// Check if project exists before deletion
if (!pathCopy.Exists()) {
std::string errMsg = "Project not found";
View::SetNotification(errMsg.c_str(), 0);
return Result("Project not found");
}

// Recursively delete the project directory and all contents
RecursiveDeleteDirectory(projectPath);

// Project deleted successfully, refresh the project list
std::string successMsg = "Project deleted: " + pathCopy.GetName();
View::SetNotification(successMsg.c_str(), 0);

// Refresh current folder to update the list while preserving position
int savedProject = currentProject_;
int savedTopIndex = topIndex_;
Path currentPathCopy = currentPath_;
setCurrentFolder(currentPathCopy);

// Restore position (adjust if necessary if we're at the end of list)
int listSize = content_.Size();
if (savedProject >= listSize && listSize > 0) {
currentProject_ = listSize - 1;
} else if (listSize > 0) {
currentProject_ = savedProject;
}
topIndex_ = savedTopIndex;
isDirty_ = true;

return Result::NoError;
};

//copy-paste-mutilate'd from ImportSampleDialog
void SelectProjectDialog::setCurrentFolder(Path &path) {

Expand Down Expand Up @@ -293,3 +406,15 @@ void SelectProjectDialog::setCurrentFolder(Path &path) {
currentProject_=0 ;
isDirty_ = true;
}

Path SelectProjectDialog::GetCurrentProjectPath() {
int count = 0;
IteratorPtr<Path> it(content_.GetIterator());
for (it->Begin(); !it->IsDone(); it->Next()) {
if (count == currentProject_) {
return it->CurrentItem();
}
count++;
}
return Path();
}
24 changes: 13 additions & 11 deletions sources/Application/Views/ModalDialogs/SelectProjectDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,24 @@ class SelectProjectDialog:public ModalView {
virtual void ProcessButtonMask(unsigned short mask,bool pressed) ;

Result OnNewProject(std::string &name) ;
Result OnDeleteProject(const Path &projectPath);

Path GetSelection() ;
Path GetSelection();
Path GetCurrentProjectPath();

protected:
void warpToNextProject(int amount) ;
protected:
void warpToNextProject(int amount) ;
void setCurrentFolder(Path &path) ;

private:
T_SimpleList<Path> content_ ;
int topIndex_ ;
int currentProject_ ;
int selected_ ;
Path currentPath_ ;
Path selection_ ;
static Path lastFolder_ ;
static int lastProject_ ;
T_SimpleList<Path> content_;
int topIndex_;
int currentProject_;
int selected_;
Path currentPath_;
Path selection_;
static Path lastFolder_;
static int lastProject_;
} ;

#endif