diff --git a/data/gui.xml b/data/gui.xml
index b464d5893..59f71b2fe 100644
--- a/data/gui.xml
+++ b/data/gui.xml
@@ -11,6 +11,7 @@
+
@@ -591,6 +592,7 @@
+
diff --git a/data/strings/en.ini b/data/strings/en.ini
index 879e43775..7deddd890 100644
--- a/data/strings/en.ini
+++ b/data/strings/en.ini
@@ -372,6 +372,7 @@ RemoveFrame = Remove Frame
RemoveFrameTag = Remove Frame Tag
RemoveLayer = Remove Layer
RemoveSlice = Remove Slice
+ReopenClosedFile = Reopen Closed File
RepeatLastExport = Repeat Last Export
ReplaceColor = Replace Color
ReselectMask = Reselect Mask
@@ -691,6 +692,7 @@ file = &File
file_new = &New...
file_open = &Open...
file_open_recent = Open &Recent
+file_reopen_closed = Reopen Close&d File
file_save = &Save
file_save_as = Save &As...
file_export = Expor&t...
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 31a562d46..227b780b9 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -264,6 +264,7 @@ if(ENABLE_UI)
commands/cmd_remove_frame.cpp
commands/cmd_remove_frame_tag.cpp
commands/cmd_remove_slice.cpp
+ commands/cmd_reopen_closed_file.cpp
commands/cmd_repeat_last_export.cpp
commands/cmd_reselect_mask.cpp
commands/cmd_reverse_frames.cpp
diff --git a/src/app/commands/cmd_reopen_closed_file.cpp b/src/app/commands/cmd_reopen_closed_file.cpp
new file mode 100644
index 000000000..f90b24022
--- /dev/null
+++ b/src/app/commands/cmd_reopen_closed_file.cpp
@@ -0,0 +1,57 @@
+// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
+//
+// This program is distributed under the terms of
+// the End-User License Agreement for Aseprite.
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "app/app.h"
+#include "app/commands/command.h"
+#include "app/commands/commands.h"
+#include "app/doc.h"
+#include "app/ui_context.h"
+
+#include
+
+namespace app {
+
+class ReopenClosedFileCommand : public Command {
+public:
+ ReopenClosedFileCommand();
+protected:
+ bool onEnabled(Context* context) override;
+ void onExecute(Context* context) override;
+};
+
+ReopenClosedFileCommand::ReopenClosedFileCommand()
+ : Command(CommandId::ReopenClosedFile(), CmdUIOnlyFlag)
+{
+}
+
+bool ReopenClosedFileCommand::onEnabled(Context* ctx)
+{
+ if (auto uiCtx = dynamic_cast(ctx)) {
+ const auto& docs = uiCtx->closedDocs();
+ return (!docs.empty());
+ }
+ return false;
+}
+
+void ReopenClosedFileCommand::onExecute(Context* ctx)
+{
+ if (auto uiCtx = dynamic_cast(ctx)) {
+ const auto& docs = uiCtx->closedDocs();
+ if (!docs.empty())
+ uiCtx->reopenClosedDoc(docs.front());
+ }
+}
+
+Command* CommandFactory::createReopenClosedFileCommand()
+{
+ return new ReopenClosedFileCommand;
+}
+
+} // namespace app
diff --git a/src/app/commands/commands_list.h b/src/app/commands/commands_list.h
index fa2e438c2..40e3117ff 100644
--- a/src/app/commands/commands_list.h
+++ b/src/app/commands/commands_list.h
@@ -116,6 +116,7 @@ FOR_EACH_COMMAND(Refresh)
FOR_EACH_COMMAND(RemoveFrame)
FOR_EACH_COMMAND(RemoveFrameTag)
FOR_EACH_COMMAND(RemoveSlice)
+FOR_EACH_COMMAND(ReopenClosedFile)
FOR_EACH_COMMAND(RepeatLastExport)
FOR_EACH_COMMAND(ReplaceColor)
FOR_EACH_COMMAND(ReselectMask)
diff --git a/src/app/context.cpp b/src/app/context.cpp
index cce362fcf..322a47201 100644
--- a/src/app/context.cpp
+++ b/src/app/context.cpp
@@ -45,6 +45,11 @@ void Context::sendDocumentToTop(Doc* document)
documents().move(document, 0);
}
+void Context::closeDocument(Doc* doc)
+{
+ onCloseDocument(doc);
+}
+
Site Context::activeSite() const
{
Site site;
@@ -221,4 +226,11 @@ ActiveSiteHandler* Context::activeSiteHandler() const
return m_activeSiteHandler.get();
}
+void Context::onCloseDocument(Doc* doc)
+{
+ ASSERT(doc != nullptr);
+ ASSERT(doc->context() == nullptr);
+ delete doc;
+}
+
} // namespace app
diff --git a/src/app/context.h b/src/app/context.h
index a35caf929..0fe1f932a 100644
--- a/src/app/context.h
+++ b/src/app/context.h
@@ -77,7 +77,8 @@ namespace app {
bool checkFlags(uint32_t flags) const { return m_flags.check(flags); }
void updateFlags() { m_flags.update(this); }
- void sendDocumentToTop(Doc* document);
+ void sendDocumentToTop(Doc* doc);
+ void closeDocument(Doc* doc);
Site activeSite() const;
Doc* activeDocument() const;
@@ -110,6 +111,7 @@ namespace app {
virtual void onSetActiveDocument(Doc* doc);
virtual void onSetActiveLayer(doc::Layer* layer);
virtual void onSetActiveFrame(const doc::frame_t frame);
+ virtual void onCloseDocument(Doc* doc);
Doc* lastSelectedDoc() { return m_lastSelectedDoc; }
diff --git a/src/app/doc_access.h b/src/app/doc_access.h
index f361fb061..06e951616 100644
--- a/src/app/doc_access.h
+++ b/src/app/doc_access.h
@@ -1,4 +1,5 @@
// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@@ -181,7 +182,7 @@ namespace app {
}
void destroyDocument() {
- ASSERT(m_doc != NULL);
+ ASSERT(m_doc != nullptr);
m_doc->close();
Doc* doc = m_doc;
@@ -191,6 +192,18 @@ namespace app {
m_doc = nullptr;
}
+ void closeDocument() {
+ ASSERT(m_doc != nullptr);
+
+ Context* ctx = (Context*)m_doc->context();
+ m_doc->close();
+ Doc* doc = m_doc;
+ unlock();
+
+ ctx->closeDocument(doc);
+ m_doc = nullptr;
+ }
+
};
class WeakDocReader : public DocAccess {
diff --git a/src/app/ui/doc_view.cpp b/src/app/ui/doc_view.cpp
index 2d305fe65..52bfc9e85 100644
--- a/src/app/ui/doc_view.cpp
+++ b/src/app/ui/doc_view.cpp
@@ -330,7 +330,9 @@ bool DocView::onCloseView(Workspace* workspace, bool quitting)
->setStatusText(0, "Sprite '%s' closed.",
m_document->name().c_str());
- destroyer.destroyDocument();
+ // Just close the document (so we can reopen it with
+ // ReopenClosedFile command).
+ destroyer.closeDocument();
// At this point the view is already destroyed
return true;
diff --git a/src/app/ui_context.cpp b/src/app/ui_context.cpp
index 7655fc1f9..11e22468d 100644
--- a/src/app/ui_context.cpp
+++ b/src/app/ui_context.cpp
@@ -28,6 +28,8 @@
#include "base/mutex.h"
#include "doc/sprite.h"
+#include
+
namespace app {
UIContext* UIContext::m_instance = nullptr;
@@ -223,6 +225,17 @@ Editor* UIContext::activeEditor()
return NULL;
}
+void UIContext::reopenClosedDoc(Doc* doc)
+{
+ auto it = std::find(m_closedDocs.begin(), m_closedDocs.end(), doc);
+ ASSERT(it != m_closedDocs.end());
+ if (it != m_closedDocs.end())
+ m_closedDocs.erase(it);
+
+ // Put the document in the context again.
+ doc->setContext(this);
+}
+
void UIContext::onAddDocument(Doc* doc)
{
app::Context::onAddDocument(doc);
@@ -295,4 +308,11 @@ void UIContext::onGetActiveSite(Site* site) const
}
}
+void UIContext::onCloseDocument(Doc* doc)
+{
+ ASSERT(doc != nullptr);
+ ASSERT(doc->context() == nullptr);
+ m_closedDocs.insert(m_closedDocs.begin(), doc);
+}
+
} // namespace app
diff --git a/src/app/ui_context.h b/src/app/ui_context.h
index 99b4e1de2..e1ac0b0bc 100644
--- a/src/app/ui_context.h
+++ b/src/app/ui_context.h
@@ -12,6 +12,8 @@
#include "app/context.h"
#include "app/docs_observer.h"
+#include
+
namespace app {
class DocView;
class Editor;
@@ -42,6 +44,10 @@ namespace app {
// new one if it's necessary.
Editor* getEditorFor(Doc* document);
+ // Returns the list of closed docs in this session.
+ const std::vector& closedDocs() const { return m_closedDocs; }
+ void reopenClosedDoc(Doc* doc);
+
protected:
void onAddDocument(Doc* doc) override;
void onRemoveDocument(Doc* doc) override;
@@ -49,9 +55,12 @@ namespace app {
void onSetActiveDocument(Doc* doc) override;
void onSetActiveLayer(doc::Layer* layer) override;
void onSetActiveFrame(const doc::frame_t frame) override;
+ void onCloseDocument(Doc* doc) override;
private:
DocView* m_lastSelectedView;
+ std::vector m_closedDocs;
+
static UIContext* m_instance;
};