From 4f6c43edc54a0c95cd8a777daa39218cd8ac3d2c Mon Sep 17 00:00:00 2001 From: David Capello Date: Sun, 13 Nov 2011 20:40:19 -0300 Subject: [PATCH] Remove the editor's default state. Now the editor has a decorator property. + Removed Editor::setDefaultState. + Removed EditorState::getDecorator. + Added Editor::get/setDecorator. + Added EditorStatesHistory class and Editor::backToPreviousState() method. + Added EditorState::onBeforePopState event. --- src/CMakeLists.txt | 1 + src/commands/cmd_canvas_size.cpp | 4 +- src/commands/cmd_import_sprite_sheet.cpp | 10 ++-- src/widgets/editor/drawing_state.cpp | 4 +- src/widgets/editor/editor.cpp | 57 +++++++++++++------ src/widgets/editor/editor.h | 45 ++++++++------- src/widgets/editor/editor_state.h | 18 ++++-- src/widgets/editor/editor_states_history.cpp | 58 ++++++++++++++++++++ src/widgets/editor/editor_states_history.h | 52 ++++++++++++++++++ src/widgets/editor/moving_cel_state.cpp | 2 +- src/widgets/editor/moving_pixels_state.cpp | 6 +- src/widgets/editor/moving_pixels_state.h | 2 +- src/widgets/editor/scrolling_state.cpp | 2 +- src/widgets/editor/select_box_state.cpp | 15 +++-- src/widgets/editor/select_box_state.h | 3 +- 15 files changed, 213 insertions(+), 66 deletions(-) create mode 100644 src/widgets/editor/editor_states_history.cpp create mode 100644 src/widgets/editor/editor_states_history.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dbe1ce0f2..f8ccd7a3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -310,6 +310,7 @@ add_library(aseprite-library widgets/editor/drawing_state.cpp widgets/editor/editor.cpp widgets/editor/editor_listeners.cpp + widgets/editor/editor_states_history.cpp widgets/editor/editor_view.cpp widgets/editor/keys.cpp widgets/editor/moving_cel_state.cpp diff --git a/src/commands/cmd_canvas_size.cpp b/src/commands/cmd_canvas_size.cpp index 7478871f3..dad50a915 100644 --- a/src/commands/cmd_canvas_size.cpp +++ b/src/commands/cmd_canvas_size.cpp @@ -74,12 +74,12 @@ public: m_top ->EntryChange.connect(Bind(&CanvasSizeFrame::onEntriesChange, this)); m_bottom->EntryChange.connect(Bind(&CanvasSizeFrame::onEntriesChange, this)); - m_editor->setDefaultState(m_selectBoxState); + m_editor->setState(m_selectBoxState); } ~CanvasSizeFrame() { - m_editor->setDefaultState(EditorStatePtr(new StandbyState)); + m_editor->backToPreviousState(); } bool pressedOk() { return get_killer() == m_ok; } diff --git a/src/commands/cmd_import_sprite_sheet.cpp b/src/commands/cmd_import_sprite_sheet.cpp index 9c4f7806b..be2454245 100644 --- a/src/commands/cmd_import_sprite_sheet.cpp +++ b/src/commands/cmd_import_sprite_sheet.cpp @@ -275,16 +275,18 @@ private: if (m_document && !m_editor) { m_rect = gfx::Rect(0, 0, 16, 16); m_editor = current_editor; - m_editor->setDefaultState(EditorStatePtr(new SelectBoxState(this, m_rect, - SelectBoxState::PaintRulers | - SelectBoxState::PaintGrid))); + + EditorStatePtr newState(new SelectBoxState(this, m_rect, + SelectBoxState::PaintRulers | + SelectBoxState::PaintGrid)); + m_editor->setState(newState); } } void releaseEditor() { if (m_editor) { - m_editor->setDefaultState(EditorStatePtr(new StandbyState)); + m_editor->backToPreviousState(); m_editor = NULL; } } diff --git a/src/widgets/editor/drawing_state.cpp b/src/widgets/editor/drawing_state.cpp index ac299a3b9..ba24bb716 100644 --- a/src/widgets/editor/drawing_state.cpp +++ b/src/widgets/editor/drawing_state.cpp @@ -80,7 +80,7 @@ bool DrawingState::onMouseDown(Editor* editor, Message* msg) m_toolLoopManager = NULL; // Change to standby state - editor->setState(editor->getDefaultState()); + editor->backToPreviousState(); editor->releaseMouse(); } @@ -98,7 +98,7 @@ bool DrawingState::onMouseUp(Editor* editor, Message* msg) m_toolLoopManager->releaseLoop(pointer_from_msg(msg)); // Back to standby state. - editor->setState(editor->getDefaultState()); + editor->backToPreviousState(); editor->releaseMouse(); return true; } diff --git a/src/widgets/editor/editor.cpp b/src/widgets/editor/editor.cpp index 024b7c504..9aa33017a 100644 --- a/src/widgets/editor/editor.cpp +++ b/src/widgets/editor/editor.cpp @@ -117,10 +117,13 @@ private: Editor::Editor() : Widget(editor_type()) - , m_defaultState(EditorStatePtr(new StandbyState())) - , m_state(m_defaultState) + , m_state(new StandbyState()) + , m_decorator(NULL) , m_customizationDelegate(NULL) { + // Add the first state into the history. + m_statesHistory.push(m_state); + m_document = NULL; m_sprite = NULL; m_zoom = 0; @@ -171,22 +174,31 @@ int editor_type() return type; } -void Editor::setDefaultState(const EditorStatePtr& newState) -{ - m_defaultState = newState; - setState(newState); -} - -void Editor::setState(const EditorStatePtr& newState) +void Editor::setStateInternal(const EditorStatePtr& newState) { hideDrawingCursor(); // Fire before change state event, set the state, and fire after // change state event. - m_state->onBeforeChangeState(this); + bool keepInHistory = m_state->onBeforeChangeState(this); + + // Push a new state + if (newState) { + if (!keepInHistory) + m_statesHistory.pop(); + + m_statesHistory.push(newState); + m_state = newState; + } + // Go to previous state + else { + m_state->onBeforePopState(this); + + m_statesHistory.pop(); + m_state = m_statesHistory.top(); + } // Change to the new state. - m_state = newState; m_state->onAfterChangeState(this); // Redraw all the editors with the same document of this editor @@ -205,13 +217,24 @@ void Editor::setState(const EditorStatePtr& newState) updateStatusBar(); } +void Editor::setState(const EditorStatePtr& newState) +{ + setStateInternal(newState); +} + +void Editor::backToPreviousState() +{ + setStateInternal(EditorStatePtr(NULL)); +} + void Editor::setDocument(Document* document) { //if (this->hasMouse()) //jmanager_free_mouse(); // TODO Why is this here? Review this code - // Reset current state. - setDefaultState(EditorStatePtr(new StandbyState)); + // Reset all states (back to standby). + m_statesHistory.clear(); + setState(EditorStatePtr(new StandbyState)); if (m_cursor_thick) editor_clean_cursor(); @@ -404,10 +427,10 @@ void Editor::drawSprite(int x1, int y1, int x2, int y2) if (rendered) { // Pre-render decorator. - if (EditorDecorator* decorator = m_defaultState->getDecorator()) { + if (m_decorator) { EditorPreRenderImpl preRender(this, rendered, Point(-source_x, -source_y), m_zoom); - decorator->preRenderDecorator(&preRender); + m_decorator->preRenderDecorator(&preRender); } #ifdef DRAWSPRITE_DOUBLEBUFFERED @@ -446,9 +469,9 @@ void Editor::drawSprite(int x1, int y1, int x2, int y2) settings->getGridColor()); // Post-render decorator. - if (EditorDecorator* decorator = m_defaultState->getDecorator()) { + if (m_decorator) { EditorPostRenderImpl postRender(this); - decorator->postRenderDecorator(&postRender); + m_decorator->postRenderDecorator(&postRender); } } diff --git a/src/widgets/editor/editor.h b/src/widgets/editor/editor.h index 1c71ababb..c9c7500dd 100644 --- a/src/widgets/editor/editor.h +++ b/src/widgets/editor/editor.h @@ -21,13 +21,13 @@ #include "app/color.h" #include "base/compiler_specific.h" -#include "base/shared_ptr.h" #include "base/signal.h" #include "document.h" #include "gui/base.h" #include "gui/widget.h" #include "widgets/editor/editor_listeners.h" #include "widgets/editor/editor_state.h" +#include "widgets/editor/editor_states_history.h" #define MIN_ZOOM 0 #define MAX_ZOOM 5 @@ -42,25 +42,26 @@ namespace tools { class Tool; } -typedef SharedPtr EditorStatePtr; - class Editor : public Widget { public: - // in editor.c - Editor(); ~Editor(); - EditorStatePtr getDefaultState() { return m_defaultState; } + // Returns the current state. EditorStatePtr getState() { return m_state; } - // Changes the state of the editor and uses it as the default one. - void setDefaultState(const EditorStatePtr& newState); - // Changes the state of the editor. void setState(const EditorStatePtr& newState); + // Backs to previous state. + void backToPreviousState(); + + // Gets/sets the current decorator. The decorator is not owned by + // the Editor, so it must be deleted by the caller. + EditorDecorator* getDecorator() { return m_decorator; } + void setDecorator(EditorDecorator* decorator) { m_decorator = decorator; } + Document* getDocument() { return m_document; } void setDocument(Document* document); @@ -145,15 +146,6 @@ public: static void editor_cursor_init(); static void editor_cursor_exit(); -private: - void editor_update_quicktool(); - void editor_draw_cursor(int x, int y, bool refresh = true); - void editor_move_cursor(int x, int y, bool refresh = true); - void editor_clean_cursor(bool refresh = true); - bool editor_cursor_is_subpixel(); - -public: - // click.c enum { @@ -180,6 +172,13 @@ protected: } private: + void setStateInternal(const EditorStatePtr& newState); + void editor_update_quicktool(); + void editor_draw_cursor(int x, int y, bool refresh = true); + void editor_move_cursor(int x, int y, bool refresh = true); + void editor_clean_cursor(bool refresh = true); + bool editor_cursor_is_subpixel(); + void drawGrid(const gfx::Rect& gridBounds, const Color& color); void editor_request_size(int *w, int *h); @@ -189,15 +188,15 @@ private: int sprite_x, int sprite_y, int color, void (*pixel)(BITMAP *bmp, int x, int y, int color)); - // Default state when the editor is in standby (generally - // StandbyState). Transitory states should back to the default - // state (e.g. ScrollingState returns to the default state when the - // mouse button is released). - EditorStatePtr m_defaultState; + // Stack of states. The top element in the stack is the current state (m_state). + EditorStatesHistory m_statesHistory; // Current editor state (it can be shared between several editors to // the same document). This member cannot be NULL. EditorStatePtr m_state; + + // Current decorator (to draw extra UI elements). + EditorDecorator* m_decorator; Document* m_document; // Active document in the editor Sprite* m_sprite; // Active sprite in the editor diff --git a/src/widgets/editor/editor_state.h b/src/widgets/editor/editor_state.h index ec1a7a248..13188511e 100644 --- a/src/widgets/editor/editor_state.h +++ b/src/widgets/editor/editor_state.h @@ -20,6 +20,7 @@ #define WIDGETS_EDITOR_EDITOR_STATE_H_INCLUDED #include "base/disable_copying.h" +#include "base/shared_ptr.h" class Editor; class EditorDecorator; @@ -36,14 +37,20 @@ public: EditorState() { } virtual ~EditorState() { } - // Called just before this state is deleted and replaced by a new - // state in the Editor::setState() method. - virtual void onBeforeChangeState(Editor* editor) { } + // Called just before this state is replaced by a new state in the + // Editor::setState() method. Returns true if this state should be + // kept in the EditorStatesHistory. + virtual bool onBeforeChangeState(Editor* editor) { return true; } // Called when this instance is set as the new Editor's state when // Editor::setState() method is used. virtual void onAfterChangeState(Editor* editor) { } + // Called just before the state will be removed from the + // EditorStatesHistory. This event is useful to remove the + // decorator from the editor. + virtual void onBeforePopState(Editor* editor) { } + // Called when the current tool in the tool bar changes. It is // useful for states which depends on the selected current tool (as // MovingPixelsState which drops the pixels in case the user selects @@ -80,11 +87,10 @@ public: // drawing cursor. virtual bool requirePenPreview() { return false; } - // Called after the sprite is painted. - virtual EditorDecorator* getDecorator() { return NULL; } - private: DISABLE_COPYING(EditorState); }; +typedef SharedPtr EditorStatePtr; + #endif // WIDGETS_EDITOR_EDITOR_STATE_H_INCLUDED diff --git a/src/widgets/editor/editor_states_history.cpp b/src/widgets/editor/editor_states_history.cpp new file mode 100644 index 000000000..f701386cf --- /dev/null +++ b/src/widgets/editor/editor_states_history.cpp @@ -0,0 +1,58 @@ +/* ASE - Allegro Sprite Editor + * Copyright (C) 2001-2011 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "widgets/editor/editor_states_history.h" + +EditorStatesHistory::EditorStatesHistory() +{ +} + +EditorStatesHistory::~EditorStatesHistory() +{ + clear(); +} + +EditorStatePtr EditorStatesHistory::top() +{ + return (!m_states.empty() ? m_states.back(): EditorStatePtr(NULL)); +} + +void EditorStatesHistory::push(const EditorStatePtr& state) +{ + ASSERT(state != NULL); + m_states.push_back(state); +} + +void EditorStatesHistory::pop() +{ + ASSERT(!m_states.empty()); + m_states.pop_back(); +} + +void EditorStatesHistory::clear() +{ + // Free shared pointers in reverse order + std::vector::reverse_iterator it = m_states.rbegin(); + std::vector::reverse_iterator end = m_states.rend(); + for (; it != end; ++it) + (*it).reset(); + + m_states.clear(); +} diff --git a/src/widgets/editor/editor_states_history.h b/src/widgets/editor/editor_states_history.h new file mode 100644 index 000000000..8ad318be3 --- /dev/null +++ b/src/widgets/editor/editor_states_history.h @@ -0,0 +1,52 @@ +/* ASE - Allegro Sprite Editor + * Copyright (C) 2001-2011 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef WIDGETS_EDITOR_STATES_HISTORY_H_INCLUDED +#define WIDGETS_EDITOR_STATES_HISTORY_H_INCLUDED + +#include "widgets/editor/editor_state.h" + +#include + +// Stack of states in the editor. The top state is the current state +// of the editor. +class EditorStatesHistory +{ +public: + EditorStatesHistory(); + ~EditorStatesHistory(); + + // Gets the current state. + EditorStatePtr top(); + + // Adds a new state in the history. + void push(const EditorStatePtr& state); + + // Removes a state from the history (you should keep a reference of + // the state with top() if you want to keep it in memory). + void pop(); + + // Deletes all the history. + void clear(); + +private: + // Stack of states (the back of the vector is the top of the stack). + std::vector m_states; +}; + +#endif diff --git a/src/widgets/editor/moving_cel_state.cpp b/src/widgets/editor/moving_cel_state.cpp index 6969ed154..f4ffcfc50 100644 --- a/src/widgets/editor/moving_cel_state.cpp +++ b/src/widgets/editor/moving_cel_state.cpp @@ -102,7 +102,7 @@ bool MovingCelState::onMouseUp(Editor* editor, Message* msg) document->generateMaskBoundaries(); } - editor->setState(editor->getDefaultState()); + editor->backToPreviousState(); editor->releaseMouse(); return true; } diff --git a/src/widgets/editor/moving_pixels_state.cpp b/src/widgets/editor/moving_pixels_state.cpp index a1c23681d..ea8febba4 100644 --- a/src/widgets/editor/moving_pixels_state.cpp +++ b/src/widgets/editor/moving_pixels_state.cpp @@ -80,7 +80,7 @@ MovingPixelsState::~MovingPixelsState() delete m_pixelsMovement; } -void MovingPixelsState::onBeforeChangeState(Editor* editor) +bool MovingPixelsState::onBeforeChangeState(Editor* editor) { ASSERT(m_pixelsMovement != NULL); @@ -96,6 +96,7 @@ void MovingPixelsState::onBeforeChangeState(Editor* editor) editor->releaseMouse(); app_get_statusbar()->hideMovePixelsOptions(); + return false; // Don't keep this state in history } void MovingPixelsState::onCurrentToolChange(Editor* editor) @@ -274,6 +275,5 @@ void MovingPixelsState::dropPixels(Editor* editor) { // Just change to default state (StandbyState generally). We'll // receive an onBeforeChangeState event after this call. - editor->setState(editor->getDefaultState()); + editor->backToPreviousState(); } - diff --git a/src/widgets/editor/moving_pixels_state.h b/src/widgets/editor/moving_pixels_state.h index 5e514b7da..affa404f3 100644 --- a/src/widgets/editor/moving_pixels_state.h +++ b/src/widgets/editor/moving_pixels_state.h @@ -33,7 +33,7 @@ public: MovingPixelsState(Editor* editor, Message* msg, Image* imge, int x, int y, int opacity); virtual ~MovingPixelsState(); - virtual void onBeforeChangeState(Editor* editor) OVERRIDE; + virtual bool onBeforeChangeState(Editor* editor) OVERRIDE; virtual void onCurrentToolChange(Editor* editor) OVERRIDE; virtual bool onMouseDown(Editor* editor, Message* msg) OVERRIDE; virtual bool onMouseUp(Editor* editor, Message* msg) OVERRIDE; diff --git a/src/widgets/editor/scrolling_state.cpp b/src/widgets/editor/scrolling_state.cpp index 921b8f923..750124f2f 100644 --- a/src/widgets/editor/scrolling_state.cpp +++ b/src/widgets/editor/scrolling_state.cpp @@ -45,7 +45,7 @@ bool ScrollingState::onMouseDown(Editor* editor, Message* msg) bool ScrollingState::onMouseUp(Editor* editor, Message* msg) { - editor->setState(editor->getDefaultState()); + editor->backToPreviousState(); editor->releaseMouse(); return true; } diff --git a/src/widgets/editor/select_box_state.cpp b/src/widgets/editor/select_box_state.cpp index 0fcad9130..4733e196c 100644 --- a/src/widgets/editor/select_box_state.cpp +++ b/src/widgets/editor/select_box_state.cpp @@ -56,6 +56,16 @@ void SelectBoxState::setBoxBounds(const gfx::Rect& box) m_rulers[V2] = Ruler(Ruler::Vertical, box.x+box.w); } +void SelectBoxState::onAfterChangeState(Editor* editor) +{ + editor->setDecorator(this); +} + +void SelectBoxState::onBeforePopState(Editor* editor) +{ + editor->setDecorator(NULL); +} + bool SelectBoxState::onMouseDown(Editor* editor, Message* msg) { if (msg->mouse.left || msg->mouse.right) { @@ -135,11 +145,6 @@ bool SelectBoxState::onSetCursor(Editor* editor) return false; } -EditorDecorator* SelectBoxState::getDecorator() -{ - return this; -} - void SelectBoxState::preRenderDecorator(EditorPreRender* render) { // Without black shadow? diff --git a/src/widgets/editor/select_box_state.h b/src/widgets/editor/select_box_state.h index 82f7d13cc..262f9b2c0 100644 --- a/src/widgets/editor/select_box_state.h +++ b/src/widgets/editor/select_box_state.h @@ -53,11 +53,12 @@ public: void setBoxBounds(const gfx::Rect& rc); // EditorState overrides + virtual void onAfterChangeState(Editor* editor) OVERRIDE; + virtual void onBeforePopState(Editor* editor) OVERRIDE; virtual bool onMouseDown(Editor* editor, Message* msg) OVERRIDE; virtual bool onMouseUp(Editor* editor, Message* msg) OVERRIDE; virtual bool onMouseMove(Editor* editor, Message* msg) OVERRIDE; virtual bool onSetCursor(Editor* editor) OVERRIDE; - virtual EditorDecorator* getDecorator() OVERRIDE; // Returns false as it overrides default standby state behavior & // look. This state uses normal arrow cursors.