[aseprite] 133/308: Add "Play Once" option in "Play" button popup

Tobias Hansen thansen at moszumanska.debian.org
Tue Mar 8 02:45:01 UTC 2016


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository aseprite.

commit fcbb3640856919dfa66789342acd0bbe4b7b017a
Author: David Capello <davidcapello at gmail.com>
Date:   Fri Dec 18 18:51:30 2015 -0300

    Add "Play Once" option in "Play" button popup
---
 data/pref.xml                           |  4 +++
 src/app/commands/cmd_play_animation.cpp |  3 +-
 src/app/ui/ani_controls.cpp             |  3 +-
 src/app/ui/editor/editor.cpp            | 21 ++++++++++---
 src/app/ui/editor/editor.h              |  6 ++--
 src/app/ui/editor/play_state.cpp        | 52 ++++++++++++++++++++++++++++++---
 src/app/ui/editor/play_state.h          |  3 +-
 src/app/ui/preview_editor.cpp           | 46 +++++++++++++++++++++++------
 src/app/ui/preview_editor.h             |  8 ++++-
 9 files changed, 123 insertions(+), 23 deletions(-)

diff --git a/data/pref.xml b/data/pref.xml
index 1cd907d..c151c5b 100644
--- a/data/pref.xml
+++ b/data/pref.xml
@@ -89,6 +89,10 @@
       <option id="right_click_mode" type="RightClickMode" default="RightClickMode::PAINT_BGCOLOR" migrate="Options.RightClickMode" />
       <option id="auto_select_layer" type="bool" default="false" migrate="Options.AutoSelectLayer" />
       <option id="cursor_color" type="app::Color" default="app::Color::fromMask()" migrate="Tools.CursorColor" />
+      <option id="play_once" type="bool" default="false" />
+    </section>
+    <section id="preview" text="Preview">
+      <option id="play_once" type="bool" default="false" />
     </section>
     <section id="theme" text="Theme">
       <option id="selected" type="std::string" default=""default"" migrate="Skin.Selected" />
diff --git a/src/app/commands/cmd_play_animation.cpp b/src/app/commands/cmd_play_animation.cpp
index b5178cd..26b2f10 100644
--- a/src/app/commands/cmd_play_animation.cpp
+++ b/src/app/commands/cmd_play_animation.cpp
@@ -13,6 +13,7 @@
 #include "app/context.h"
 #include "app/context_access.h"
 #include "app/modules/editors.h"
+#include "app/pref/preferences.h"
 #include "app/ui/editor/editor.h"
 
 namespace app {
@@ -59,7 +60,7 @@ void PlayAnimationCommand::onExecute(Context* context)
   if (current_editor->isPlaying())
     current_editor->stop();
   else
-    current_editor->play();
+    current_editor->play(Preferences::instance().editor.playOnce());
 }
 
 Command* CommandFactory::createPlayAnimationCommand()
diff --git a/src/app/ui/ani_controls.cpp b/src/app/ui/ani_controls.cpp
index 826760a..c70282d 100644
--- a/src/app/ui/ani_controls.cpp
+++ b/src/app/ui/ani_controls.cpp
@@ -110,7 +110,8 @@ void AniControls::onRightClick(Item* item)
   ButtonSet::onRightClick(item);
 
   if (item == getItem(ACTION_PLAY) && current_editor)
-    current_editor->showAnimationSpeedMultiplierPopup(true);
+    current_editor->showAnimationSpeedMultiplierPopup(
+      Preferences::instance().editor.playOnce, true);
 }
 
 const char* AniControls::getCommandId(int index) const
diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp
index 5399a9c..d1eafbf 100644
--- a/src/app/ui/editor/editor.cpp
+++ b/src/app/ui/editor/editor.cpp
@@ -1594,14 +1594,14 @@ void Editor::notifyScrollChanged()
   m_observers.notifyScrollChanged(this);
 }
 
-void Editor::play()
+void Editor::play(bool playOnce)
 {
   ASSERT(m_state);
   if (!m_state)
     return;
 
   if (!dynamic_cast<PlayState*>(m_state.get()))
-    setState(EditorStatePtr(new PlayState));
+    setState(EditorStatePtr(new PlayState(playOnce)));
 }
 
 void Editor::stop()
@@ -1619,7 +1619,8 @@ bool Editor::isPlaying() const
   return (dynamic_cast<PlayState*>(m_state.get()) != nullptr);
 }
 
-void Editor::showAnimationSpeedMultiplierPopup(bool withStopBehaviorOptions)
+void Editor::showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
+                                               bool withStopBehaviorOptions)
 {
   double options[] = { 0.25, 0.5, 1.0, 1.5, 2.0, 3.0 };
   Menu menu;
@@ -1631,8 +1632,20 @@ void Editor::showAnimationSpeedMultiplierPopup(bool withStopBehaviorOptions)
     menu.addChild(item);
   }
 
+  menu.addChild(new MenuSeparator);
+
+  // Play once option
+  {
+    MenuItem* item = new MenuItem("Play Once");
+    item->Click.connect(
+      [&playOnce]() {
+        playOnce(!playOnce());
+      });
+    item->setSelected(playOnce());
+    menu.addChild(item);
+  }
+
   if (withStopBehaviorOptions) {
-    menu.addChild(new MenuSeparator);
     MenuItem* item = new MenuItem("Rewind on Stop");
     item->Click.connect(
       []() {
diff --git a/src/app/ui/editor/editor.h b/src/app/ui/editor/editor.h
index 90b7a9f..70efb2f 100644
--- a/src/app/ui/editor/editor.h
+++ b/src/app/ui/editor/editor.h
@@ -12,6 +12,7 @@
 #include "app/app_render.h"
 #include "app/color.h"
 #include "app/document.h"
+#include "app/pref/option.h"
 #include "app/tools/selection_mode.h"
 #include "app/ui/editor/brush_preview.h"
 #include "app/ui/editor/editor_observers.h"
@@ -194,12 +195,13 @@ namespace app {
     void notifyScrollChanged();
 
     // Animation control
-    void play();
+    void play(bool playOnce);
     void stop();
     bool isPlaying() const;
 
     // Shows a popup menu to change the editor animation speed.
-    void showAnimationSpeedMultiplierPopup(bool withStopBehaviorOptions);
+    void showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
+                                           bool withStopBehaviorOptions);
     double getAnimationSpeedMultiplier() const;
     void setAnimationSpeedMultiplier(double speed);
 
diff --git a/src/app/ui/editor/play_state.cpp b/src/app/ui/editor/play_state.cpp
index d2ad40f..242d32d 100644
--- a/src/app/ui/editor/play_state.cpp
+++ b/src/app/ui/editor/play_state.cpp
@@ -18,6 +18,7 @@
 #include "app/ui/editor/editor.h"
 #include "app/ui/editor/scrolling_state.h"
 #include "app/ui_context.h"
+#include "doc/frame_tag.h"
 #include "doc/handle_anidir.h"
 #include "ui/manager.h"
 #include "ui/message.h"
@@ -27,8 +28,9 @@ namespace app {
 
 using namespace ui;
 
-PlayState::PlayState()
+PlayState::PlayState(bool playOnce)
   : m_editor(nullptr)
+  , m_playOnce(playOnce)
   , m_toScroll(false)
   , m_playTimer(10)
   , m_nextFrameTime(-1)
@@ -51,6 +53,21 @@ void PlayState::onEnterState(Editor* editor)
     m_refFrame = editor->frame();
   }
 
+  // Go to the first frame of the animation or active frame tag
+  if (m_playOnce) {
+    frame_t frame = 0;
+
+    doc::FrameTag* tag = get_animation_tag(
+      m_editor->sprite(), m_refFrame);
+    if (tag) {
+      frame = (tag->aniDir() == AniDir::REVERSE ?
+               tag->toFrame():
+               tag->fromFrame());
+    }
+
+    m_editor->setFrame(frame);
+  }
+
   m_toScroll = false;
   m_nextFrameTime = getNextFrameTime();
   m_curFrameTick = ui::clock();
@@ -65,7 +82,7 @@ void PlayState::onEnterState(Editor* editor)
 EditorState::LeaveAction PlayState::onLeaveState(Editor* editor, EditorState* newState)
 {
   if (!m_toScroll) {
-    if (Preferences::instance().general.rewindOnStop())
+    if (m_playOnce || Preferences::instance().general.rewindOnStop())
       m_editor->setFrame(m_refFrame);
 
     // We don't stop the timer if we are going to the ScrollingState
@@ -135,8 +152,35 @@ void PlayState::onPlaybackTick()
   doc::FrameTag* tag = get_animation_tag(sprite, m_refFrame);
 
   while (m_nextFrameTime <= 0) {
-    doc::frame_t frame = calculate_next_frame(
-      sprite, m_editor->frame(), frame_t(1), tag,
+    doc::frame_t frame = m_editor->frame();
+
+    if (m_playOnce) {
+      bool atEnd = false;
+      if (tag) {
+        switch (tag->aniDir()) {
+          case AniDir::FORWARD:
+            atEnd = (frame == tag->toFrame());
+            break;
+          case AniDir::REVERSE:
+            atEnd = (frame == tag->fromFrame());
+            break;
+          case AniDir::PING_PONG:
+            atEnd = (!m_pingPongForward &&
+                     frame == tag->fromFrame());
+            break;
+        }
+      }
+      else {
+        atEnd = (frame == sprite->lastFrame());
+      }
+      if (atEnd) {
+        m_editor->stop();
+        break;
+      }
+    }
+
+    frame = calculate_next_frame(
+      sprite, frame, frame_t(1), tag,
       m_pingPongForward);
 
     m_editor->setFrame(frame);
diff --git a/src/app/ui/editor/play_state.h b/src/app/ui/editor/play_state.h
index 0f6e3b2..4ada6d9 100644
--- a/src/app/ui/editor/play_state.h
+++ b/src/app/ui/editor/play_state.h
@@ -20,7 +20,7 @@ namespace app {
 
   class PlayState : public StateWithWheelBehavior {
   public:
-    PlayState();
+    PlayState(bool playOnce);
 
     void onEnterState(Editor* editor) override;
     LeaveAction onLeaveState(Editor* editor, EditorState* newState) override;
@@ -39,6 +39,7 @@ namespace app {
     double getNextFrameTime();
 
     Editor* m_editor;
+    bool m_playOnce;
     bool m_toScroll;
     ui::Timer m_playTimer;
 
diff --git a/src/app/ui/preview_editor.cpp b/src/app/ui/preview_editor.cpp
index a017328..ee95b91 100644
--- a/src/app/ui/preview_editor.cpp
+++ b/src/app/ui/preview_editor.cpp
@@ -21,6 +21,7 @@
 #include "app/ui/editor/editor.h"
 #include "app/ui/editor/editor_view.h"
 #include "app/ui/editor/navigate_state.h"
+#include "app/ui/editor/play_state.h"
 #include "app/ui/skin/skin_button.h"
 #include "app/ui/skin/skin_theme.h"
 #include "app/ui/status_bar.h"
@@ -101,6 +102,11 @@ public:
 
   bool isPlaying() const { return m_isPlaying; }
 
+  void stop() {
+    m_isPlaying = false;
+    setupIcons();
+  }
+
   base::Signal0<void> Popup;
 
 private:
@@ -251,8 +257,7 @@ void PreviewEditorWindow::onClose(ui::CloseEvent& ev)
     // state. TODO abstract this event
     ToolBar::instance()->invalidate();
 
-    delete m_docView;
-    m_docView = NULL;
+    destroyDocView();
   }
 }
 
@@ -282,7 +287,7 @@ void PreviewEditorWindow::onPlayClicked()
 
   if (m_playButton->isPlaying()) {
     m_refFrame = miniEditor->frame();
-    miniEditor->play();
+    miniEditor->play(Preferences::instance().preview.playOnce());
   }
   else
     miniEditor->stop();
@@ -294,7 +299,8 @@ void PreviewEditorWindow::onPopupSpeed()
   if (!miniEditor || !miniEditor->document())
     return;
 
-  miniEditor->showAnimationSpeedMultiplierPopup(false);
+  miniEditor->showAnimationSpeedMultiplierPopup(
+    Preferences::instance().preview.playOnce, false);
   m_aniSpeed = miniEditor->getAnimationSpeedMultiplier();
 }
 
@@ -323,7 +329,8 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
 
   // Set the same location as in the given editor.
   if (!miniEditor || miniEditor->document() != document) {
-    delete m_docView;
+    destroyDocView();
+
     m_docView = new DocumentView(document, DocumentView::Preview);
     addChild(m_docView);
 
@@ -333,6 +340,7 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
     miniEditor->setFrame(editor->frame());
     miniEditor->setState(EditorStatePtr(new NavigateState));
     miniEditor->setAnimationSpeedMultiplier(m_aniSpeed);
+    miniEditor->addObserver(this);
     layout();
     center = true;
   }
@@ -356,7 +364,7 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
     if (!miniEditor->isPlaying())
       miniEditor->setFrame(m_refFrame = editor->frame());
 
-    miniEditor->play();
+    miniEditor->play(Preferences::instance().preview.playOnce());
   }
 }
 
@@ -366,13 +374,33 @@ void PreviewEditorWindow::uncheckCenterButton()
     m_centerButton->setSelected(false);
 }
 
-void PreviewEditorWindow::hideWindow()
+void PreviewEditorWindow::onStateChanged(Editor* editor)
 {
-  delete m_docView;
-  m_docView = NULL;
+  EditorStatePtr state = editor->getState();
+  PlayState* playState = (state ? dynamic_cast<PlayState*>(state.get()): nullptr);
+  if (!playState) {
+    // We have to switch the "play button" state to "play" because the
+    // editor animation has just stopped. This happens when we use
+    // "play once" option and the PlayState stops automatically.
+    m_playButton->stop();
+  }
+}
 
+void PreviewEditorWindow::hideWindow()
+{
+  destroyDocView();
   if (isVisible())
     closeWindow(NULL);
 }
 
+void PreviewEditorWindow::destroyDocView()
+{
+  if (m_docView) {
+    m_docView->getEditor()->removeObserver(this);
+
+    delete m_docView;
+    m_docView = nullptr;
+  }
+}
+
 } // namespace app
diff --git a/src/app/ui/preview_editor.h b/src/app/ui/preview_editor.h
index f61c369..57ff4f6 100644
--- a/src/app/ui/preview_editor.h
+++ b/src/app/ui/preview_editor.h
@@ -10,6 +10,7 @@
 #pragma once
 
 #include "app/ui/document_view.h"
+#include "app/ui/editor/editor_observer.h"
 #include "doc/frame.h"
 #include "ui/window.h"
 
@@ -17,7 +18,8 @@ namespace app {
   class MiniCenterButton;
   class MiniPlayButton;
 
-  class PreviewEditorWindow : public ui::Window {
+  class PreviewEditorWindow : public ui::Window
+                            , public EditorObserver {
   public:
     PreviewEditorWindow();
     ~PreviewEditorWindow();
@@ -30,6 +32,9 @@ namespace app {
 
     Editor* relatedEditor() const { return m_relatedEditor; }
 
+    // EditorObserver impl
+    void onStateChanged(Editor* editor) override;
+
   protected:
     bool onProcessMessage(ui::Message* msg) override;
     void onClose(ui::CloseEvent& ev) override;
@@ -40,6 +45,7 @@ namespace app {
     void onPlayClicked();
     void onPopupSpeed();
     void hideWindow();
+    void destroyDocView();
 
     bool m_isEnabled;
     DocumentView* m_docView;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git



More information about the Pkg-games-commits mailing list