2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
2025-04-01 05:43:27 +08:00
|
|
|
// Copyright (C) 2018-2025 Igara Studio S.A.
|
2018-03-16 03:05:56 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
2015-02-12 23:16:25 +08:00
|
|
|
//
|
2016-08-27 04:02:58 +08:00
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
2013-11-11 05:27:11 +08:00
|
|
|
|
2017-03-30 07:46:56 +08:00
|
|
|
#ifndef APP_UI_TIMELINE_TIMELINE_H_INCLUDED
|
|
|
|
#define APP_UI_TIMELINE_TIMELINE_H_INCLUDED
|
2014-03-30 06:40:17 +08:00
|
|
|
#pragma once
|
2013-11-11 05:27:11 +08:00
|
|
|
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "app/doc_observer.h"
|
2020-12-30 21:25:37 +08:00
|
|
|
#include "app/docs_observer.h"
|
2017-03-30 08:18:29 +08:00
|
|
|
#include "app/loop_tag.h"
|
2015-02-15 20:48:38 +08:00
|
|
|
#include "app/pref/preferences.h"
|
2013-11-11 09:59:25 +08:00
|
|
|
#include "app/ui/editor/editor_observer.h"
|
2015-05-10 06:55:33 +08:00
|
|
|
#include "app/ui/input_chain_element.h"
|
2017-03-30 07:46:56 +08:00
|
|
|
#include "app/ui/timeline/ani_controls.h"
|
2021-04-08 05:11:30 +08:00
|
|
|
#include "app/ui/timeline/timeline_observer.h"
|
2020-12-30 21:25:37 +08:00
|
|
|
#include "base/debug.h"
|
2014-12-29 07:39:11 +08:00
|
|
|
#include "doc/frame.h"
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "doc/layer.h"
|
2021-11-24 16:49:20 +08:00
|
|
|
#include "doc/object_version.h"
|
2016-06-14 04:24:41 +08:00
|
|
|
#include "doc/selected_frames.h"
|
2016-06-14 01:50:43 +08:00
|
|
|
#include "doc/selected_layers.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/sprite.h"
|
2020-12-30 21:25:37 +08:00
|
|
|
#include "doc/tag.h"
|
|
|
|
#include "gfx/color.h"
|
2016-09-14 02:02:00 +08:00
|
|
|
#include "obs/connection.h"
|
2021-04-08 05:11:30 +08:00
|
|
|
#include "obs/observable.h"
|
2015-09-18 02:19:47 +08:00
|
|
|
#include "ui/scroll_bar.h"
|
2014-08-08 21:33:45 +08:00
|
|
|
#include "ui/timer.h"
|
2013-11-11 05:27:11 +08:00
|
|
|
#include "ui/widget.h"
|
2023-06-09 06:00:49 +08:00
|
|
|
#include "view/range.h"
|
2023-06-06 04:25:01 +08:00
|
|
|
#include "view/timeline_adapter.h"
|
2013-11-11 05:27:11 +08:00
|
|
|
|
2021-05-29 02:08:17 +08:00
|
|
|
#include <memory>
|
2013-11-11 05:27:11 +08:00
|
|
|
#include <vector>
|
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
namespace doc {
|
2013-11-11 05:27:11 +08:00
|
|
|
class Cel;
|
|
|
|
class Layer;
|
2014-04-10 08:56:06 +08:00
|
|
|
class LayerImage;
|
2013-11-11 05:27:11 +08:00
|
|
|
class Sprite;
|
|
|
|
} // namespace doc
|
|
|
|
|
2013-12-11 11:34:16 +08:00
|
|
|
namespace ui {
|
|
|
|
class Graphics;
|
2018-12-14 01:08:56 +08:00
|
|
|
class TooltipManager;
|
2024-09-06 20:32:14 +08:00
|
|
|
class DragEvent;
|
2025-04-28 22:20:48 +08:00
|
|
|
struct PaintWidgetPartInfo;
|
2013-12-11 11:34:16 +08:00
|
|
|
} // namespace ui
|
|
|
|
|
2013-11-11 05:27:11 +08:00
|
|
|
namespace app {
|
2015-02-17 22:43:25 +08:00
|
|
|
|
|
|
|
namespace skin {
|
|
|
|
class SkinTheme;
|
|
|
|
}
|
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
using namespace doc;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-08-14 04:25:39 +08:00
|
|
|
class CommandExecutionEvent;
|
2014-05-18 08:27:44 +08:00
|
|
|
class ConfigureTimelinePopup;
|
2013-11-11 05:27:11 +08:00
|
|
|
class Context;
|
2018-07-07 13:47:42 +08:00
|
|
|
class Doc;
|
|
|
|
class Editor;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2013-11-11 05:27:11 +08:00
|
|
|
class Timeline : public ui::Widget,
|
|
|
|
public ui::ScrollableViewDelegate,
|
2013-12-15 20:42:05 +08:00
|
|
|
public obs::observable<TimelineObserver>,
|
2017-11-29 08:16:37 +08:00
|
|
|
public ContextObserver,
|
2018-07-07 19:38:04 +08:00
|
|
|
public DocsObserver,
|
2017-11-29 08:16:37 +08:00
|
|
|
public DocObserver,
|
|
|
|
public EditorObserver,
|
|
|
|
public InputChainElement,
|
2018-12-14 01:08:56 +08:00
|
|
|
public TagProvider {
|
2013-11-11 05:27:11 +08:00
|
|
|
public:
|
|
|
|
using Range = view::Range;
|
2023-06-06 04:25:01 +08:00
|
|
|
using RealRange = view::RealRange;
|
2023-06-09 06:00:49 +08:00
|
|
|
using VirtualRange = view::VirtualRange;
|
|
|
|
using fr_t = view::fr_t;
|
|
|
|
using col_t = view::col_t;
|
2019-10-02 01:55:08 +08:00
|
|
|
static constexpr const auto kNoCol = view::kNoCol;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-09-18 02:19:47 +08:00
|
|
|
enum State {
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
STATE_STANDBY,
|
2015-09-18 02:19:47 +08:00
|
|
|
STATE_SCROLLING,
|
|
|
|
STATE_SELECTING_LAYERS,
|
2019-09-06 02:03:13 +08:00
|
|
|
STATE_SELECTING_FRAMES,
|
2013-12-15 20:42:05 +08:00
|
|
|
STATE_SELECTING_CELS,
|
2019-09-06 02:03:13 +08:00
|
|
|
STATE_MOVING_SEPARATOR,
|
|
|
|
STATE_MOVING_RANGE,
|
2017-07-19 04:07:35 +08:00
|
|
|
STATE_MOVING_ONIONSKIN_RANGE_LEFT,
|
2018-07-07 08:06:03 +08:00
|
|
|
STATE_MOVING_ONIONSKIN_RANGE_RIGHT,
|
2019-10-02 01:55:08 +08:00
|
|
|
STATE_MOVING_TAG,
|
2024-02-27 00:11:26 +08:00
|
|
|
STATE_RESIZING_TAG_LEFT,
|
2018-07-07 13:47:42 +08:00
|
|
|
STATE_RESIZING_TAG_RIGHT,
|
2015-04-07 21:48:04 +08:00
|
|
|
// Changing layers flags states
|
2014-08-28 20:36:34 +08:00
|
|
|
STATE_SHOWING_LAYERS,
|
|
|
|
STATE_HIDING_LAYERS,
|
|
|
|
STATE_LOCKING_LAYERS,
|
|
|
|
STATE_UNLOCKING_LAYERS,
|
|
|
|
STATE_ENABLING_CONTINUOUS_LAYERS,
|
2024-09-05 04:37:24 +08:00
|
|
|
STATE_DISABLING_CONTINUOUS_LAYERS,
|
2015-05-10 06:55:33 +08:00
|
|
|
STATE_EXPANDING_LAYERS,
|
|
|
|
STATE_COLLAPSING_LAYERS,
|
2025-04-28 22:20:48 +08:00
|
|
|
// Drag & drop handling state
|
|
|
|
STATE_DRAGGING_EXTERNAL_RANGE,
|
2024-09-06 20:32:14 +08:00
|
|
|
};
|
|
|
|
|
2015-09-15 21:57:43 +08:00
|
|
|
enum DropOp { kMove, kCopy };
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-08-27 05:18:25 +08:00
|
|
|
Timeline(ui::TooltipManager* tooltipManager);
|
2017-04-13 02:53:54 +08:00
|
|
|
~Timeline();
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-04-13 02:53:54 +08:00
|
|
|
void updateUsingEditor(Editor* editor);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
Sprite* sprite() { return m_sprite; }
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-04-13 02:53:54 +08:00
|
|
|
bool isMovingCel() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-07-22 09:59:45 +08:00
|
|
|
// The range is specified in "virtual frames" (not real sprite
|
2016-08-27 05:18:25 +08:00
|
|
|
// frames, we'll have to do a conversion each time we want to use
|
2017-04-13 02:53:54 +08:00
|
|
|
// this range with the sprite).
|
2018-06-13 04:11:10 +08:00
|
|
|
VirtualRange virtualRange() const { return m_range; }
|
|
|
|
bool isRangeEnabled() const { return m_range.enabled(); }
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-04-13 03:24:43 +08:00
|
|
|
// Returns the range in "real sprite frames."
|
2017-04-13 02:53:54 +08:00
|
|
|
RealRange realRange() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-04-13 02:53:54 +08:00
|
|
|
void prepareToMoveRange();
|
|
|
|
void moveRange(const VirtualRange& range);
|
2023-09-16 06:53:31 +08:00
|
|
|
void setVirtualRange(const VirtualRange& range);
|
|
|
|
void setRealRange(const RealRange& range);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-09-16 06:53:31 +08:00
|
|
|
void activateClipboardRange();
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-08-25 23:31:00 +08:00
|
|
|
// Drag-and-drop operations. These actions are used by commands
|
|
|
|
// called from popup menus.
|
2023-06-06 04:25:01 +08:00
|
|
|
void dropRange(DropOp op);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-06-06 04:25:01 +08:00
|
|
|
// TagProvider impl
|
|
|
|
// Returns the active frame tag depending on the timeline status
|
|
|
|
// E.g. if other frame tags are collapsed, the focused band has
|
2015-03-11 03:25:20 +08:00
|
|
|
// priority and tags in other bands are ignored.
|
2023-06-09 06:00:49 +08:00
|
|
|
Tag* getTagByFrame(const frame_t frame, const bool getLoopTagIfNone) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-06-09 06:00:49 +08:00
|
|
|
// ScrollableViewDelegate impl
|
2013-12-11 11:34:16 +08:00
|
|
|
gfx::Size visibleSize() const override;
|
2023-06-09 06:00:49 +08:00
|
|
|
gfx::Point viewScroll() const override;
|
2015-01-20 20:38:39 +08:00
|
|
|
void setViewScroll(const gfx::Point& pt) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2019-10-02 01:55:08 +08:00
|
|
|
void lockRange();
|
2014-03-30 23:53:57 +08:00
|
|
|
void unlockRange();
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-08-08 21:33:45 +08:00
|
|
|
void clearAndInvalidateRange();
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2025-08-20 00:26:12 +08:00
|
|
|
void refresh();
|
|
|
|
|
2013-12-16 04:26:29 +08:00
|
|
|
protected:
|
|
|
|
bool onProcessMessage(ui::Message* msg) override;
|
2015-03-10 03:41:03 +08:00
|
|
|
void onInitTheme(ui::InitThemeEvent& ev) override;
|
2018-03-30 03:13:10 +08:00
|
|
|
void onInvalidateRegion(const gfx::Region& region) override;
|
2023-06-06 04:25:01 +08:00
|
|
|
void onSizeHint(ui::SizeHintEvent& ev) override;
|
2018-03-30 03:25:43 +08:00
|
|
|
void onResize(ui::ResizeEvent& ev) override;
|
2015-03-11 03:25:20 +08:00
|
|
|
void onPaint(ui::PaintEvent& ev) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-03-10 03:41:03 +08:00
|
|
|
// DocObserver impl.
|
|
|
|
void onGeneralUpdate(DocEvent& ev) override;
|
2023-06-06 04:25:01 +08:00
|
|
|
void onAddLayer(DocEvent& ev) override;
|
2013-11-11 05:27:11 +08:00
|
|
|
void onBeforeRemoveLayer(DocEvent& ev) override;
|
2023-05-10 09:08:37 +08:00
|
|
|
void onAfterRemoveLayer(DocEvent& ev) override;
|
2023-06-06 04:25:01 +08:00
|
|
|
void onAddFrame(DocEvent& ev) override;
|
|
|
|
void onRemoveFrame(DocEvent& ev) override;
|
|
|
|
void onAddCel(DocEvent& ev) override;
|
|
|
|
void onAfterRemoveCel(DocEvent& ev) override;
|
|
|
|
void onLayerNameChange(DocEvent& ev) override;
|
2014-07-22 09:59:45 +08:00
|
|
|
void onAddTag(DocEvent& ev) override;
|
2023-06-06 04:25:01 +08:00
|
|
|
void onRemoveTag(DocEvent& ev) override;
|
2014-07-22 09:59:45 +08:00
|
|
|
void onTagChange(DocEvent& ev) override;
|
2024-11-22 01:07:03 +08:00
|
|
|
void onTagRename(DocEvent& ev) override;
|
2016-08-25 23:31:00 +08:00
|
|
|
void onLayerCollapsedChanged(DocEvent& ev) override;
|
2015-02-15 20:48:38 +08:00
|
|
|
void onAfterLayerVisibilityChange(DocEvent& ev) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-02-17 22:43:25 +08:00
|
|
|
// app::Context slots.
|
2016-08-07 15:18:24 +08:00
|
|
|
void onBeforeCommandExecution(CommandExecutionEvent& ev);
|
2016-08-04 09:13:04 +08:00
|
|
|
void onAfterCommandExecution(CommandExecutionEvent& ev);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-03-27 08:52:50 +08:00
|
|
|
// ContextObserver impl
|
2016-07-25 20:51:58 +08:00
|
|
|
void onActiveSiteChange(const Site& site) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-07-25 20:51:58 +08:00
|
|
|
// DocsObserver impl.
|
|
|
|
void onRemoveDocument(Doc* document) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-07-29 03:44:21 +08:00
|
|
|
// EditorObserver impl.
|
2017-11-29 08:16:37 +08:00
|
|
|
void onStateChanged(Editor* editor) override;
|
|
|
|
void onAfterFrameChanged(Editor* editor) override;
|
|
|
|
void onAfterLayerChanged(Editor* editor) override;
|
2013-11-11 09:59:25 +08:00
|
|
|
void onDestroyEditor(Editor* editor) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-12-02 04:14:18 +08:00
|
|
|
// InputChainElement impl
|
2021-11-24 16:49:20 +08:00
|
|
|
void onNewInputPriority(InputChainElement* element, const ui::Message* msg) override;
|
|
|
|
bool onCanCut(Context* ctx) override;
|
2015-05-10 06:55:33 +08:00
|
|
|
bool onCanCopy(Context* ctx) override;
|
2021-11-24 16:49:20 +08:00
|
|
|
bool onCanPaste(Context* ctx) override;
|
|
|
|
bool onCanClear(Context* ctx) override;
|
|
|
|
bool onCut(Context* ctx) override;
|
2015-05-10 06:55:33 +08:00
|
|
|
bool onCopy(Context* ctx) override;
|
2021-11-24 16:49:20 +08:00
|
|
|
bool onPaste(Context* ctx, const gfx::Point* position) override;
|
|
|
|
bool onClear(Context* ctx) override;
|
2015-03-10 03:41:03 +08:00
|
|
|
void onCancel(Context* ctx) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-03-10 03:41:03 +08:00
|
|
|
void onDragEnter(ui::DragEvent& e) override;
|
2016-11-23 05:05:56 +08:00
|
|
|
void onDragLeave(ui::DragEvent& e) override;
|
2014-08-08 21:33:45 +08:00
|
|
|
void onDrag(ui::DragEvent& e) override;
|
2014-08-28 09:43:24 +08:00
|
|
|
void onDrop(ui::DragEvent& e) override;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-08-28 09:43:24 +08:00
|
|
|
private:
|
|
|
|
struct DrawCelData;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-07-25 20:51:58 +08:00
|
|
|
struct Hit {
|
|
|
|
int part;
|
2016-08-25 23:31:00 +08:00
|
|
|
layer_t layer;
|
2023-06-06 04:25:01 +08:00
|
|
|
col_t frame;
|
2020-12-30 21:25:37 +08:00
|
|
|
ObjectId tag;
|
|
|
|
bool veryBottom;
|
|
|
|
int band;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-03-30 07:36:41 +08:00
|
|
|
Hit(int part = 0,
|
|
|
|
layer_t layer = -1,
|
2020-12-30 21:25:37 +08:00
|
|
|
col_t frame = kNoCol,
|
|
|
|
ObjectId tag = NullId,
|
|
|
|
int band = -1);
|
2023-06-06 04:25:01 +08:00
|
|
|
bool operator!=(const Hit& other) const;
|
|
|
|
Tag* getTag() const;
|
2013-11-11 05:27:11 +08:00
|
|
|
};
|
|
|
|
|
2017-12-02 04:14:18 +08:00
|
|
|
struct DropTarget {
|
|
|
|
enum HHit { HNone, Before, After };
|
|
|
|
enum VHit { VNone, Bottom, Top, FirstChild, VeryBottom };
|
2020-04-17 23:29:48 +08:00
|
|
|
DropTarget();
|
2018-06-13 04:11:10 +08:00
|
|
|
DropTarget(const DropTarget& o);
|
2020-04-17 23:29:48 +08:00
|
|
|
bool operator!=(const DropTarget& o) const
|
2024-12-17 01:52:19 +08:00
|
|
|
{
|
2018-06-13 04:11:10 +08:00
|
|
|
return (hhit != o.hhit || vhit != o.vhit || outside != o.outside);
|
2017-12-02 04:14:18 +08:00
|
|
|
}
|
2014-07-22 09:59:45 +08:00
|
|
|
HHit hhit;
|
|
|
|
VHit vhit;
|
2018-06-13 04:11:10 +08:00
|
|
|
bool outside;
|
2024-12-17 01:52:19 +08:00
|
|
|
};
|
|
|
|
|
2017-04-13 03:11:35 +08:00
|
|
|
struct Row {
|
2024-12-17 01:52:19 +08:00
|
|
|
Row();
|
2017-11-29 08:16:37 +08:00
|
|
|
Row(Layer* layer, const int level, const LayerFlags inheritedFlags);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-04-13 03:24:43 +08:00
|
|
|
Layer* layer() const { return m_layer; }
|
|
|
|
int level() const { return m_level; }
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-06-09 06:00:49 +08:00
|
|
|
bool parentVisible() const;
|
|
|
|
bool parentEditable() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-12-02 04:14:18 +08:00
|
|
|
private:
|
|
|
|
Layer* m_layer;
|
|
|
|
int m_level;
|
|
|
|
LayerFlags m_inheritedFlags;
|
|
|
|
};
|
|
|
|
|
2023-09-16 06:53:31 +08:00
|
|
|
void handleRangeMouseDown(const ui::Message* msg,
|
2014-07-22 09:59:45 +08:00
|
|
|
const Range::Type rangeType,
|
2023-09-16 06:53:31 +08:00
|
|
|
doc::Layer* fromLayer,
|
2023-06-06 04:25:01 +08:00
|
|
|
const col_t fromFrame);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-09-16 06:53:31 +08:00
|
|
|
void handleRangeMouseMove(doc::Layer* fromLayer, const col_t fromFrame);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2024-12-06 09:18:43 +08:00
|
|
|
bool selectedLayersBounds(const SelectedLayers& layers, layer_t* first, layer_t* last) const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-09-18 03:39:55 +08:00
|
|
|
void setLayer(Layer* layer);
|
2023-06-06 04:25:01 +08:00
|
|
|
void setFrame(col_t frame, bool byUser);
|
2014-04-30 09:51:14 +08:00
|
|
|
bool allLayersVisible();
|
|
|
|
bool allLayersInvisible();
|
|
|
|
bool allLayersLocked();
|
|
|
|
bool allLayersUnlocked();
|
2015-01-20 20:38:39 +08:00
|
|
|
bool allLayersContinuous();
|
|
|
|
bool allLayersDiscontinuous();
|
2013-11-11 07:29:51 +08:00
|
|
|
void detachDocument();
|
2015-03-11 03:25:20 +08:00
|
|
|
void setCursor(ui::Message* msg, const Hit& hit);
|
2024-12-06 09:18:43 +08:00
|
|
|
bool getDrawableLayers(layer_t* firstLayer, layer_t* lastLayer);
|
2023-06-06 04:25:01 +08:00
|
|
|
void getDrawableFrames(col_t* firstFrame, col_t* lastFrame);
|
|
|
|
bool getTagFrames(const doc::Tag* tag, col_t* fromFrame, col_t* toFrame) const;
|
2013-12-11 11:34:16 +08:00
|
|
|
void drawPart(ui::Graphics* g,
|
2020-12-30 21:25:37 +08:00
|
|
|
const gfx::Rect& bounds,
|
2017-03-14 05:13:38 +08:00
|
|
|
const std::string* text,
|
|
|
|
ui::Style* style,
|
|
|
|
const bool is_active = false,
|
|
|
|
const bool is_hover = false,
|
|
|
|
const bool is_clicked = false,
|
|
|
|
const bool is_disabled = false);
|
2015-03-10 00:57:16 +08:00
|
|
|
void drawTop(ui::Graphics* g);
|
2013-12-11 11:34:16 +08:00
|
|
|
void drawHeader(ui::Graphics* g);
|
2023-06-09 06:00:49 +08:00
|
|
|
void drawHeaderFrame(ui::Graphics* g, const col_t col);
|
2023-05-10 09:08:37 +08:00
|
|
|
void drawLayer(ui::Graphics* g, const layer_t layerIdx);
|
|
|
|
void drawCel(ui::Graphics* g,
|
2023-06-09 06:00:49 +08:00
|
|
|
const layer_t layerIdx,
|
|
|
|
const col_t col,
|
2023-05-10 09:08:37 +08:00
|
|
|
const Cel* cel,
|
|
|
|
const DrawCelData* data);
|
2015-01-20 20:38:39 +08:00
|
|
|
void drawCelLinkDecorators(ui::Graphics* g,
|
2020-12-30 21:25:37 +08:00
|
|
|
const gfx::Rect& bounds,
|
2023-05-10 09:08:37 +08:00
|
|
|
const Cel* cel,
|
2023-06-09 06:00:49 +08:00
|
|
|
const col_t col,
|
2017-03-14 05:13:38 +08:00
|
|
|
const bool is_active,
|
2023-05-10 09:08:37 +08:00
|
|
|
const bool is_hover,
|
|
|
|
const DrawCelData* data);
|
2013-12-11 11:34:16 +08:00
|
|
|
void drawTags(ui::Graphics* g);
|
2020-12-30 21:25:37 +08:00
|
|
|
void drawTagBraces(ui::Graphics* g,
|
|
|
|
gfx::Color tagColor,
|
|
|
|
const gfx::Rect& bounds,
|
|
|
|
const gfx::Rect& clipBounds);
|
2025-04-28 22:20:48 +08:00
|
|
|
void paintDropFrameDeco(ui::Graphics* g, ui::PaintWidgetPartInfo info, gfx::Rect dropBounds);
|
|
|
|
void paintDropLayerDeco(ui::Graphics* g,
|
|
|
|
const ui::PaintWidgetPartInfo& info,
|
|
|
|
gfx::Rect dropBounds);
|
2013-12-11 11:34:16 +08:00
|
|
|
void drawRangeOutline(ui::Graphics* g);
|
|
|
|
void drawPaddings(ui::Graphics* g);
|
2023-06-06 04:25:01 +08:00
|
|
|
bool drawPart(ui::Graphics* g, int part, layer_t layer, col_t frame);
|
2013-12-11 11:34:16 +08:00
|
|
|
void drawClipboardRange(ui::Graphics* g);
|
2013-12-16 04:26:29 +08:00
|
|
|
gfx::Rect getLayerHeadersBounds() const;
|
|
|
|
gfx::Rect getFrameHeadersBounds() const;
|
2013-12-18 11:01:55 +08:00
|
|
|
gfx::Rect getOnionskinFramesBounds() const;
|
2013-12-16 04:26:29 +08:00
|
|
|
gfx::Rect getCelsBounds() const;
|
2015-03-11 03:25:20 +08:00
|
|
|
gfx::Rect getPartBounds(const Hit& hit) const;
|
2025-04-28 22:20:48 +08:00
|
|
|
gfx::Rect getSelectedFramesBounds(const Range& range) const;
|
|
|
|
gfx::Rect getSelectedLayersBounds(const Range& range) const;
|
2014-07-22 09:59:45 +08:00
|
|
|
gfx::Rect getRangeBounds(const Range& range) const;
|
2018-03-30 03:21:43 +08:00
|
|
|
gfx::Rect getRangeClipBounds(const Range& range) const;
|
2023-06-06 04:25:01 +08:00
|
|
|
int getFrameXPos(const col_t frame) const;
|
|
|
|
int getFrameWidth(const col_t frame) const;
|
|
|
|
col_t getFrameInXPos(const int x) const;
|
2015-03-10 03:41:03 +08:00
|
|
|
void invalidateHit(const Hit& hit);
|
2023-05-10 09:08:37 +08:00
|
|
|
void invalidateLayer(const Layer* layer);
|
2023-06-06 04:25:01 +08:00
|
|
|
void invalidateFrame(const col_t frame);
|
2019-09-06 02:03:13 +08:00
|
|
|
void invalidateRange();
|
2017-07-26 02:26:32 +08:00
|
|
|
void regenerateCols();
|
2017-04-13 03:46:40 +08:00
|
|
|
void regenerateRows();
|
2017-03-27 08:52:50 +08:00
|
|
|
void regenerateTagBands();
|
2017-03-30 07:36:41 +08:00
|
|
|
int visibleTagBands() const;
|
2015-09-18 02:19:47 +08:00
|
|
|
void updateScrollBars();
|
2015-03-11 03:25:20 +08:00
|
|
|
void updateByMousePos(ui::Message* msg, const gfx::Point& mousePos);
|
2015-03-10 03:41:03 +08:00
|
|
|
Hit hitTest(ui::Message* msg, const gfx::Point& mousePos);
|
2015-08-20 21:51:41 +08:00
|
|
|
Hit hitTestCel(const gfx::Point& mousePos);
|
2015-03-11 03:25:20 +08:00
|
|
|
void setHot(const Hit& hit);
|
2023-06-06 04:25:01 +08:00
|
|
|
void showCel(layer_t layer, col_t frame);
|
2022-04-25 23:54:13 +08:00
|
|
|
void showCurrentCel();
|
2017-04-15 00:18:01 +08:00
|
|
|
void focusTagBand(int band);
|
2013-11-11 05:27:11 +08:00
|
|
|
void cleanClk();
|
2015-09-18 02:19:47 +08:00
|
|
|
gfx::Size getScrollableSize() const;
|
|
|
|
gfx::Point getMaxScrollablePos() const;
|
2016-08-25 23:31:00 +08:00
|
|
|
doc::Layer* getLayer(int layerIndex) const;
|
|
|
|
layer_t getLayerIndex(const Layer* layer) const;
|
|
|
|
bool isLayerActive(const layer_t layerIdx) const;
|
2023-06-06 04:25:01 +08:00
|
|
|
bool isFrameActive(const col_t frame) const;
|
|
|
|
bool isCelActive(const layer_t layerIdx, const col_t frame) const;
|
|
|
|
bool isCelLooselyActive(const layer_t layerIdx, const col_t frame) const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-07-22 09:59:45 +08:00
|
|
|
void updateStatusBar(ui::Message* msg);
|
2023-06-06 04:25:01 +08:00
|
|
|
void updateStatusBarForFrame(const col_t frame, const Tag* tag, const Cel* cel);
|
2014-07-22 09:59:45 +08:00
|
|
|
void updateDropRange(const gfx::Point& pt);
|
2014-08-08 21:33:45 +08:00
|
|
|
void clearClipboardRange();
|
2023-06-09 06:00:49 +08:00
|
|
|
void resetAllRanges();
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-07-25 10:50:45 +08:00
|
|
|
// The layer of the bottom (e.g. Background layer)
|
2023-06-06 04:25:01 +08:00
|
|
|
constexpr layer_t firstLayer() const { return 0; }
|
2014-07-25 10:50:45 +08:00
|
|
|
// The layer of the top.
|
2017-04-13 03:11:35 +08:00
|
|
|
layer_t lastLayer() const { return m_rows.size() - 1; }
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-06-06 04:25:01 +08:00
|
|
|
constexpr col_t firstFrame() const { return col_t(0); }
|
|
|
|
col_t lastFrame() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-08-25 23:31:00 +08:00
|
|
|
bool validLayer(layer_t layer) const { return layer >= firstLayer() && layer <= lastLayer(); }
|
2023-06-06 04:25:01 +08:00
|
|
|
bool validFrame(col_t frame) const { return frame >= firstFrame() && frame <= lastFrame(); }
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-03-10 00:57:16 +08:00
|
|
|
int topHeight() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-09-16 06:53:31 +08:00
|
|
|
app::gen::GlobalPref::Timeline& timelinePref() const;
|
2015-02-15 20:48:38 +08:00
|
|
|
DocumentPreferences& docPref() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-08-04 09:13:04 +08:00
|
|
|
// Theme/dimensions
|
2015-02-17 22:43:25 +08:00
|
|
|
skin::SkinTheme* skinTheme() const;
|
2016-08-07 15:18:24 +08:00
|
|
|
int headerBoxWidth() const;
|
2016-08-04 09:13:04 +08:00
|
|
|
int headerBoxHeight() const;
|
|
|
|
int layerBoxHeight() const;
|
|
|
|
int frameBoxWidth() const;
|
|
|
|
int outlineWidth() const;
|
2017-03-27 08:52:50 +08:00
|
|
|
int oneTagHeight() const;
|
2023-06-06 04:25:01 +08:00
|
|
|
col_t calcTagVisibleToFrame(Tag* tag) const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-07-25 20:51:58 +08:00
|
|
|
void updateCelOverlayBounds(const Hit& hit);
|
|
|
|
void drawCelOverlay(ui::Graphics* g);
|
|
|
|
void onThumbnailsPrefChange();
|
2017-11-22 01:30:30 +08:00
|
|
|
void setZoom(const double zoom);
|
|
|
|
void setZoomAndUpdate(const double zoom, const bool updatePref);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-11-22 01:30:30 +08:00
|
|
|
double zoom() const;
|
2019-10-02 01:55:08 +08:00
|
|
|
int tagFramesDuration(const Tag* tag) const;
|
2017-07-29 03:44:21 +08:00
|
|
|
// Calculate the duration of the selected range of frames
|
|
|
|
int selectedFramesDuration() const;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-11-29 08:16:37 +08:00
|
|
|
void setLayerVisibleFlag(const layer_t layer, const bool state);
|
|
|
|
void setLayerEditableFlag(const layer_t layer, const bool state);
|
|
|
|
void setLayerContinuousFlag(const layer_t layer, const bool state);
|
|
|
|
void setLayerCollapsedFlag(const layer_t layer, const bool state);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2020-06-17 01:37:24 +08:00
|
|
|
int separatorX() const;
|
2020-06-12 02:30:06 +08:00
|
|
|
void setSeparatorX(int newValue);
|
2023-06-09 06:00:49 +08:00
|
|
|
void updateTimelineAdapter(bool allTags);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2020-12-30 21:25:37 +08:00
|
|
|
static gfx::Color highlightColor(const gfx::Color color);
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2023-06-06 04:25:01 +08:00
|
|
|
std::unique_ptr<view::TimelineAdapter> m_adapter;
|
2015-09-18 02:19:47 +08:00
|
|
|
ui::ScrollBar m_hbar;
|
|
|
|
ui::ScrollBar m_vbar;
|
|
|
|
gfx::Rect m_viewportArea;
|
2016-08-04 09:14:33 +08:00
|
|
|
double m_zoom;
|
2025-04-01 05:43:27 +08:00
|
|
|
bool m_scaleUpToFit;
|
2013-11-11 05:27:11 +08:00
|
|
|
Context* m_context;
|
2015-04-01 04:31:45 +08:00
|
|
|
Editor* m_editor;
|
2018-07-07 22:54:44 +08:00
|
|
|
Doc* m_document;
|
2013-11-11 05:27:11 +08:00
|
|
|
Sprite* m_sprite;
|
|
|
|
Layer* m_layer;
|
2023-06-06 04:25:01 +08:00
|
|
|
col_t m_frame;
|
2017-12-02 04:14:18 +08:00
|
|
|
int m_rangeLocks;
|
2023-06-09 06:00:49 +08:00
|
|
|
VirtualRange m_range;
|
|
|
|
VirtualRange m_startRange;
|
|
|
|
VirtualRange m_dropRange;
|
2013-11-11 05:27:11 +08:00
|
|
|
State m_state;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2021-11-24 16:49:20 +08:00
|
|
|
// Version of the sprite before executing a command. Used to check
|
|
|
|
// if the sprite was modified after executing a command to avoid
|
2021-06-09 06:46:37 +08:00
|
|
|
// regenerating all rows if it's not necessary.
|
2021-11-24 16:49:20 +08:00
|
|
|
doc::ObjectVersion m_savedVersion;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-07-26 02:26:32 +08:00
|
|
|
// Data used to display columns in the timeline
|
2023-06-06 04:25:01 +08:00
|
|
|
col_t m_ncols;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-04-13 03:11:35 +08:00
|
|
|
// Data used to display each row in the timeline
|
|
|
|
std::vector<Row> m_rows;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2017-03-27 08:52:50 +08:00
|
|
|
// Data used to display frame tags
|
2017-03-27 08:54:08 +08:00
|
|
|
int m_tagBands;
|
2017-03-30 07:36:41 +08:00
|
|
|
int m_tagFocusBand;
|
2019-10-02 01:55:08 +08:00
|
|
|
std::map<Tag*, int> m_tagBand;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2013-11-11 05:27:11 +08:00
|
|
|
int m_separator_x;
|
|
|
|
int m_separator_w;
|
2013-12-18 11:01:55 +08:00
|
|
|
int m_origFrames;
|
2015-03-10 03:41:03 +08:00
|
|
|
Hit m_hot; // The 'hot' part is where the mouse is on top of
|
2014-07-22 09:59:45 +08:00
|
|
|
DropTarget m_dropTarget;
|
2015-03-10 03:41:03 +08:00
|
|
|
Hit m_clk; // The 'clk' part is where the mouse's button was pressed (maybe for a drag & drop
|
2014-04-10 08:56:06 +08:00
|
|
|
// operation)
|
|
|
|
// Absolute mouse positions for scrolling.
|
2014-02-03 05:46:19 +08:00
|
|
|
gfx::Point m_oldPos;
|
2014-05-18 08:27:44 +08:00
|
|
|
// Configure timeline
|
2021-05-29 02:08:17 +08:00
|
|
|
std::unique_ptr<ConfigureTimelinePopup> m_confPopup;
|
2021-06-09 06:46:37 +08:00
|
|
|
obs::scoped_connection m_ctxConn1, m_ctxConn2;
|
2016-11-23 05:05:56 +08:00
|
|
|
obs::connection m_firstFrameConn;
|
2023-05-17 01:30:08 +08:00
|
|
|
obs::connection m_onionskinConn;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-08-08 21:33:45 +08:00
|
|
|
// Marching ants stuff to show the range in the clipboard.
|
|
|
|
// TODO merge this with the marching ants of the sprite editor (ui::Editor)
|
|
|
|
ui::Timer m_clipboard_timer;
|
|
|
|
int m_offset_count;
|
2017-07-19 04:07:35 +08:00
|
|
|
bool m_redrawMarchingAntsOnly;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2014-08-28 09:43:24 +08:00
|
|
|
bool m_scroll; // True if the drag-and-drop operation is a scroll operation.
|
|
|
|
bool m_copy; // True if the drag-and-drop operation is a copy.
|
2015-09-18 03:39:55 +08:00
|
|
|
bool m_fromTimeline;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-04-07 21:48:04 +08:00
|
|
|
AniControls m_aniControls;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2016-07-25 21:17:53 +08:00
|
|
|
// Data used for thumbnails.
|
2016-07-25 20:51:58 +08:00
|
|
|
bool m_thumbnailsOverlayVisible;
|
2019-04-12 01:29:20 +08:00
|
|
|
gfx::Rect m_thumbnailsOverlayBounds;
|
2016-07-25 20:51:58 +08:00
|
|
|
Hit m_thumbnailsOverlayHit;
|
|
|
|
gfx::Point m_thumbnailsOverlayDirection;
|
2016-09-26 22:39:40 +08:00
|
|
|
obs::connection m_thumbnailsPrefConn;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-08-05 20:40:11 +08:00
|
|
|
// Temporal data used to move the range.
|
|
|
|
struct MoveRange {
|
2016-08-25 23:31:00 +08:00
|
|
|
layer_t activeRelativeLayer;
|
2023-06-06 04:25:01 +08:00
|
|
|
col_t activeRelativeFrame;
|
2015-08-05 20:40:11 +08:00
|
|
|
} m_moveRangeData;
|
2024-12-17 01:52:19 +08:00
|
|
|
|
2015-08-05 20:40:11 +08:00
|
|
|
// Temporal data used to move tags.
|
2020-12-30 21:25:37 +08:00
|
|
|
struct ResizeTag {
|
2023-06-09 06:00:49 +08:00
|
|
|
doc::ObjectId tag = doc::NullId;
|
2023-06-06 04:25:01 +08:00
|
|
|
col_t from, to;
|
2023-06-09 06:00:49 +08:00
|
|
|
void reset() { tag = doc::NullId; }
|
2023-06-06 04:25:01 +08:00
|
|
|
void reset(const view::TimelineAdapter& adapter, const doc::ObjectId tagId)
|
2024-12-17 01:52:19 +08:00
|
|
|
{
|
2023-06-09 06:00:49 +08:00
|
|
|
if (auto t = doc::get<doc::Tag>(tagId)) {
|
|
|
|
tag = tagId;
|
|
|
|
from = adapter.toColFrame(fr_t(t->fromFrame()));
|
|
|
|
to = adapter.toColFrame(fr_t(t->toFrame()));
|
2024-12-17 01:52:19 +08:00
|
|
|
}
|
|
|
|
else {
|
2023-06-09 06:00:49 +08:00
|
|
|
tag = doc::NullId;
|
2024-12-17 01:52:19 +08:00
|
|
|
}
|
|
|
|
}
|
2020-12-30 21:25:37 +08:00
|
|
|
} m_resizeTagData;
|
2024-12-17 01:52:19 +08:00
|
|
|
};
|
|
|
|
|
2017-12-02 04:14:18 +08:00
|
|
|
class LockTimelineRange {
|
2024-12-17 01:52:19 +08:00
|
|
|
public:
|
2017-12-02 04:14:18 +08:00
|
|
|
LockTimelineRange(Timeline* timeline) : m_timeline(timeline)
|
2024-12-17 01:52:19 +08:00
|
|
|
{
|
2020-04-17 23:29:48 +08:00
|
|
|
if (m_timeline)
|
|
|
|
m_timeline->lockRange();
|
2024-12-17 01:52:19 +08:00
|
|
|
}
|
2017-12-02 04:14:18 +08:00
|
|
|
~LockTimelineRange()
|
2024-12-17 01:52:19 +08:00
|
|
|
{
|
2020-04-17 23:29:48 +08:00
|
|
|
if (m_timeline)
|
|
|
|
m_timeline->unlockRange();
|
2024-12-17 01:52:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2017-12-02 04:14:18 +08:00
|
|
|
Timeline* m_timeline;
|
2024-12-17 01:52:19 +08:00
|
|
|
};
|
|
|
|
|
2013-11-11 05:27:11 +08:00
|
|
|
} // namespace app
|
|
|
|
|
|
|
|
#endif
|