Skip to content
Merged
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
20 changes: 11 additions & 9 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
1.6.0-bacon10
Allow greater granular stretching using LPOF
Documentation in tips and tricks

1.6.0-bacon11
Slices decoupled from loop mode
* Slices are no longer a loop mode — they are now an independent parameter
* Set slices > 1 to enable slicing; loop mode (none/loop/ping pong/etc.) applies within each slice
* Enables looped slices, e.g. for amen breaks and other timed loops
* Old projects with "slicer" loop mode load correctly: slices count is preserved, loop mode resets to "none"

1.6.0-bacon10
Allow greater granular stretching using LPOF
Documentation in tips and tricks
1.6.0-bacon10
Slices decoupled from loop mode
* Slices are no longer a loop mode — they are now an independent parameter
* Set slices > 1 to enable slicing; loop mode (none/loop/ping pong/etc.) applies within each slice
* Enables looped slices, e.g. for amen breaks and other timed loops
* Old projects with "slicer" loop mode load correctly: slices count is preserved, loop mode resets to "none"

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
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
Loading