aseprite/src/app/commands/cmd_play_animation.cpp
David Capello 58d302749c Use a FrameTag for the loop section (fix #557)
Changes:
* Paint FrameTags in Timeline with labels
* Add app::ui::FrameTagWindow
* Fix FrameTag::m_aniDir initialization
* Add warning for files that doesn't support frame tags
* Remove document preferences related to the active loop
2015-03-09 13:57:54 -03:00

205 lines
5.0 KiB
C++

// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ui/ui.h"
#include "app/app.h"
#include "app/commands/command.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/handle_anidir.h"
#include "app/loop_tag.h"
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/pref/preferences.h"
#include "app/settings/settings.h"
#include "app/ui/editor/editor.h"
#include "app/ui/main_window.h"
#include "app/ui/preview_editor.h"
#include "doc/image.h"
#include "doc/palette.h"
#include "doc/sprite.h"
namespace app {
// TODO merge this with PreviewEditor 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_docPref(App::instance()->preferences().document(m_doc))
, m_oldOnionskinState(m_docPref.onionskin.active())
, m_playTimer(10)
{
m_editor->setEditorFlags(Editor::kNoneFlag);
// Desactivate the onionskin
m_docPref.onionskin.active(false);
// Clear extras (e.g. pen preview)
m_doc->destroyExtraCel();
setFocusStop(true); // To receive keyboard messages
m_curFrameTick = ui::clock();
m_pingPongForward = true;
m_nextFrameTime = editor->sprite()->frameDuration(editor->frame());
m_playTimer.Tick.connect(&PlayAniWindow::onPlaybackTick, this);
m_playTimer.start();
}
protected:
void onPlaybackTick() {
if (m_nextFrameTime >= 0) {
m_nextFrameTime -= (ui::clock() - m_curFrameTick);
FrameTag* loopTag = get_loop_tag(m_editor->sprite());
while (m_nextFrameTime <= 0) {
frame_t frame = calculate_next_frame(
m_editor->sprite(),
m_editor->frame(), loopTag,
m_pingPongForward);
m_editor->setFrame(frame);
m_nextFrameTime += m_editor->sprite()->frameDuration(frame);
}
invalidate();
m_curFrameTick = ui::clock();
}
}
virtual bool onProcessMessage(Message* msg) override {
switch (msg->type()) {
case kOpenMessage:
ui::set_mouse_cursor(kNoCursor);
break;
case kCloseMessage:
// Restore onionskin flag
m_docPref.onionskin.active(m_oldOnionskinState);
// Restore editor
m_editor->setFrame(m_oldFrame);
m_editor->setEditorFlags(m_oldFlags);
break;
case kMouseUpMessage: {
closeWindow(this);
break;
}
case kKeyDownMessage: {
closeWindow(this);
return true;
}
case kSetCursorMessage:
ui::set_mouse_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;
frame_t m_oldFrame;
Editor::EditorFlags m_oldFlags;
Document* m_doc;
DocumentPreferences& m_docPref;
bool m_oldOnionskinState;
bool m_pingPongForward;
int m_nextFrameTime;
int m_curFrameTick;
ui::Timer m_playTimer;
};
class PlayAnimationCommand : public Command {
public:
PlayAnimationCommand();
Command* clone() const override { return new PlayAnimationCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
PlayAnimationCommand::PlayAnimationCommand()
: Command("PlayAnimation",
"Play Animation",
CmdUIOnlyFlag)
{
}
bool PlayAnimationCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
ContextFlags::HasActiveSprite);
}
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
PreviewEditorWindow* preview =
App::instance()->getMainWindow()->getPreviewEditor();
bool enabled = (preview ? preview->isPreviewEnabled(): false);
if (enabled)
preview->setPreviewEnabled(false);
PlayAniWindow window(context, current_editor);
window.openWindowInForeground();
if (enabled)
preview->setPreviewEnabled(enabled);
}
Command* CommandFactory::createPlayAnimationCommand()
{
return new PlayAnimationCommand;
}
} // namespace app