mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-18 21:40:46 +00:00
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
This commit is contained in:
parent
e09cdd67cb
commit
58d302749c
@ -133,12 +133,6 @@
|
||||
<option id="opacity_step" type="int" default="28" migrate="Onionskin.OpacityStep" />
|
||||
<option id="type" type="OnionskinType" default="OnionskinType::MERGE" migrate="Onionskin.Type" />
|
||||
</section>
|
||||
<section id="loop">
|
||||
<option id="visible" type="bool" default="false" />
|
||||
<option id="from" type="doc::frame_t" default="0" />
|
||||
<option id="to" type="doc::frame_t" default="1" />
|
||||
<option id="ani_dir" type="doc::AniDir" default="doc::AniDir::FORWARD" />
|
||||
</section>
|
||||
</document>
|
||||
|
||||
</preferences>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -10,6 +10,8 @@
|
||||
<dim id="tabs_close_icon_width" value="14" />
|
||||
<dim id="tabs_close_icon_height" value="12" />
|
||||
<dim id="tabs_icon_width" value="10" />
|
||||
<dim id="timeline_top_border" value="2" />
|
||||
<dim id="timeline_tags_area_height" value="4" />
|
||||
</dimensions>
|
||||
|
||||
<colors>
|
||||
@ -348,7 +350,7 @@
|
||||
<part id="timeline_padding_br" x="288" y="24" w1="1" w2="10" w3="1" h1="1" h2="10" h3="1" />
|
||||
<part id="timeline_drop_layer_deco" x="252" y="127" w1="3" w2="1" w3="3" h1="2" h2="1" h3="2" />
|
||||
<part id="timeline_drop_frame_deco" x="252" y="120" w1="2" w2="1" w3="2" h1="3" h2="1" h3="3" />
|
||||
<part id="timeline_loop_range" x="240" y="132" w1="3" w2="6" w3="3" h1="3" h2="6" h3="3" />
|
||||
<part id="timeline_loop_range" x="240" y="132" w1="4" w2="4" w3="4" h1="3" h2="6" h3="3" />
|
||||
<part id="flag_normal" x="0" y="240" w="16" h="10" />
|
||||
<part id="flag_highlight" x="16" y="240" w="16" h="10" />
|
||||
<part id="drop_pixels_ok" x="176" y="176" w="7" h="8" />
|
||||
|
@ -5,10 +5,10 @@
|
||||
<window text="Frame Tag Properties" id="frame_tag_properties">
|
||||
<grid columns="2">
|
||||
<label text="Name:" />
|
||||
<entry maxsize="256" id="name" />
|
||||
<entry maxsize="256" id="name" magnet="true" />
|
||||
|
||||
<label text="From:" />
|
||||
<entry maxsize="10" id="from" magnet="true" />
|
||||
<entry maxsize="10" id="from" />
|
||||
|
||||
<label text="To:" />
|
||||
<entry maxsize="10" id="to" />
|
||||
|
@ -258,6 +258,7 @@ add_library(app-lib
|
||||
job.cpp
|
||||
launcher.cpp
|
||||
log.cpp
|
||||
loop_tag.cpp
|
||||
modules.cpp
|
||||
modules/editors.cpp
|
||||
modules/gfx.cpp
|
||||
@ -312,6 +313,7 @@ add_library(app-lib
|
||||
ui/editor/zooming_state.cpp
|
||||
ui/file_list.cpp
|
||||
ui/file_selector.cpp
|
||||
ui/frame_tag_window.cpp
|
||||
ui/hex_color_entry.cpp
|
||||
ui/home_view.cpp
|
||||
ui/keyboard_shortcuts.cpp
|
||||
|
@ -16,14 +16,13 @@
|
||||
#include "app/color.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/loop_tag.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/frame_tag_window.h"
|
||||
#include "doc/anidir.h"
|
||||
#include "doc/frame_tag.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
#include "generated_frame_tag_properties.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
@ -56,76 +55,39 @@ void FrameTagPropertiesCommand::onExecute(Context* context)
|
||||
{
|
||||
const ContextReader reader(context);
|
||||
const Sprite* sprite = reader.sprite();
|
||||
|
||||
frame_t frame = reader.frame();
|
||||
|
||||
const FrameTag* best = nullptr;
|
||||
for (const FrameTag* tag : sprite->frameTags()) {
|
||||
if (frame >= tag->fromFrame() &&
|
||||
frame <= tag->toFrame()) {
|
||||
if (!best ||
|
||||
(tag->toFrame() - tag->fromFrame()) < (best->toFrame() - best->fromFrame())) {
|
||||
best = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!best)
|
||||
const FrameTag* foundTag = get_shortest_tag(sprite, frame);
|
||||
if (!foundTag)
|
||||
return;
|
||||
|
||||
app::gen::FrameTagProperties window;
|
||||
FrameTagWindow window(sprite, foundTag);
|
||||
if (!window.show())
|
||||
return;
|
||||
|
||||
window.name()->setText(best->name());
|
||||
window.from()->setTextf("%d", best->fromFrame()+1);
|
||||
window.to()->setTextf("%d", best->toFrame()+1);
|
||||
window.color()->setColor(app::Color::fromRgb(
|
||||
doc::rgba_getr(best->color()),
|
||||
doc::rgba_getg(best->color()),
|
||||
doc::rgba_getb(best->color())));
|
||||
ContextWriter writer(reader);
|
||||
Transaction transaction(writer.context(), "Change Frame Tag Properties");
|
||||
FrameTag* tag = const_cast<FrameTag*>(foundTag);
|
||||
|
||||
static_assert(
|
||||
int(doc::AniDir::FORWARD) == 0 &&
|
||||
int(doc::AniDir::REVERSE) == 1 &&
|
||||
int(doc::AniDir::PING_PONG) == 2, "doc::AniDir has changed");
|
||||
window.anidir()->addItem("Forward");
|
||||
window.anidir()->addItem("Reverse");
|
||||
window.anidir()->addItem("Ping-pong");
|
||||
window.anidir()->setSelectedItemIndex(int(best->aniDir()));
|
||||
std::string name = window.nameValue();
|
||||
if (tag->name() != name)
|
||||
transaction.execute(new cmd::SetFrameTagName(tag, name));
|
||||
|
||||
window.openWindowInForeground();
|
||||
if (window.getKiller() == window.ok()) {
|
||||
std::string name = window.name()->getText();
|
||||
frame_t first = 0;
|
||||
frame_t last = sprite->lastFrame();
|
||||
frame_t from = window.from()->getTextInt()-1;
|
||||
frame_t to = window.to()->getTextInt()-1;
|
||||
from = MID(first, from, last);
|
||||
to = MID(from, to, last);
|
||||
app::Color color = window.color()->getColor();
|
||||
doc::color_t docColor = doc::rgba(
|
||||
color.getRed(), color.getGreen(), color.getBlue(), 255);
|
||||
doc::AniDir anidir = (doc::AniDir)window.anidir()->getSelectedItemIndex();
|
||||
|
||||
ContextWriter writer(reader);
|
||||
Transaction transaction(writer.context(), "Change Frame Tag Properties");
|
||||
|
||||
FrameTag* tag = const_cast<FrameTag*>(best);
|
||||
|
||||
if (tag->name() != name)
|
||||
transaction.execute(new cmd::SetFrameTagName(tag, name));
|
||||
|
||||
if (tag->fromFrame() != from ||
|
||||
tag->toFrame() != to)
|
||||
transaction.execute(new cmd::SetFrameTagRange(tag, from, to));
|
||||
|
||||
if (tag->color() != docColor)
|
||||
transaction.execute(new cmd::SetFrameTagColor(tag, docColor));
|
||||
|
||||
if (tag->aniDir() != anidir)
|
||||
transaction.execute(new cmd::SetFrameTagAniDir(tag, anidir));
|
||||
|
||||
transaction.commit();
|
||||
doc::frame_t from, to;
|
||||
window.rangeValue(from, to);
|
||||
if (tag->fromFrame() != from ||
|
||||
tag->toFrame() != to) {
|
||||
transaction.execute(new cmd::SetFrameTagRange(tag, from, to));
|
||||
}
|
||||
|
||||
doc::color_t docColor = window.colorValue();
|
||||
if (tag->color() != docColor)
|
||||
transaction.execute(new cmd::SetFrameTagColor(tag, docColor));
|
||||
|
||||
doc::AniDir anidir = window.aniDirValue();
|
||||
if (tag->aniDir() != anidir)
|
||||
transaction.execute(new cmd::SetFrameTagAniDir(tag, anidir));
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createFrameTagPropertiesCommand()
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "app/context.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/frame_tag_window.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/frame_tag.h"
|
||||
@ -50,11 +51,10 @@ bool NewFrameTagCommand::onEnabled(Context* context)
|
||||
|
||||
void NewFrameTagCommand::onExecute(Context* context)
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Sprite* sprite(writer.sprite());
|
||||
|
||||
frame_t from = writer.frame();
|
||||
frame_t to = writer.frame();
|
||||
const ContextReader reader(context);
|
||||
const Sprite* sprite(reader.sprite());
|
||||
frame_t from = reader.frame();
|
||||
frame_t to = reader.frame();
|
||||
|
||||
Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
|
||||
if (range.enabled() &&
|
||||
@ -64,12 +64,22 @@ void NewFrameTagCommand::onExecute(Context* context)
|
||||
to = range.frameEnd();
|
||||
}
|
||||
|
||||
base::UniquePtr<FrameTag> frameTag(new FrameTag(from, to));
|
||||
FrameTagWindow window(sprite, frameTag);
|
||||
if (!window.show())
|
||||
return;
|
||||
|
||||
window.rangeValue(from, to);
|
||||
frameTag->setFrameRange(from, to);
|
||||
frameTag->setName(window.nameValue());
|
||||
frameTag->setColor(window.colorValue());
|
||||
frameTag->setAniDir(window.aniDirValue());
|
||||
|
||||
{
|
||||
ContextWriter writer(reader);
|
||||
Transaction transaction(writer.context(), "New Frames Tag");
|
||||
|
||||
FrameTag* frameTag = new FrameTag(from, to);
|
||||
transaction.execute(new cmd::AddFrameTag(sprite, frameTag));
|
||||
|
||||
transaction.execute(new cmd::AddFrameTag(writer.sprite(), frameTag));
|
||||
frameTag.release();
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#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"
|
||||
@ -69,18 +70,19 @@ protected:
|
||||
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(),
|
||||
m_docPref,
|
||||
m_editor->frame(), loopTag,
|
||||
m_pingPongForward);
|
||||
|
||||
m_editor->setFrame(frame);
|
||||
m_nextFrameTime += m_editor->sprite()->frameDuration(frame);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
invalidate();
|
||||
m_curFrameTick = ui::clock();
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,18 @@
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/cmd/add_frame_tag.h"
|
||||
#include "app/cmd/remove_frame_tag.h"
|
||||
#include "app/cmd/set_frame_tag_range.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/loop_tag.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/frame_tag.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -32,7 +38,7 @@ protected:
|
||||
void onExecute(Context* context) override;
|
||||
|
||||
Action m_action;
|
||||
frame_t m_begin, m_end;
|
||||
doc::frame_t m_begin, m_end;
|
||||
};
|
||||
|
||||
SetLoopSectionCommand::SetLoopSectionCommand()
|
||||
@ -66,13 +72,13 @@ bool SetLoopSectionCommand::onEnabled(Context* ctx)
|
||||
|
||||
void SetLoopSectionCommand::onExecute(Context* ctx)
|
||||
{
|
||||
Document* doc = ctx->activeDocument();
|
||||
doc::Document* doc = ctx->activeDocument();
|
||||
if (!doc)
|
||||
return;
|
||||
|
||||
DocumentPreferences& docPref = App::instance()->preferences().document(doc);
|
||||
frame_t begin = m_begin;
|
||||
frame_t end = m_end;
|
||||
doc::Sprite* sprite = doc->sprite();
|
||||
doc::frame_t begin = m_begin;
|
||||
doc::frame_t end = m_end;
|
||||
bool on = false;
|
||||
|
||||
switch (m_action) {
|
||||
@ -100,13 +106,39 @@ void SetLoopSectionCommand::onExecute(Context* ctx)
|
||||
|
||||
}
|
||||
|
||||
doc::FrameTag* loopTag = get_loop_tag(sprite);
|
||||
if (on) {
|
||||
docPref.loop.visible(true);
|
||||
docPref.loop.from(begin);
|
||||
docPref.loop.to(end);
|
||||
if (!loopTag) {
|
||||
loopTag = create_loop_tag(begin, end);
|
||||
|
||||
ContextWriter writer(ctx);
|
||||
Transaction transaction(writer.context(), "Add Loop");
|
||||
transaction.execute(new cmd::AddFrameTag(sprite, loopTag));
|
||||
transaction.commit();
|
||||
}
|
||||
else if (loopTag->fromFrame() != begin ||
|
||||
loopTag->toFrame() != end) {
|
||||
ContextWriter writer(ctx);
|
||||
Transaction transaction(writer.context(), "Set Loop Range");
|
||||
transaction.execute(new cmd::SetFrameTagRange(loopTag, begin, end));
|
||||
transaction.commit();
|
||||
}
|
||||
else {
|
||||
Command* cmd = CommandsModule::instance()->getCommandByName(CommandId::FrameTagProperties);
|
||||
ctx->executeCommand(cmd);
|
||||
}
|
||||
}
|
||||
else
|
||||
docPref.loop.visible(false);
|
||||
else {
|
||||
if (loopTag) {
|
||||
ContextWriter writer(ctx);
|
||||
Transaction transaction(writer.context(), "Remove Loop");
|
||||
transaction.execute(new cmd::RemoveFrameTag(sprite, loopTag));
|
||||
transaction.commit();
|
||||
delete loopTag;
|
||||
}
|
||||
}
|
||||
|
||||
App::instance()->getMainWindow()->getTimeline()->invalidate();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSetLoopSectionCommand()
|
||||
|
@ -133,7 +133,8 @@ class AseFormat : public FileFormat {
|
||||
FILE_SUPPORT_INDEXED |
|
||||
FILE_SUPPORT_LAYERS |
|
||||
FILE_SUPPORT_FRAMES |
|
||||
FILE_SUPPORT_PALETTES;
|
||||
FILE_SUPPORT_PALETTES |
|
||||
FILE_SUPPORT_FRAME_TAGS;
|
||||
}
|
||||
|
||||
bool onLoad(FileOp* fop) override;
|
||||
@ -1285,6 +1286,11 @@ static void ase_file_read_frame_tags_chunk(FILE* f, FrameTags* frameTags)
|
||||
frame_t from = fgetw(f);
|
||||
frame_t to = fgetw(f);
|
||||
int aniDir = fgetc(f);
|
||||
if (aniDir != int(AniDir::FORWARD) &&
|
||||
aniDir != int(AniDir::REVERSE) &&
|
||||
aniDir != int(AniDir::PING_PONG)) {
|
||||
aniDir = int(AniDir::FORWARD);
|
||||
}
|
||||
|
||||
fgetl(f); // 8 reserved bytes
|
||||
fgetl(f);
|
||||
|
@ -294,7 +294,7 @@ FileOp* fop_to_save_document(Context* context, Document* document, const char* f
|
||||
break;
|
||||
}
|
||||
|
||||
// check frames support
|
||||
// Frames support
|
||||
if (fop->document->sprite()->totalFrames() > 1) {
|
||||
if (!fop->format->support(FILE_SUPPORT_FRAMES) &&
|
||||
!fop->format->support(FILE_SUPPORT_SEQUENCES)) {
|
||||
@ -302,14 +302,14 @@ FileOp* fop_to_save_document(Context* context, Document* document, const char* f
|
||||
}
|
||||
}
|
||||
|
||||
// layers support
|
||||
// Layers support
|
||||
if (fop->document->sprite()->folder()->getLayersCount() > 1) {
|
||||
if (!(fop->format->support(FILE_SUPPORT_LAYERS))) {
|
||||
warnings += "<<- Layers";
|
||||
}
|
||||
}
|
||||
|
||||
// Palettes support.
|
||||
// Palettes support
|
||||
if (fop->document->sprite()->getPalettes().size() > 1) {
|
||||
if (!fop->format->support(FILE_SUPPORT_PALETTES) &&
|
||||
!fop->format->support(FILE_SUPPORT_SEQUENCES)) {
|
||||
@ -317,6 +317,13 @@ FileOp* fop_to_save_document(Context* context, Document* document, const char* f
|
||||
}
|
||||
}
|
||||
|
||||
// Check frames support
|
||||
if (!fop->document->sprite()->frameTags().empty()) {
|
||||
if (!fop->format->support(FILE_SUPPORT_FRAME_TAGS)) {
|
||||
warnings += "<<- Frame tags";
|
||||
}
|
||||
}
|
||||
|
||||
// Show the confirmation alert
|
||||
if (!warnings.empty()) {
|
||||
// Interative
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define FILE_SUPPORT_PALETTES 0x00000200
|
||||
#define FILE_SUPPORT_SEQUENCES 0x00000400
|
||||
#define FILE_SUPPORT_GET_FORMAT_OPTIONS 0x00000800
|
||||
#define FILE_SUPPORT_FRAME_TAGS 0x00001000
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "app/handle_anidir.h"
|
||||
|
||||
#include "doc/frame.h"
|
||||
#include "doc/frame_tag.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
@ -18,24 +20,27 @@ namespace app {
|
||||
doc::frame_t calculate_next_frame(
|
||||
doc::Sprite* sprite,
|
||||
doc::frame_t frame,
|
||||
DocumentPreferences& docPref,
|
||||
doc::FrameTag* tag,
|
||||
bool& pingPongForward)
|
||||
{
|
||||
frame_t first = frame_t(0);
|
||||
frame_t last = sprite->lastFrame();
|
||||
doc::frame_t first = doc::frame_t(0);
|
||||
doc::frame_t last = sprite->lastFrame();
|
||||
doc::AniDir aniDir = doc::AniDir::FORWARD;
|
||||
|
||||
if (docPref.loop.visible()) {
|
||||
frame_t loopBegin, loopEnd;
|
||||
loopBegin = docPref.loop.from();
|
||||
loopEnd = docPref.loop.to();
|
||||
loopBegin = MID(first, loopBegin, last);
|
||||
loopEnd = MID(first, loopEnd, last);
|
||||
if (tag) {
|
||||
doc::frame_t loopFrom, loopTo;
|
||||
|
||||
first = loopBegin;
|
||||
last = loopEnd;
|
||||
loopFrom = tag->fromFrame();
|
||||
loopTo = tag->toFrame();
|
||||
loopFrom = MID(first, loopFrom, last);
|
||||
loopTo = MID(first, loopTo, last);
|
||||
|
||||
first = loopFrom;
|
||||
last = loopTo;
|
||||
aniDir = tag->aniDir();
|
||||
}
|
||||
|
||||
switch (docPref.loop.aniDir()) {
|
||||
switch (aniDir) {
|
||||
|
||||
case doc::AniDir::FORWARD:
|
||||
++frame;
|
||||
|
@ -9,10 +9,10 @@
|
||||
#define APP_HANDLE_ANIDIR_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/pref/preferences.h"
|
||||
#include "doc/frame.h"
|
||||
|
||||
namespace doc {
|
||||
class FrameTag;
|
||||
class Sprite;
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ namespace app {
|
||||
doc::frame_t calculate_next_frame(
|
||||
doc::Sprite* sprite,
|
||||
doc::frame_t frame,
|
||||
DocumentPreferences& docPref,
|
||||
doc::FrameTag* tag,
|
||||
bool& pingPongForward);
|
||||
|
||||
} // namespace app
|
||||
|
53
src/app/loop_tag.cpp
Normal file
53
src/app/loop_tag.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
// 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 "app/loop_tag.h"
|
||||
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/frame_tag.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
const char* kLoopTagName = "Loop";
|
||||
|
||||
doc::FrameTag* get_shortest_tag(const doc::Sprite* sprite, doc::frame_t frame)
|
||||
{
|
||||
const doc::FrameTag* found = nullptr;
|
||||
for (const doc::FrameTag* tag : sprite->frameTags()) {
|
||||
if (frame >= tag->fromFrame() &&
|
||||
frame <= tag->toFrame()) {
|
||||
if (!found ||
|
||||
(tag->toFrame() - tag->fromFrame()) < (found->toFrame() - found->fromFrame())) {
|
||||
found = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return const_cast<doc::FrameTag*>(found);
|
||||
}
|
||||
|
||||
doc::FrameTag* get_loop_tag(doc::Sprite* sprite)
|
||||
{
|
||||
// Get tag with special "Loop" name
|
||||
for (doc::FrameTag* tag : sprite->frameTags())
|
||||
if (tag->name() == kLoopTagName)
|
||||
return tag;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
doc::FrameTag* create_loop_tag(doc::frame_t from, doc::frame_t to)
|
||||
{
|
||||
doc::FrameTag* tag = new doc::FrameTag(from, to);
|
||||
tag->setName(kLoopTagName);
|
||||
return tag;
|
||||
}
|
||||
|
||||
} // app
|
27
src/app/loop_tag.h
Normal file
27
src/app/loop_tag.h
Normal file
@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
|
||||
#ifndef APP_LOOP_TAG_H_INCLUDED
|
||||
#define APP_LOOP_TAG_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/frame.h"
|
||||
|
||||
namespace doc {
|
||||
class FrameTag;
|
||||
class Sprite;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
doc::FrameTag* get_shortest_tag(const doc::Sprite* sprite, doc::frame_t frame);
|
||||
doc::FrameTag* get_loop_tag(doc::Sprite* sprite);
|
||||
doc::FrameTag* create_loop_tag(doc::frame_t from, doc::frame_t to);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -12,17 +12,23 @@
|
||||
#include "app/ui/configure_timeline_popup.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/cmd/remove_frame_tag.h"
|
||||
#include "app/cmd/set_frame_tag_anidir.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/context.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document.h"
|
||||
#include "app/find_widget.h"
|
||||
#include "app/load_widget.h"
|
||||
#include "app/loop_tag.h"
|
||||
#include "app/settings/settings.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/frame_tag.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/message.h"
|
||||
@ -66,10 +72,14 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
|
||||
m_pingPongDir->Click.connect(Bind<void>(&ConfigureTimelinePopup::onAniDir, this, doc::AniDir::PING_PONG));
|
||||
}
|
||||
|
||||
app::Document* ConfigureTimelinePopup::doc()
|
||||
{
|
||||
return UIContext::instance()->activeDocument();
|
||||
}
|
||||
|
||||
DocumentPreferences& ConfigureTimelinePopup::docPref()
|
||||
{
|
||||
return App::instance()->preferences().document(
|
||||
UIContext::instance()->activeDocument());
|
||||
return App::instance()->preferences().document(doc());
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
|
||||
@ -97,7 +107,17 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
|
||||
break;
|
||||
}
|
||||
|
||||
switch (docPref.loop.aniDir()) {
|
||||
doc::AniDir aniDir = doc::AniDir::FORWARD;
|
||||
if (doc()) {
|
||||
if (doc::FrameTag* tag = get_loop_tag(doc()->sprite())) {
|
||||
aniDir = tag->aniDir();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ASSERT(false && "We should have an active sprite at this moment");
|
||||
}
|
||||
|
||||
switch (aniDir) {
|
||||
case doc::AniDir::FORWARD:
|
||||
m_normalDir->setSelected(true);
|
||||
break;
|
||||
@ -167,12 +187,32 @@ void ConfigureTimelinePopup::onSetLoopSection()
|
||||
|
||||
void ConfigureTimelinePopup::onResetLoopSection()
|
||||
{
|
||||
docPref().loop.visible(false);
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Transaction transaction(writer.context(), "Remove Loop");
|
||||
transaction.execute(new cmd::RemoveFrameTag(writer.sprite(),
|
||||
get_loop_tag(writer.sprite())));
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onAniDir(doc::AniDir aniDir)
|
||||
{
|
||||
docPref().loop.aniDir(aniDir);
|
||||
ContextWriter writer(UIContext::instance());
|
||||
doc::Sprite* sprite = writer.sprite();
|
||||
if (sprite) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
doc::FrameTag* loopTag = get_loop_tag(sprite);
|
||||
Transaction transaction(writer.context(), "Set Loop Direction");
|
||||
if (loopTag)
|
||||
transaction.execute(new cmd::SetFrameTagAniDir(loopTag, aniDir));
|
||||
else {
|
||||
loopTag = create_loop_tag(doc::frame_t(0), sprite->lastFrame());
|
||||
loopTag->setAniDir(aniDir);
|
||||
transaction.execute(new cmd::AddFrameTag(sprite, loopTag));
|
||||
}
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -21,6 +21,7 @@ namespace ui {
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
|
||||
class ConfigureTimelinePopup : public ui::PopupWindow {
|
||||
public:
|
||||
@ -38,6 +39,7 @@ namespace app {
|
||||
|
||||
private:
|
||||
void updateWidgetsFromCurrentSettings();
|
||||
app::Document* doc();
|
||||
DocumentPreferences& docPref();
|
||||
|
||||
ui::RadioButton* m_merge;
|
||||
|
73
src/app/ui/frame_tag_window.cpp
Normal file
73
src/app/ui/frame_tag_window.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
// 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 "app/ui/frame_tag_window.h"
|
||||
|
||||
#include "doc/frame_tag.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
FrameTagWindow::FrameTagWindow(const doc::Sprite* sprite, const doc::FrameTag* frameTag)
|
||||
: m_sprite(sprite)
|
||||
{
|
||||
name()->setText(frameTag->name());
|
||||
from()->setTextf("%d", frameTag->fromFrame()+1);
|
||||
to()->setTextf("%d", frameTag->toFrame()+1);
|
||||
color()->setColor(app::Color::fromRgb(
|
||||
doc::rgba_getr(frameTag->color()),
|
||||
doc::rgba_getg(frameTag->color()),
|
||||
doc::rgba_getb(frameTag->color())));
|
||||
|
||||
static_assert(
|
||||
int(doc::AniDir::FORWARD) == 0 &&
|
||||
int(doc::AniDir::REVERSE) == 1 &&
|
||||
int(doc::AniDir::PING_PONG) == 2, "doc::AniDir has changed");
|
||||
anidir()->addItem("Forward");
|
||||
anidir()->addItem("Reverse");
|
||||
anidir()->addItem("Ping-pong");
|
||||
anidir()->setSelectedItemIndex(int(frameTag->aniDir()));
|
||||
}
|
||||
|
||||
bool FrameTagWindow::show()
|
||||
{
|
||||
openWindowInForeground();
|
||||
return (getKiller() == ok());
|
||||
}
|
||||
|
||||
std::string FrameTagWindow::nameValue()
|
||||
{
|
||||
return name()->getText();
|
||||
}
|
||||
|
||||
void FrameTagWindow::rangeValue(doc::frame_t& from, doc::frame_t& to)
|
||||
{
|
||||
doc::frame_t first = 0;
|
||||
doc::frame_t last = m_sprite->lastFrame();
|
||||
|
||||
from = this->from()->getTextInt()-1;
|
||||
to = this->to()->getTextInt()-1;
|
||||
from = MID(first, from, last);
|
||||
to = MID(from, to, last);
|
||||
}
|
||||
|
||||
doc::color_t FrameTagWindow::colorValue()
|
||||
{
|
||||
app::Color color = this->color()->getColor();
|
||||
return doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255);
|
||||
}
|
||||
|
||||
doc::AniDir FrameTagWindow::aniDirValue()
|
||||
{
|
||||
return (doc::AniDir)anidir()->getSelectedItemIndex();
|
||||
}
|
||||
|
||||
} // namespace app
|
46
src/app/ui/frame_tag_window.h
Normal file
46
src/app/ui/frame_tag_window.h
Normal file
@ -0,0 +1,46 @@
|
||||
// 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.
|
||||
|
||||
#ifndef APP_UI_FRAME_TAG_WINDOW_H_INCLUDED
|
||||
#define APP_UI_FRAME_TAG_WINDOW_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/color_button.h"
|
||||
#include "doc/anidir.h"
|
||||
#include "doc/frame.h"
|
||||
|
||||
#include "generated_frame_tag_properties.h"
|
||||
|
||||
namespace doc {
|
||||
class FrameTag;
|
||||
class Sprite;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class Splitter;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
class FrameTagWindow : protected app::gen::FrameTagProperties {
|
||||
public:
|
||||
FrameTagWindow(const doc::Sprite* sprite, const doc::FrameTag* frameTag);
|
||||
|
||||
bool show();
|
||||
|
||||
std::string nameValue();
|
||||
void rangeValue(doc::frame_t& from, doc::frame_t& to);
|
||||
doc::color_t colorValue();
|
||||
doc::AniDir aniDirValue();
|
||||
|
||||
private:
|
||||
const doc::Sprite* m_sprite;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -15,6 +15,7 @@
|
||||
#include "app/document.h"
|
||||
#include "app/handle_anidir.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/loop_tag.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/pref/preferences.h"
|
||||
@ -35,6 +36,8 @@
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
#include "doc/frame_tag.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace app::skin;
|
||||
@ -157,6 +160,7 @@ PreviewEditorWindow::PreviewEditorWindow()
|
||||
, m_playButton(new MiniPlayButton())
|
||||
, m_playTimer(10)
|
||||
, m_pingPongForward(true)
|
||||
, m_refFrame(0)
|
||||
{
|
||||
child_spacing = 0;
|
||||
setAutoRemap(false);
|
||||
@ -305,7 +309,7 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
|
||||
miniEditor->centerInSpritePoint(centerPoint);
|
||||
|
||||
miniEditor->setLayer(editor->layer());
|
||||
miniEditor->setFrame(editor->frame());
|
||||
miniEditor->setFrame(m_refFrame = editor->frame());
|
||||
}
|
||||
|
||||
void PreviewEditorWindow::uncheckCenterButton()
|
||||
@ -329,22 +333,24 @@ void PreviewEditorWindow::onPlaybackTick()
|
||||
if (!miniEditor)
|
||||
return;
|
||||
|
||||
Document* document = miniEditor->document();
|
||||
Sprite* sprite = miniEditor->sprite();
|
||||
doc::Document* document = miniEditor->document();
|
||||
doc::Sprite* sprite = miniEditor->sprite();
|
||||
if (!document || !sprite)
|
||||
return;
|
||||
|
||||
DocumentPreferences& docPref =
|
||||
App::instance()->preferences().document(document);
|
||||
|
||||
if (m_nextFrameTime >= 0) {
|
||||
m_nextFrameTime -= (ui::clock() - m_curFrameTick);
|
||||
|
||||
// TODO get the frame tag in updateUsingEditor()
|
||||
doc::FrameTag* tag = get_shortest_tag(sprite, m_refFrame);
|
||||
if (!tag)
|
||||
tag = get_loop_tag(sprite);
|
||||
|
||||
while (m_nextFrameTime <= 0) {
|
||||
frame_t frame = calculate_next_frame(
|
||||
doc::frame_t frame = calculate_next_frame(
|
||||
sprite,
|
||||
miniEditor->frame(),
|
||||
docPref,
|
||||
tag,
|
||||
m_pingPongForward);
|
||||
|
||||
miniEditor->setFrame(frame);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/document_view.h"
|
||||
#include "doc/frame.h"
|
||||
#include "ui/timer.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
@ -51,6 +52,7 @@ namespace app {
|
||||
int m_curFrameTick;
|
||||
|
||||
bool m_pingPongForward;
|
||||
doc::frame_t m_refFrame;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/app_menus.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
@ -22,6 +23,7 @@
|
||||
#include "app/document_api.h"
|
||||
#include "app/document_range_ops.h"
|
||||
#include "app/document_undo.h"
|
||||
#include "app/loop_tag.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/modules/gui.h"
|
||||
@ -40,6 +42,7 @@
|
||||
#include "doc/frame_tag.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "she/font.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include <cstdio>
|
||||
@ -76,6 +79,7 @@ using namespace ui;
|
||||
|
||||
enum {
|
||||
A_PART_NOTHING,
|
||||
A_PART_TOP,
|
||||
A_PART_SEPARATOR,
|
||||
A_PART_HEADER_EYE,
|
||||
A_PART_HEADER_PADLOCK,
|
||||
@ -86,6 +90,7 @@ enum {
|
||||
A_PART_HEADER_ONIONSKIN_RANGE_RIGHT,
|
||||
A_PART_HEADER_LAYER,
|
||||
A_PART_HEADER_FRAME,
|
||||
A_PART_HEADER_FRAME_TAGS,
|
||||
A_PART_LAYER,
|
||||
A_PART_LAYER_EYE_ICON,
|
||||
A_PART_LAYER_PADLOCK_ICON,
|
||||
@ -758,6 +763,8 @@ void Timeline::onPaint(ui::PaintEvent& ev)
|
||||
getDrawableLayers(g, &first_layer, &last_layer);
|
||||
getDrawableFrames(g, &first_frame, &last_frame);
|
||||
|
||||
drawTop(g);
|
||||
|
||||
// Draw the header for layers.
|
||||
drawHeader(g);
|
||||
|
||||
@ -811,7 +818,6 @@ void Timeline::onPaint(ui::PaintEvent& ev)
|
||||
}
|
||||
|
||||
drawPaddings(g);
|
||||
drawLoopRange(g);
|
||||
drawFrameTags(g);
|
||||
drawRangeOutline(g);
|
||||
drawClipboardRange(g);
|
||||
@ -1037,6 +1043,12 @@ void Timeline::drawClipboardRange(ui::Graphics* g)
|
||||
g->drawRect(0, getRangeBounds(clipboard_range));
|
||||
}
|
||||
|
||||
void Timeline::drawTop(ui::Graphics* g)
|
||||
{
|
||||
g->fillRect(skinTheme()->colors.workspace(),
|
||||
getPartBounds(A_PART_TOP));
|
||||
}
|
||||
|
||||
void Timeline::drawHeader(ui::Graphics* g)
|
||||
{
|
||||
SkinTheme::Styles& styles = skinTheme()->styles;
|
||||
@ -1253,41 +1265,50 @@ void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::drawLoopRange(ui::Graphics* g)
|
||||
void Timeline::drawFrameTags(ui::Graphics* g)
|
||||
{
|
||||
DocumentPreferences& docPref = this->docPref();
|
||||
if (!docPref.loop.visible())
|
||||
return;
|
||||
|
||||
frame_t begin = docPref.loop.from();
|
||||
frame_t end = docPref.loop.to();
|
||||
if (begin > end)
|
||||
return;
|
||||
|
||||
gfx::Rect bounds1 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), begin);
|
||||
gfx::Rect bounds2 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), end);
|
||||
gfx::Rect bounds = bounds1.createUnion(bounds2);
|
||||
|
||||
IntersectClip clip(g, bounds);
|
||||
IntersectClip clip(g, getPartBounds(A_PART_HEADER_FRAME_TAGS));
|
||||
if (!clip)
|
||||
return;
|
||||
|
||||
drawPart(g, bounds, NULL,
|
||||
skinTheme()->styles.timelineLoopRange());
|
||||
}
|
||||
SkinTheme* theme = skinTheme();
|
||||
SkinTheme::Styles& styles = theme->styles;
|
||||
|
||||
void Timeline::drawFrameTags(ui::Graphics* g)
|
||||
{
|
||||
SkinTheme::Styles& styles = skinTheme()->styles;
|
||||
if (!m_sprite->frameTags().empty()) {
|
||||
g->fillRect(theme->colors.workspace(),
|
||||
gfx::Rect(
|
||||
0, getFont()->height(),
|
||||
getClientBounds().w,
|
||||
theme->dimensions.timelineTagsAreaHeight()));
|
||||
}
|
||||
|
||||
for (FrameTag* frameTag : m_sprite->frameTags()) {
|
||||
gfx::Rect bounds1 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), frameTag->fromFrame());
|
||||
gfx::Rect bounds2 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), frameTag->toFrame());
|
||||
gfx::Rect bounds = bounds1.createUnion(bounds2);
|
||||
bounds.y -= theme->dimensions.timelineTagsAreaHeight();
|
||||
|
||||
IntersectClip clip(g, bounds);
|
||||
if (clip) {
|
||||
drawPart(g, bounds, NULL, styles.timelineLoopRange());
|
||||
{
|
||||
IntersectClip clip(g, bounds);
|
||||
if (clip)
|
||||
drawPart(g, bounds, NULL, styles.timelineLoopRange());
|
||||
}
|
||||
|
||||
{
|
||||
int textHeight = getFont()->height();
|
||||
bounds.y -= textHeight + 2*ui::guiscale();
|
||||
bounds.x += 3*ui::guiscale();
|
||||
bounds.w = getFont()->textLength(frameTag->name().c_str()) + 4*ui::guiscale();
|
||||
bounds.h = getFont()->height() + 2*ui::guiscale();
|
||||
g->fillRect(frameTag->color(), bounds);
|
||||
|
||||
bounds.y += 2*ui::guiscale();
|
||||
bounds.x += 2*ui::guiscale();
|
||||
g->drawString(
|
||||
frameTag->name(),
|
||||
color_utils::blackandwhite_neg(frameTag->color()),
|
||||
gfx::ColorNone,
|
||||
bounds.getOrigin());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1365,6 +1386,7 @@ void Timeline::drawPaddings(ui::Graphics* g)
|
||||
gfx::Rect client = getClientBounds();
|
||||
gfx::Rect bottomLayer;
|
||||
gfx::Rect lastFrame;
|
||||
int top = topHeight();
|
||||
|
||||
if (!m_layers.empty()) {
|
||||
bottomLayer = getPartBounds(A_PART_LAYER, firstLayer());
|
||||
@ -1376,7 +1398,7 @@ void Timeline::drawPaddings(ui::Graphics* g)
|
||||
}
|
||||
|
||||
drawPart(g,
|
||||
gfx::Rect(lastFrame.x+lastFrame.w, client.y,
|
||||
gfx::Rect(lastFrame.x+lastFrame.w, client.y + top,
|
||||
client.w - (lastFrame.x+lastFrame.w),
|
||||
bottomLayer.y+bottomLayer.h),
|
||||
NULL, styles.timelinePaddingTr());
|
||||
@ -1397,8 +1419,9 @@ gfx::Rect Timeline::getLayerHeadersBounds() const
|
||||
{
|
||||
gfx::Rect rc = getClientBounds();
|
||||
rc.w = m_separator_x;
|
||||
rc.y += HDRSIZE;
|
||||
rc.h -= HDRSIZE;
|
||||
int h = topHeight() + HDRSIZE;
|
||||
rc.y += h;
|
||||
rc.h -= h;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1406,6 +1429,7 @@ gfx::Rect Timeline::getFrameHeadersBounds() const
|
||||
{
|
||||
gfx::Rect rc = getClientBounds();
|
||||
rc.x += m_separator_x;
|
||||
rc.y += topHeight();
|
||||
rc.w -= m_separator_x;
|
||||
rc.h = HDRSIZE;
|
||||
return rc;
|
||||
@ -1435,78 +1459,89 @@ gfx::Rect Timeline::getCelsBounds() const
|
||||
gfx::Rect rc = getClientBounds();
|
||||
rc.x += m_separator_x;
|
||||
rc.w -= m_separator_x;
|
||||
rc.y += HDRSIZE;
|
||||
rc.h -= HDRSIZE;
|
||||
rc.y += HDRSIZE + topHeight();
|
||||
rc.h -= HDRSIZE - topHeight();
|
||||
return rc;
|
||||
}
|
||||
|
||||
gfx::Rect Timeline::getPartBounds(int part, LayerIndex layer, frame_t frame) const
|
||||
{
|
||||
const gfx::Rect bounds = getClientBounds();
|
||||
gfx::Rect bounds = getClientBounds();
|
||||
int y = topHeight();
|
||||
|
||||
switch (part) {
|
||||
|
||||
case A_PART_NOTHING:
|
||||
break;
|
||||
|
||||
case A_PART_TOP:
|
||||
return gfx::Rect(bounds.x, bounds.y, bounds.w, y);
|
||||
|
||||
case A_PART_SEPARATOR:
|
||||
return gfx::Rect(m_separator_x, 0,
|
||||
m_separator_x + m_separator_w, bounds.h);
|
||||
return gfx::Rect(bounds.x + m_separator_x, bounds.y + y,
|
||||
m_separator_x + m_separator_w, bounds.h - y);
|
||||
|
||||
case A_PART_HEADER_EYE:
|
||||
return gfx::Rect(FRMSIZE*0, 0, FRMSIZE, HDRSIZE);
|
||||
return gfx::Rect(bounds.x + FRMSIZE*0, bounds.y + y, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_PADLOCK:
|
||||
return gfx::Rect(FRMSIZE*1, 0, FRMSIZE, HDRSIZE);
|
||||
return gfx::Rect(bounds.x + FRMSIZE*1, bounds.y + y, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_CONTINUOUS:
|
||||
return gfx::Rect(FRMSIZE*2, 0, FRMSIZE, HDRSIZE);
|
||||
return gfx::Rect(bounds.x + FRMSIZE*2, bounds.y + y, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_GEAR:
|
||||
return gfx::Rect(FRMSIZE*3, 0, FRMSIZE, HDRSIZE);
|
||||
return gfx::Rect(bounds.x + FRMSIZE*3, bounds.y + y, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_ONIONSKIN:
|
||||
return gfx::Rect(FRMSIZE*4, 0, FRMSIZE, HDRSIZE);
|
||||
return gfx::Rect(bounds.x + FRMSIZE*4, bounds.y + y, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_LAYER:
|
||||
return gfx::Rect(FRMSIZE*5, 0,
|
||||
return gfx::Rect(bounds.x + FRMSIZE*5, bounds.y + y,
|
||||
m_separator_x - FRMSIZE*5, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_FRAME:
|
||||
if (validFrame(frame)) {
|
||||
return gfx::Rect(m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x,
|
||||
0, FRMSIZE, HDRSIZE);
|
||||
return gfx::Rect(
|
||||
bounds.x + m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x,
|
||||
bounds.y + y, FRMSIZE, HDRSIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_HEADER_FRAME_TAGS:
|
||||
return gfx::Rect(
|
||||
bounds.x + m_separator_x + m_separator_w - 1,
|
||||
bounds.y,
|
||||
bounds.w - m_separator_x - m_separator_w + 1, y);
|
||||
|
||||
case A_PART_LAYER:
|
||||
if (validLayer(layer)) {
|
||||
return gfx::Rect(0,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
return gfx::Rect(bounds.x,
|
||||
bounds.y + y + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
m_separator_x, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_EYE_ICON:
|
||||
if (validLayer(layer)) {
|
||||
return gfx::Rect(0,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
return gfx::Rect(bounds.x,
|
||||
bounds.y + y + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
FRMSIZE, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_PADLOCK_ICON:
|
||||
if (validLayer(layer)) {
|
||||
return gfx::Rect(FRMSIZE,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
return gfx::Rect(bounds.x + FRMSIZE,
|
||||
bounds.y + y + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
FRMSIZE, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_CONTINUOUS_ICON:
|
||||
if (validLayer(layer)) {
|
||||
return gfx::Rect(2*FRMSIZE,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
return gfx::Rect(bounds.x + 2*FRMSIZE,
|
||||
bounds.y + y + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
FRMSIZE, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
@ -1514,8 +1549,8 @@ gfx::Rect Timeline::getPartBounds(int part, LayerIndex layer, frame_t frame) con
|
||||
case A_PART_LAYER_TEXT:
|
||||
if (validLayer(layer)) {
|
||||
int x = FRMSIZE*3;
|
||||
return gfx::Rect(x,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
return gfx::Rect(bounds.x + x,
|
||||
bounds.y + y + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
m_separator_x - x, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
@ -1523,8 +1558,8 @@ gfx::Rect Timeline::getPartBounds(int part, LayerIndex layer, frame_t frame) con
|
||||
case A_PART_CEL:
|
||||
if (validLayer(layer) && frame >= frame_t(0)) {
|
||||
return gfx::Rect(
|
||||
m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
bounds.x + m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x,
|
||||
bounds.y + y + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
FRMSIZE, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
@ -1612,8 +1647,11 @@ void Timeline::updateHot(ui::Message* msg, const gfx::Point& mousePos, int& hot_
|
||||
hot_part = A_PART_SEPARATOR;
|
||||
}
|
||||
else {
|
||||
int top = topHeight();
|
||||
|
||||
hot_layer = lastLayer() - LayerIndex(
|
||||
(mousePos.y
|
||||
- top
|
||||
- HDRSIZE
|
||||
+ m_scroll_y) / LAYSIZE);
|
||||
|
||||
@ -1648,7 +1686,7 @@ void Timeline::updateHot(ui::Message* msg, const gfx::Point& mousePos, int& hot_
|
||||
hot_part = A_PART_SEPARATOR;
|
||||
}
|
||||
// Is the mouse on the headers?
|
||||
else if (mousePos.y < HDRSIZE) {
|
||||
else if (mousePos.y >= top && mousePos.y < top+HDRSIZE) {
|
||||
if (mousePos.x < m_separator_x) {
|
||||
if (getPartBounds(A_PART_HEADER_EYE).contains(mousePos))
|
||||
hot_part = A_PART_HEADER_EYE;
|
||||
@ -2168,4 +2206,14 @@ skin::SkinTheme* Timeline::skinTheme() const
|
||||
return static_cast<SkinTheme*>(getTheme());
|
||||
}
|
||||
|
||||
int Timeline::topHeight() const
|
||||
{
|
||||
int h = skinTheme()->dimensions.timelineTopBorder();
|
||||
if (m_sprite && !m_sprite->frameTags().empty()) {
|
||||
h += getFont()->height();
|
||||
h += skinTheme()->dimensions.timelineTagsAreaHeight();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -146,13 +146,13 @@ namespace app {
|
||||
void drawPart(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
const char* text, skin::Style* style,
|
||||
bool is_active = false, bool is_hover = false, bool is_clicked = false);
|
||||
void drawTop(ui::Graphics* g);
|
||||
void drawHeader(ui::Graphics* g);
|
||||
void drawHeaderFrame(ui::Graphics* g, frame_t frame);
|
||||
void drawLayer(ui::Graphics* g, LayerIndex layerIdx);
|
||||
void drawCel(ui::Graphics* g, LayerIndex layerIdx, frame_t frame, Cel* cel);
|
||||
void drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
Cel* cel, Cel* activeCel, frame_t frame, bool is_active, bool is_hover);
|
||||
void drawLoopRange(ui::Graphics* g);
|
||||
void drawFrameTags(ui::Graphics* g);
|
||||
void drawRangeOutline(ui::Graphics* g);
|
||||
void drawPaddings(ui::Graphics* g);
|
||||
@ -195,6 +195,8 @@ namespace app {
|
||||
bool validLayer(LayerIndex layer) const { return layer >= firstLayer() && layer <= lastLayer(); }
|
||||
bool validFrame(frame_t frame) const { return frame >= firstFrame() && frame <= lastFrame(); }
|
||||
|
||||
int topHeight() const;
|
||||
|
||||
DocumentPreferences& docPref() const;
|
||||
skin::SkinTheme* skinTheme() const;
|
||||
|
||||
|
@ -18,6 +18,7 @@ FrameTag::FrameTag(frame_t from, frame_t to)
|
||||
, m_to(to)
|
||||
, m_color(rgba(0, 0, 0, 255))
|
||||
, m_name("Tag")
|
||||
, m_aniDir(AniDir::FORWARD)
|
||||
{
|
||||
}
|
||||
|
||||
@ -39,6 +40,10 @@ void FrameTag::setColor(color_t color)
|
||||
|
||||
void FrameTag::setAniDir(AniDir aniDir)
|
||||
{
|
||||
ASSERT(m_aniDir == AniDir::FORWARD ||
|
||||
m_aniDir == AniDir::REVERSE ||
|
||||
m_aniDir == AniDir::PING_PONG);
|
||||
|
||||
m_aniDir = aniDir;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ namespace doc {
|
||||
const_iterator end() const { return m_tags.end(); }
|
||||
|
||||
std::size_t size() const { return m_tags.size(); }
|
||||
bool empty() const { return m_tags.empty(); }
|
||||
|
||||
private:
|
||||
Sprite* m_sprite;
|
||||
|
Loading…
x
Reference in New Issue
Block a user