Show full animation length/tag length on status bar (fix #1528)

This commit is contained in:
David Capello 2017-07-28 16:44:21 -03:00
parent 835941a6d6
commit 744e40b4b7
8 changed files with 185 additions and 29 deletions

View File

@ -551,6 +551,7 @@ add_library(app-lib
util/pic_file.cpp
util/pixel_ratio.cpp
util/range_utils.cpp
util/readable_time.cpp
util/wrap_point.cpp
webserver.cpp
xml_document.cpp

View File

@ -47,6 +47,7 @@
#include "app/ui/timeline/timeline.h"
#include "app/ui_context.h"
#include "app/util/new_image_from_mask.h"
#include "app/util/readable_time.h"
#include "base/bind.h"
#include "base/pi.h"
#include "doc/layer.h"
@ -554,9 +555,10 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
if (sprite->totalFrames() > 1) {
sprintf(
buf+std::strlen(buf), " :frame: %d :clock: %d",
buf+std::strlen(buf), " :frame: %d :clock: %s/%s",
editor->frame()+editor->docPref().timeline.firstFrame(),
sprite->frameDuration(editor->frame()));
human_readable_time(sprite->frameDuration(editor->frame())).c_str(),
human_readable_time(sprite->totalAnimationDuration()).c_str());
}
if (editor->docPref().show.grid()) {

View File

@ -39,6 +39,7 @@
#include "app/ui_context.h"
#include "app/util/clipboard.h"
#include "app/util/layer_boundaries.h"
#include "app/util/readable_time.h"
#include "base/bind.h"
#include "base/convert_to.h"
#include "base/memory.h"
@ -245,6 +246,7 @@ Timeline::Timeline()
m_ctxConn = m_context->AfterCommandExecution.connect(
&Timeline::onAfterCommandExecution, this);
m_context->documents().add_observer(this);
m_context->add_observer(this);
setDoubleBuffered(true);
addChild(&m_aniControls);
@ -262,6 +264,7 @@ Timeline::~Timeline()
detachDocument();
m_context->documents().remove_observer(this);
m_context->remove_observer(this);
delete m_confPopup;
}
@ -1569,6 +1572,13 @@ void Timeline::onAfterCommandExecution(CommandExecutionEvent& ev)
invalidate();
}
void Timeline::onActiveSiteChange(const doc::Site& site)
{
if (hasMouse()) {
updateStatusBarForFrame(site.frame(), nullptr, site.cel());
}
}
void Timeline::onRemoveDocument(doc::Document* document)
{
if (document == m_document) {
@ -3118,7 +3128,7 @@ void Timeline::updateStatusBar(ui::Message* msg)
StatusBar* sb = StatusBar::instance();
if (m_state == STATE_MOVING_RANGE) {
if (m_state == STATE_MOVING_RANGE && msg) {
const char* verb = is_copy_key_pressed(msg) ? "Copy": "Move";
switch (m_range.type()) {
@ -3234,39 +3244,88 @@ void Timeline::updateStatusBar(ui::Message* msg)
break;
case PART_HEADER_FRAME:
if (validFrame(m_hot.frame)) {
sb->setStatusText(
0,
":frame: %d :clock: %d",
(int)m_hot.frame+docPref().timeline.firstFrame(),
m_sprite->frameDuration(m_hot.frame));
return;
}
break;
case PART_CEL:
if (layer) {
Cel* cel = (layer->isImage() ? layer->cel(m_hot.frame): NULL);
StatusBar::instance()->setStatusText(0,
"%s at frame %d"
#ifdef _DEBUG
" (Image %d)"
#endif
, cel ? "Cel": "Empty cel"
, (int)m_hot.frame+1
#ifdef _DEBUG
, (cel ? cel->image()->id(): 0)
#endif
);
return;
}
break;
case PART_FRAME_TAG: {
frame_t frame = m_frame;
if (validFrame(m_hot.frame))
frame = m_hot.frame;
updateStatusBarForFrame(
frame,
m_hot.getFrameTag(),
(layer ? layer->cel(frame) : nullptr));
return;
}
}
}
sb->clearText();
}
void Timeline::updateStatusBarForFrame(const frame_t frame,
const FrameTag* frameTag,
const Cel* cel)
{
if (!m_sprite)
return;
char buf[256] = { 0 };
frame_t base = docPref().timeline.firstFrame();
frame_t firstFrame = frame;
frame_t lastFrame = frame;
if (frameTag) {
firstFrame = frameTag->fromFrame();
lastFrame = frameTag->toFrame();
}
else if (m_range.enabled() &&
m_range.frames() > 1) {
firstFrame = m_range.firstFrame();
lastFrame = m_range.lastFrame();
}
std::sprintf(
buf+std::strlen(buf), ":frame: %d",
base+frame);
if (firstFrame != lastFrame) {
std::sprintf(
buf+std::strlen(buf), " [%d...%d]",
int(base+firstFrame),
int(base+lastFrame));
}
std::sprintf(
buf+std::strlen(buf), " :clock: %s",
human_readable_time(m_sprite->frameDuration(frame)).c_str());
if (firstFrame != lastFrame) {
std::sprintf(
buf+std::strlen(buf), " [%s]",
frameTag ?
human_readable_time(tagFramesDuration(frameTag)).c_str():
human_readable_time(selectedFramesDuration()).c_str());
}
if (m_sprite->totalFrames() > 1)
std::sprintf(
buf+std::strlen(buf), "/%s",
human_readable_time(m_sprite->totalAnimationDuration()).c_str());
if (cel) {
std::sprintf(
buf+std::strlen(buf), " Cel :pos: %d %d :size: %d %d",
cel->bounds().x, cel->bounds().y,
cel->bounds().w, cel->bounds().h);
if (cel->links() > 0) {
std::sprintf(
buf+std::strlen(buf), " Links %d",
int(cel->links()));
}
}
StatusBar::instance()
->setStatusText(0, buf);
}
void Timeline::showCel(layer_t layer, frame_t frame)
{
gfx::Point scroll = viewScroll();
@ -3841,4 +3900,29 @@ void Timeline::onCancel(Context* ctx)
invalidate();
}
int Timeline::tagFramesDuration(const FrameTag* frameTag) const
{
ASSERT(m_sprite);
ASSERT(frameTag);
int duration = 0;
for (frame_t f=frameTag->fromFrame();
f<frameTag->toFrame(); ++f) {
duration += m_sprite->frameDuration(f);
}
return duration;
}
int Timeline::selectedFramesDuration() const
{
ASSERT(m_sprite);
int duration = 0;
for (frame_t f=0; f<m_sprite->totalFrames(); ++f) {
if (isFrameActive(f))
duration += m_sprite->frameDuration(f);
}
return duration; // TODO cache this value
}
} // namespace app

View File

@ -54,6 +54,7 @@ namespace app {
class Timeline : public ui::Widget
, public ui::ScrollableViewDelegate
, public doc::ContextObserver
, public doc::DocumentsObserver
, public doc::DocumentObserver
, public app::EditorObserver
@ -138,6 +139,9 @@ namespace app {
// app::Context slots.
void onAfterCommandExecution(CommandExecutionEvent& ev);
// ContextObserver impl
void onActiveSiteChange(const doc::Site& site) override;
// DocumentsObserver impl.
void onRemoveDocument(doc::Document* document) override;
@ -288,6 +292,9 @@ namespace app {
bool isCelActive(const layer_t layerIdx, const frame_t frame) const;
bool isCelLooselyActive(const layer_t layerIdx, const frame_t frame) const;
void updateStatusBar(ui::Message* msg);
void updateStatusBarForFrame(const frame_t frame,
const FrameTag* frameTag,
const Cel* cel);
void updateDropRange(const gfx::Point& pt);
void clearClipboardRange();
void clearAndInvalidateRange();
@ -326,6 +333,9 @@ namespace app {
const bool updatePref);
double zoom() const;
int tagFramesDuration(const FrameTag* frameTag) const;
// Calculate the duration of the selected range of frames
int selectedFramesDuration() const;
ui::ScrollBar m_hbar;
ui::ScrollBar m_vbar;

View File

@ -0,0 +1,31 @@
// Aseprite
// Copyright (C) 2017 David Capello
//
// 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/util/readable_time.h"
#include <cstdio>
namespace app {
std::string human_readable_time(const int t)
{
char buf[32];
if (t < 900)
std::sprintf(buf, "%dms", t);
else if (t < 1000*59)
std::sprintf(buf, "%0.2fs", double(t) / 1000.0);
else if (t < 1000*60*59)
std::sprintf(buf, "%0.2fm", double(t) / 1000.0 / 60.0);
else
std::sprintf(buf, "%0.2fh", double(t) / 1000.0 / 60.0 / 60.0);
return buf;
}
} // namespace app

View File

@ -0,0 +1,19 @@
// Aseprite
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_UTIL_READABLE_TIME_H_INCLUDED
#define APP_UTIL_READABLE_TIME_H_INCLUDED
#pragma once
#include <string>
namespace app {
std::string human_readable_time(const int t);
} // namespace app
#endif

View File

@ -376,6 +376,14 @@ int Sprite::frameDuration(frame_t frame) const
return 0;
}
int Sprite::totalAnimationDuration() const
{
int duration = 0;
for (frame_t frame=0; frame<m_frames; ++frame)
duration += frameDuration(frame);
return duration; // TODO cache this value
}
void Sprite::setFrameDuration(frame_t frame, int msecs)
{
if (frame >= 0 && frame < m_frames)

View File

@ -123,6 +123,7 @@ namespace doc {
void setTotalFrames(frame_t frames);
int frameDuration(frame_t frame) const;
int totalAnimationDuration() const;
void setFrameDuration(frame_t frame, int msecs);
void setFrameRangeDuration(frame_t from, frame_t to, int msecs);
void setDurationForAllFrames(int msecs);