diff --git a/src/app/commands/cmd_play_animation.cpp b/src/app/commands/cmd_play_animation.cpp index b71b969b9..b065ffc0e 100644 --- a/src/app/commands/cmd_play_animation.cpp +++ b/src/app/commands/cmd_play_animation.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 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 @@ -20,8 +20,6 @@ #include "config.h" #endif -#include - #include "ui/ui.h" #include "app/app.h" @@ -44,6 +42,126 @@ namespace app { +// TODO merge this with MiniEditor logic and create a new Editor state + +using namespace ui; + +class PlayAniWindow : public Window { +public: + PlayAniWindow(Context* context, Editor* editor) + : Window(DesktopWindow) + , m_editor(editor) + , m_oldFrame(editor->frame()) + , m_oldFlags(m_editor->editorFlags()) + , m_doc(editor->document()) + , m_docSettings(context->settings()->getDocumentSettings(m_doc)) + , m_oldOnionskinState(m_docSettings->getUseOnionskin()) + , m_playTimer(10) + { + m_editor->setEditorFlags(Editor::kNoneFlag); + + // Desactivate the onionskin + m_docSettings->setUseOnionskin(false); + + // Clear extras (e.g. pen preview) + m_doc->destroyExtraCel(); + + setFocusStop(true); // To receive keyboard messages + + m_curFrameTick = ji_clock; + m_pingPongForward = true; + m_nextFrameTime = editor->sprite()->getFrameDuration(editor->frame()); + + m_playTimer.Tick.connect(&PlayAniWindow::onPlaybackTick, this); + m_playTimer.start(); + } + +protected: + void onPlaybackTick() { + if (m_nextFrameTime >= 0) { + m_nextFrameTime -= (ji_clock - m_curFrameTick); + + while (m_nextFrameTime <= 0) { + FrameNumber frame = calculate_next_frame( + m_editor->sprite(), + m_editor->frame(), + m_docSettings, + m_pingPongForward); + + m_editor->setFrame(frame); + m_nextFrameTime += m_editor->sprite()->getFrameDuration(frame); + invalidate(); + } + + m_curFrameTick = ji_clock; + } + } + + virtual bool onProcessMessage(Message* msg) OVERRIDE { + switch (msg->type()) { + + case kOpenMessage: + jmouse_set_cursor(kNoCursor); + break; + + case kCloseMessage: + // Restore onionskin flag + m_docSettings->setUseOnionskin(m_oldOnionskinState); + + // Restore editor + m_editor->setFrame(m_oldFrame); + m_editor->setEditorFlags(m_oldFlags); + break; + + case kMouseUpMessage: { + closeWindow(this); + break; + } + + case kKeyDownMessage: { + KeyMessage* keyMsg = static_cast(msg); + + closeWindow(this); + + return true; + } + + case kSetCursorMessage: + jmouse_set_cursor(kNoCursor); + return true; + } + + return Window::onProcessMessage(msg); + } + + virtual void onPaint(PaintEvent& ev) OVERRIDE { + Graphics* g = ev.getGraphics(); + g->fillRect(gfx::rgba(0, 0, 0), getClientBounds()); + + Graphics subG(g->getInternalSurface(), + m_editor->getBounds().x + g->getInternalDeltaY(), + m_editor->getBounds().y + g->getInternalDeltaY()); + + m_editor->drawSpriteUnclippedRect(&subG, + gfx::Rect(0, 0, + m_editor->sprite()->width(), + m_editor->sprite()->height())); + } + +private: + Editor* m_editor; + FrameNumber m_oldFrame; + Editor::EditorFlags m_oldFlags; + Document* m_doc; + IDocumentSettings* m_docSettings; + bool m_oldOnionskinState; + bool m_pingPongForward; + + int m_nextFrameTime; + int m_curFrameTick; + ui::Timer m_playTimer; +}; + class PlayAnimationCommand : public Command { public: PlayAnimationCommand(); @@ -54,15 +172,6 @@ protected: void onExecute(Context* context); }; -static int speed_timer; - -static void speed_timer_callback() -{ - speed_timer++; -} - -END_OF_STATIC_FUNCTION(speed_timer_callback); - PlayAnimationCommand::PlayAnimationCommand() : Command("PlayAnimation", "Play Animation", @@ -78,108 +187,27 @@ bool PlayAnimationCommand::onEnabled(Context* context) void PlayAnimationCommand::onExecute(Context* context) { + // Do not play one-frame images + { + ContextReader writer(context); + Sprite* sprite(writer.sprite()); + if (!sprite || sprite->totalFrames() < 2) + return; + } + + // Hide mini editor MiniEditorWindow* miniEditor = App::instance()->getMainWindow()->getMiniEditor(); - bool visibleMiniEditor = (miniEditor ? miniEditor->isVisible(): false); - ContextWriter writer(context); - Document* document(writer.document()); - Sprite* sprite(writer.sprite()); - int msecs; - bool done = false; - IDocumentSettings* docSettings = context->settings()->getDocumentSettings(document); - bool onionskin_state = docSettings->getUseOnionskin(); - Palette *oldpal, *newpal; - bool pingPongForward = true; - - if (sprite->totalFrames() < 2) - return; - - if (visibleMiniEditor) - miniEditor->closeWindow(NULL); - - // desactivate the onionskin - docSettings->setUseOnionskin(false); - - ui::jmouse_hide(); - - FrameNumber oldFrame = current_editor->frame(); - - LOCK_VARIABLE(speed_timer); - LOCK_FUNCTION(speed_timer_callback); - - clear_keybuf(); - - // Clear all the screen - clear_bitmap(ui::ji_screen); - - // Clear extras (e.g. pen preview) - document->destroyExtraCel(); - - // Do animation - oldpal = NULL; - speed_timer = 0; - while (!done) { - msecs = sprite->getFrameDuration(current_editor->frame()); - install_int_ex(speed_timer_callback, MSEC_TO_TIMER(msecs)); - - newpal = sprite->getPalette(current_editor->frame()); - if (oldpal != newpal) { - PALETTE rgbpal; - raster::convert_palette_to_allegro(newpal, rgbpal); - set_palette(rgbpal); - oldpal = newpal; - } - - current_editor->drawSpriteClipped - (gfx::Region(gfx::Rect(0, 0, sprite->width(), sprite->height()))); - - ui::dirty_display_flag = true; - - do { - poll_mouse(); - poll_keyboard(); - if (keypressed() || mouse_b) - done = true; - gui_feedback(); - } while (!done && (speed_timer <= 0)); - - if (!done) { - current_editor->setFrame( - calculate_next_frame( - sprite, - current_editor->frame(), - docSettings, - pingPongForward)); - - speed_timer--; - } - gui_feedback(); + bool enabled = (miniEditor ? miniEditor->isMiniEditorEnabled(): false); + if (enabled) { + miniEditor->setVisible(false); + miniEditor->setMiniEditorEnabled(false); } - // Restore onionskin flag - docSettings->setUseOnionskin(onionskin_state); + PlayAniWindow window(context, current_editor); + window.openWindowInForeground(); - // If right-click or ESC - if (mouse_b == 2 || (keypressed() && (readkey()>>8) == KEY_ESC)) { - // Return to the old frame position - current_editor->setFrame(oldFrame); - } - - // Refresh all - newpal = sprite->getPalette(current_editor->frame()); - set_current_palette(newpal, true); - ui::Manager::getDefault()->invalidate(); - gui_feedback(); - - while (mouse_b) - poll_mouse(); - - clear_keybuf(); - remove_int(speed_timer_callback); - - ui::jmouse_show(); - - if (visibleMiniEditor) - miniEditor->openWindow(); + if (enabled) + miniEditor->setMiniEditorEnabled(enabled); } Command* CommandFactory::createPlayAnimationCommand() diff --git a/src/app/commands/cmd_undo.cpp b/src/app/commands/cmd_undo.cpp index 92f962d4d..8bc310515 100644 --- a/src/app/commands/cmd_undo.cpp +++ b/src/app/commands/cmd_undo.cpp @@ -93,8 +93,8 @@ void UndoCommand::onExecute(Context* context) // Draw the current layer/frame (which is not undone yet) so the // user can see the doUndo/doRedo effect. - current_editor->drawSpriteClipped - (gfx::Region(gfx::Rect(0, 0, sprite->width(), sprite->height()))); + current_editor->drawSpriteClipped( + gfx::Region(gfx::Rect(0, 0, sprite->width(), sprite->height()))); ui::dirty_display_flag = true; gui_feedback(); diff --git a/src/app/ui/document_view.cpp b/src/app/ui/document_view.cpp index f690ddcb7..1c2c12f60 100644 --- a/src/app/ui/document_view.cpp +++ b/src/app/ui/document_view.cpp @@ -136,7 +136,7 @@ DocumentView::DocumentView(Document* document, Type type) EditorView::AlwaysSelected)) , m_editor(type == Normal ? new AppEditor(document): - new Editor(document, Editor::kNoneFlag)) // Don't show grid/mask in mini preview + new Editor(document, Editor::kShowOutside)) // Don't show grid/mask in mini preview { addChild(m_view); diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index 763575738..0280edadd 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -392,7 +392,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, in if (rendered) { // Pre-render decorator. - if (m_decorator) { + if ((m_flags & kShowDecorators) && m_decorator) { EditorPreRenderImpl preRender(this, rendered, Point(-source_x, -source_y), m_zoom); m_decorator->preRenderDecorator(&preRender); @@ -457,41 +457,39 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc) // Fill the outside (parts of the editor that aren't covered by the // sprite). SkinTheme* theme = static_cast(this->getTheme()); - g->fillRegion(theme->getColor(ThemeColor::EditorFace), outside); + if (m_flags & kShowOutside) { + g->fillRegion(theme->getColor(ThemeColor::EditorFace), outside); + } // Draw the pixel grid - if (docSettings->getPixelGridVisible()) { - if (m_zoom > 1) - drawGrid(g, enclosingRect, Rect(0, 0, 1, 1), docSettings->getPixelGridColor()); + if ((m_zoom > 1) && docSettings->getPixelGridVisible()) { + drawGrid(g, enclosingRect, Rect(0, 0, 1, 1), docSettings->getPixelGridColor()); } // Draw the grid if (docSettings->getGridVisible()) drawGrid(g, enclosingRect, docSettings->getGridBounds(), docSettings->getGridColor()); - // Draw the borders that enclose the sprite. - enclosingRect.enlarge(1); - g->drawRect(theme->getColor(ThemeColor::EditorSpriteBorder), enclosingRect); - g->drawHLine( - theme->getColor(ThemeColor::EditorSpriteBottomBorder), - enclosingRect.x, enclosingRect.y+enclosingRect.h, enclosingRect.w); + if (m_flags & kShowOutside) { + // Draw the borders that enclose the sprite. + enclosingRect.enlarge(1); + g->drawRect(theme->getColor(ThemeColor::EditorSpriteBorder), enclosingRect); + g->drawHLine( + theme->getColor(ThemeColor::EditorSpriteBottomBorder), + enclosingRect.x, enclosingRect.y+enclosingRect.h, enclosingRect.w); + } // Draw the mask if (m_document->getBoundariesSegments()) drawMask(g); // Post-render decorator. - if (m_decorator) { + if ((m_flags & kShowDecorators) && m_decorator) { EditorPostRenderImpl postRender(this); m_decorator->postRenderDecorator(&postRender); } } -void Editor::drawSpriteUnclippedRect(const gfx::Rect& rc) -{ - drawSpriteUnclippedRect(getGraphics(getClientBounds()), rc); -} - void Editor::drawSpriteClipped(const gfx::Region& updateRegion) { Region region; @@ -507,7 +505,7 @@ void Editor::drawSpriteClipped(const gfx::Region& updateRegion) if (clip) { for (Region::const_iterator it2=updateRegion.begin(), end2=updateRegion.end(); it2 != end2; ++it2) { - drawSpriteUnclippedRect(*it2); + drawSpriteUnclippedRect(getGraphics(getClientBounds()), *it2); } } } @@ -522,7 +520,7 @@ void Editor::drawSpriteClipped(const gfx::Region& updateRegion) */ void Editor::drawMask(Graphics* g) { - if ((m_flags & kShowMaskFlag) == 0) + if ((m_flags & kShowMask) == 0) return; int x1, y1, x2, y2; @@ -576,7 +574,7 @@ void Editor::drawMask(Graphics* g) void Editor::drawMaskSafe() { - if ((m_flags & kShowMaskFlag) == 0) + if ((m_flags & kShowMask) == 0) return; if (isVisible() && @@ -612,7 +610,7 @@ void Editor::drawMaskSafe() void Editor::drawGrid(Graphics* g, const gfx::Rect& spriteBounds, const Rect& gridBounds, const app::Color& color) { - if ((m_flags & kShowGridFlag) == 0) + if ((m_flags & kShowGrid) == 0) return; // Copy the grid bounds diff --git a/src/app/ui/editor/editor.h b/src/app/ui/editor/editor.h index 9a1d7a47f..ba7d5ba2a 100644 --- a/src/app/ui/editor/editor.h +++ b/src/app/ui/editor/editor.h @@ -69,10 +69,13 @@ namespace app { enum EditorFlags { kNoneFlag = 0, - kShowGridFlag = 1, - kShowMaskFlag = 2, + kShowGrid = 1, + kShowMask = 2, kShowOnionskin = 4, - kDefaultEditorFlags = kShowGridFlag | kShowMaskFlag | kShowOnionskin, + kShowOutside = 8, + kShowDecorators = 16, + kDefaultEditorFlags = (kShowGrid | kShowMask | + kShowOnionskin | kShowOutside | kShowDecorators), }; enum ZoomBehavior { @@ -102,6 +105,7 @@ namespace app { void setDecorator(EditorDecorator* decorator) { m_decorator = decorator; } EditorFlags editorFlags() const { return m_flags; } + void setEditorFlags(EditorFlags flags) { m_flags = flags; } Document* document() { return m_document; } Sprite* sprite() { return m_sprite; } @@ -131,6 +135,7 @@ namespace app { // Draws the sprite taking care of the whole clipping region. void drawSpriteClipped(const gfx::Region& updateRegion); + void drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc); void flashCurrentLayer(); @@ -228,8 +233,6 @@ namespace app { // You should setup the clip of the screen before calling this // routine. void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy); - void drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc); - void drawSpriteUnclippedRect(const gfx::Rect& rc); // Stack of states. The top element in the stack is the current state (m_state). EditorStatesHistory m_statesHistory; diff --git a/src/app/ui/editor/standby_state.cpp b/src/app/ui/editor/standby_state.cpp index 1caa402ae..067a46817 100644 --- a/src/app/ui/editor/standby_state.cpp +++ b/src/app/ui/editor/standby_state.cpp @@ -660,7 +660,7 @@ void StandbyState::Decorator::postRenderDecorator(EditorPostRender* render) Editor* editor = render->getEditor(); // Draw transformation handles (if the mask is visible and isn't frozen). - if (editor->editorFlags() & Editor::kShowMaskFlag && + if (editor->editorFlags() & Editor::kShowMask && editor->document()->isMaskVisible() && !editor->document()->mask()->isFrozen()) { // And draw only when the user has a selection tool as active tool.