- Refactored edition actions into a separate namespace for reusability

- Direct consequence of the previous : smooth addition of the Edit Menu
This commit is contained in:
Stepland 2019-03-28 10:54:50 +01:00
parent 713bb70c91
commit bba736da08
6 changed files with 201 additions and 108 deletions

View File

@ -50,7 +50,7 @@ set(SOURCE_FILES
SoundEffect.h SoundEffect.h
TimeSelection.h TimeSelection.h
NotesClipboard.cpp NotesClipboard.cpp
NotesClipboard.h ChartWithHistory.cpp ChartWithHistory.h Preferences.cpp Preferences.h) NotesClipboard.h ChartWithHistory.cpp ChartWithHistory.h Preferences.cpp Preferences.h EditActions.cpp EditActions.h)
#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${FEIS_SOURCE_DIR}/cmake") #set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${FEIS_SOURCE_DIR}/cmake")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})

96
EditActions.cpp Normal file
View File

@ -0,0 +1,96 @@
//
// Created by Syméon on 28/03/2019.
//
#include "EditActions.h"
void EditActions::undo(std::optional<EditorState>& ed, NotificationsQueue& nq) {
if (ed and ed->chart) {
auto previous = ed->chart->history.get_previous();
if (previous) {
nq.push(std::make_shared<UndoNotification>(**previous));
(*previous)->undoAction(*ed);
ed->densityGraph.should_recompute = true;
}
}
}
void EditActions::redo(std::optional<EditorState>& ed, NotificationsQueue& nq) {
if (ed and ed->chart) {
auto next = ed->chart->history.get_next();
if (next) {
nq.push(std::make_shared<RedoNotification>(**next));
(*next)->doAction(*ed);
ed->densityGraph.should_recompute = true;
}
}
}
void EditActions::cut(std::optional<EditorState>& ed, NotificationsQueue& nq) {
if (ed and ed->chart and (not ed->chart->selectedNotes.empty())) {
std::stringstream ss;
ss << "Cut " << ed->chart->selectedNotes.size() << " note";
if (ed->chart->selectedNotes.size() > 1) {
ss << "s";
}
nq.push(std::make_shared<TextNotification>(ss.str()));
ed->chart->notesClipboard.copy(ed->chart->selectedNotes);
for (auto note : ed->chart->selectedNotes) {
ed->chart->ref.Notes.erase(note);
}
ed->chart->history.push(std::make_shared<ToggledNotes>(ed->chart->selectedNotes,false));
ed->chart->selectedNotes.clear();
}
}
void EditActions::copy(std::optional<EditorState>& ed, NotificationsQueue& nq) {
if (ed and ed->chart and (not ed->chart->selectedNotes.empty())) {
std::stringstream ss;
ss << "Copied " << ed->chart->selectedNotes.size() << " note";
if (ed->chart->selectedNotes.size() > 1) {
ss << "s";
}
nq.push(std::make_shared<TextNotification>(ss.str()));
ed->chart->notesClipboard.copy(ed->chart->selectedNotes);
}
}
void EditActions::paste(std::optional<EditorState>& ed, NotificationsQueue& nq) {
if (ed and ed->chart and (not ed->chart->notesClipboard.empty())) {
int tick_offset = static_cast<int>(ed->getCurrentTick());
std::set<Note> pasted_notes = ed->chart->notesClipboard.paste(tick_offset);
std::stringstream ss;
ss << "Pasted " << pasted_notes.size() << " note";
if (pasted_notes.size() > 1) {
ss << "s";
}
nq.push(std::make_shared<TextNotification>(ss.str()));
for (auto note : pasted_notes) {
ed->chart->ref.Notes.insert(note);
}
ed->chart->selectedNotes = pasted_notes;
ed->chart->history.push(std::make_shared<ToggledNotes>(ed->chart->selectedNotes,true));
}
}
void EditActions::delete_(std::optional<EditorState>& ed, NotificationsQueue& nq) {
if (ed and ed->chart) {
if (not ed->chart->selectedNotes.empty()) {
ed->chart->history.push(std::make_shared<ToggledNotes>(ed->chart->selectedNotes,false));
nq.push(std::make_shared<TextNotification>("Deleted selected notes"));
for (auto note : ed->chart->selectedNotes) {
ed->chart->ref.Notes.erase(note);
}
ed->chart->selectedNotes.clear();
}
}
}

24
EditActions.h Normal file
View File

@ -0,0 +1,24 @@
//
// Created by Syméon on 28/03/2019.
//
#ifndef FEIS_EDITACTIONS_H
#define FEIS_EDITACTIONS_H
#include "NotificationsQueue.h"
#include "EditorState.h"
namespace EditActions {
void undo(std::optional<EditorState>& ed, NotificationsQueue& nq);
void redo(std::optional<EditorState>& ed, NotificationsQueue& nq);
void cut(std::optional<EditorState>& ed, NotificationsQueue& nq);
void copy(std::optional<EditorState>& ed, NotificationsQueue& nq);
void paste(std::optional<EditorState>& ed, NotificationsQueue& nq);
void delete_(std::optional<EditorState>& ed, NotificationsQueue& nq);
};
#endif //FEIS_EDITACTIONS_H

View File

@ -634,6 +634,21 @@ saveChangesResponses EditorState::alertSaveChanges() {
} }
} }
/*
* Saves if asked and returns false if user canceled
*/
bool EditorState::saveChangesOrCancel() {
switch(alertSaveChanges()) {
case saveChangesYes:
ESHelper::save(*this);
case saveChangesNo:
case saveChangesDidNotDisplayDialog:
return true;
case saveChangesCancel:
return false;
}
}
/* /*
* This SCREAAAAMS for optimisation, but in the meantime it works ! * This SCREAAAAMS for optimisation, but in the meantime it works !
*/ */
@ -737,7 +752,19 @@ void ESHelper::openFromFile(std::optional<EditorState> &ed, std::filesystem::pat
} }
/* /*
* Returns the newly created chart if there is * returns true if user saved or if saving wasn't necessary
* returns false if user canceled
*/
bool ESHelper::saveOrCancel(std::optional<EditorState>& ed) {
if (ed) {
return ed->saveChangesOrCancel();
} else {
return true;
}
}
/*
* Returns the newly created chart if there is one
*/ */
std::optional<Chart> ESHelper::NewChartDialog::display(EditorState &editorState) { std::optional<Chart> ESHelper::NewChartDialog::display(EditorState &editorState) {

View File

@ -107,6 +107,7 @@ public:
void displayLinearView(); void displayLinearView();
saveChangesResponses alertSaveChanges(); saveChangesResponses alertSaveChanges();
bool saveChangesOrCancel();
void updateVisibleNotes(); void updateVisibleNotes();
std::set<Note> visibleNotes; std::set<Note> visibleNotes;
@ -119,6 +120,8 @@ namespace ESHelper {
void open(std::optional<EditorState>& ed); void open(std::optional<EditorState>& ed);
void openFromFile(std::optional<EditorState>& ed, std::filesystem::path path); void openFromFile(std::optional<EditorState>& ed, std::filesystem::path path);
bool saveOrCancel(std::optional<EditorState>& ed);
class NewChartDialog { class NewChartDialog {
public: public:

155
main.cpp
View File

@ -11,6 +11,7 @@
#include "SoundEffect.h" #include "SoundEffect.h"
#include "TimeSelection.h" #include "TimeSelection.h"
#include "Preferences.h" #include "Preferences.h"
#include "EditActions.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -65,17 +66,7 @@ int main(int argc, char** argv) {
switch (event.type) { switch (event.type) {
case sf::Event::Closed: case sf::Event::Closed:
preferences.save(); preferences.save();
if (editorState) { if (ESHelper::saveOrCancel(editorState)) {
switch (editorState->alertSaveChanges()) {
case saveChangesYes:
ESHelper::save(*editorState);
case saveChangesNo:
case saveChangesDidNotDisplayDialog:
window.close();
case saveChangesCancel:
break;
}
} else {
window.close(); window.close();
} }
break; break;
@ -168,16 +159,7 @@ int main(int argc, char** argv) {
// Delete selected notes from the chart and discard timeSelection // Delete selected notes from the chart and discard timeSelection
case sf::Keyboard::Delete: case sf::Keyboard::Delete:
if (editorState and editorState->chart) { EditActions::delete_(editorState, notificationsQueue);
if (not editorState->chart->selectedNotes.empty()) {
editorState->chart->history.push(std::make_shared<ToggledNotes>(editorState->chart->selectedNotes,false));
notificationsQueue.push(std::make_shared<TextNotification>("Deleted selected notes"));
for (auto note : editorState->chart->selectedNotes) {
editorState->chart->ref.Notes.erase(note);
}
editorState->chart->selectedNotes.clear();
}
}
break; break;
/* /*
@ -310,22 +292,14 @@ int main(int argc, char** argv) {
*/ */
case sf::Keyboard::C: case sf::Keyboard::C:
if (event.key.control) { if (event.key.control) {
if (editorState and editorState->chart and (not editorState->chart->selectedNotes.empty())) { EditActions::copy(editorState, notificationsQueue);
std::stringstream ss;
ss << "Copied " << editorState->chart->selectedNotes.size() << " note";
if (editorState->chart->selectedNotes.size() > 1) {
ss << "s";
}
notificationsQueue.push(std::make_shared<TextNotification>(ss.str()));
editorState->chart->notesClipboard.copy(editorState->chart->selectedNotes);
}
} }
break; break;
case sf::Keyboard::O: case sf::Keyboard::O:
if (event.key.control) { if (event.key.control) {
ESHelper::open(editorState); if (ESHelper::saveOrCancel(editorState)) {
ESHelper::open(editorState);
}
} }
break; break;
case sf::Keyboard::P: case sf::Keyboard::P:
@ -341,68 +315,22 @@ int main(int argc, char** argv) {
break; break;
case sf::Keyboard::V: case sf::Keyboard::V:
if (event.key.control) { if (event.key.control) {
if (editorState and editorState->chart and (not editorState->chart->notesClipboard.empty())) { EditActions::paste(editorState, notificationsQueue);
int tick_offset = static_cast<int>(editorState->getCurrentTick());
std::set<Note> pasted_notes = editorState->chart->notesClipboard.paste(tick_offset);
std::stringstream ss;
ss << "Pasted " << pasted_notes.size() << " note";
if (pasted_notes.size() > 1) {
ss << "s";
}
notificationsQueue.push(std::make_shared<TextNotification>(ss.str()));
for (auto note : pasted_notes) {
editorState->chart->ref.Notes.insert(note);
}
editorState->chart->selectedNotes = pasted_notes;
editorState->chart->history.push(std::make_shared<ToggledNotes>(editorState->chart->selectedNotes,true));
}
} }
break; break;
case sf::Keyboard::X: case sf::Keyboard::X:
if (event.key.control) { if (event.key.control) {
if (editorState and editorState->chart and (not editorState->chart->selectedNotes.empty())) { EditActions::cut(editorState, notificationsQueue);
std::stringstream ss;
ss << "Cut " << editorState->chart->selectedNotes.size() << " note";
if (editorState->chart->selectedNotes.size() > 1) {
ss << "s";
}
notificationsQueue.push(std::make_shared<TextNotification>(ss.str()));
editorState->chart->notesClipboard.copy(editorState->chart->selectedNotes);
for (auto note : editorState->chart->selectedNotes) {
editorState->chart->ref.Notes.erase(note);
}
editorState->chart->history.push(std::make_shared<ToggledNotes>(editorState->chart->selectedNotes,false));
editorState->chart->selectedNotes.clear();
}
} }
break; break;
case sf::Keyboard::Y: case sf::Keyboard::Y:
if (event.key.control) { if (event.key.control) {
if (editorState and editorState->chart) { EditActions::redo(editorState, notificationsQueue);
auto next = editorState->chart->history.get_next();
if (next) {
notificationsQueue.push(std::make_shared<RedoNotification>(**next));
(*next)->doAction(*editorState);
editorState->densityGraph.should_recompute = true;
}
}
} }
break; break;
case sf::Keyboard::Z: case sf::Keyboard::Z:
if (event.key.control) { if (event.key.control) {
if (editorState and editorState->chart) { EditActions::undo(editorState, notificationsQueue);
auto previous = editorState->chart->history.get_previous();
if (previous) {
notificationsQueue.push(std::make_shared<UndoNotification>(**previous));
(*previous)->undoAction(*editorState);
editorState->densityGraph.should_recompute = true;
}
}
} }
break; break;
default: default:
@ -556,39 +484,33 @@ int main(int argc, char** argv) {
{ {
if (ImGui::BeginMenu("File")) { if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("New")) { if (ImGui::MenuItem("New")) {
const char* _filepath = tinyfd_saveFileDialog("New File",nullptr,0,nullptr,nullptr); if (ESHelper::saveOrCancel(editorState)) {
if (_filepath != nullptr) { const char* _filepath = tinyfd_saveFileDialog("New File",nullptr,0,nullptr,nullptr);
std::filesystem::path filepath(_filepath); if (_filepath != nullptr) {
try { std::filesystem::path filepath(_filepath);
Fumen f(filepath); try {
f.autoSaveAsMemon(); Fumen f(filepath);
editorState.emplace(f); f.autoSaveAsMemon();
Toolbox::pushNewRecentFile(std::filesystem::canonical(editorState->fumen.path)); editorState.emplace(f);
} catch (const std::exception& e) { Toolbox::pushNewRecentFile(std::filesystem::canonical(editorState->fumen.path));
tinyfd_messageBox("Error",e.what(),"ok","error",1); } catch (const std::exception& e) {
tinyfd_messageBox("Error",e.what(),"ok","error",1);
}
} }
} }
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Open","Ctrl+O")) { if (ImGui::MenuItem("Open","Ctrl+O")) {
ESHelper::open(editorState); if (ESHelper::saveOrCancel(editorState)) {
ESHelper::open(editorState);
}
} }
if (ImGui::BeginMenu("Recent Files")) { if (ImGui::BeginMenu("Recent Files")) {
int i = 0; int i = 0;
for (const auto& file : Toolbox::getRecentFiles()) { for (const auto& file : Toolbox::getRecentFiles()) {
ImGui::PushID(i); ImGui::PushID(i);
if (ImGui::MenuItem(file.c_str())) { if (ImGui::MenuItem(file.c_str())) {
if (editorState) { if (ESHelper::saveOrCancel(editorState)) {
switch(editorState->alertSaveChanges()) {
case saveChangesYes:
ESHelper::save(*editorState);
case saveChangesNo:
case saveChangesDidNotDisplayDialog:
ESHelper::openFromFile(editorState,file);
case saveChangesCancel:
break;
}
} else {
ESHelper::openFromFile(editorState,file); ESHelper::openFromFile(editorState,file);
} }
} }
@ -598,7 +520,9 @@ int main(int argc, char** argv) {
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::MenuItem("Close","",false,editorState.has_value())) { if (ImGui::MenuItem("Close","",false,editorState.has_value())) {
editorState.reset(); if (ESHelper::saveOrCancel(editorState)) {
editorState.reset();
}
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Save","Ctrl+S",false,editorState.has_value())) { if (ImGui::MenuItem("Save","Ctrl+S",false,editorState.has_value())) {
@ -623,6 +547,25 @@ int main(int argc, char** argv) {
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("Edit")) { if (ImGui::BeginMenu("Edit")) {
if (ImGui::MenuItem("Undo", "Ctrl+Z")) {
EditActions::undo(editorState, notificationsQueue);
}
if (ImGui::MenuItem("Redo", "Ctrl+Y")) {
EditActions::redo(editorState, notificationsQueue);
}
ImGui::Separator();
if (ImGui::MenuItem("Cut", "Ctrl+X")) {
EditActions::cut(editorState, notificationsQueue);
}
if (ImGui::MenuItem("Copy", "Ctrl+C")) {
EditActions::copy(editorState, notificationsQueue);
}
if (ImGui::MenuItem("Paste", "Ctrl+V")) {
EditActions::paste(editorState, notificationsQueue);
}
if (ImGui::MenuItem("Delete", "Delete")) {
EditActions::delete_(editorState, notificationsQueue);
}
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("Chart",editorState.has_value())) { if (ImGui::BeginMenu("Chart",editorState.has_value())) {