base pointer movement in timeline
This commit is contained in:
@@ -84,6 +84,11 @@ rational rational::flipped() const
|
||||
return rational(denom, numer);
|
||||
}
|
||||
|
||||
bool rational::isNull() const
|
||||
{
|
||||
return denominator() == 0;
|
||||
}
|
||||
|
||||
//Function: get active instances
|
||||
|
||||
int rational::getActiveInstances()
|
||||
|
||||
@@ -96,6 +96,9 @@ public:
|
||||
|
||||
// Produce "flipped" version
|
||||
rational flipped() const;
|
||||
|
||||
// Returns whether the rational is null or not
|
||||
bool isNull() const;
|
||||
|
||||
//Function: print number to cout
|
||||
void print(ostream &out = cout) const;
|
||||
|
||||
@@ -63,6 +63,7 @@ void TimelineOutput::AttachTimeline(TimelinePanel *timeline)
|
||||
|
||||
//disconnect(view, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SLOT(InsertBlockAtIndex(Block*, int)));
|
||||
disconnect(view, SIGNAL(RequestPlaceBlock(Block*, rational, int)), this, SLOT(PlaceBlock(Block*, rational, int)));
|
||||
disconnect(view, SIGNAL(RequestReplaceBlock(Block*, Block*, int)), this, SLOT(ReplaceBlock(Block*, Block*, int)));
|
||||
|
||||
// Remove existing UI objects from TimelinePanel
|
||||
attached_timeline_->Clear();
|
||||
@@ -84,6 +85,7 @@ void TimelineOutput::AttachTimeline(TimelinePanel *timeline)
|
||||
|
||||
//connect(view, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SLOT(InsertBlockAtIndex(Block*, int)));
|
||||
connect(view, SIGNAL(RequestPlaceBlock(Block*, rational, int)), this, SLOT(PlaceBlock(Block*, rational, int)));
|
||||
connect(view, SIGNAL(RequestReplaceBlock(Block*, Block*, int)), this, SLOT(ReplaceBlock(Block*, Block*, int)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,9 +242,16 @@ void TimelineOutput::TrackEdgeRemoved(NodeEdgePtr edge)
|
||||
|
||||
void TimelineOutput::PlaceBlock(Block *block, rational start, int track)
|
||||
{
|
||||
Q_ASSERT(track >= 0);
|
||||
|
||||
while (track >= track_cache_.size()) {
|
||||
AddTrack();
|
||||
}
|
||||
|
||||
track_cache_.at(track)->PlaceBlock(block, start);
|
||||
}
|
||||
|
||||
void TimelineOutput::ReplaceBlock(Block *old, Block *replace, int track)
|
||||
{
|
||||
track_cache_.at(track)->ReplaceBlock(old, replace);
|
||||
}
|
||||
|
||||
@@ -101,9 +101,17 @@ private slots:
|
||||
|
||||
/**
|
||||
* @brief Forwards a PlaceBlock signal to the requested track
|
||||
*
|
||||
* If the track index doesn't exist, tracks are automatically created until a track at that index does exist
|
||||
* (provided the track index is positive). A negative track index fails immediately.
|
||||
*/
|
||||
void PlaceBlock(Block* block, rational start, int track);
|
||||
|
||||
/**
|
||||
* @brief Forwards a ReplaceBlock signal to the appropriate track
|
||||
*/
|
||||
void ReplaceBlock(Block* old, Block* replace, int track);
|
||||
|
||||
};
|
||||
|
||||
#endif // TIMELINEOUTPUT_H
|
||||
|
||||
@@ -245,12 +245,12 @@ void TrackOutput::AddBlockToGraph(Block *block)
|
||||
|
||||
void TrackOutput::PlaceBlock(Block *block, rational start)
|
||||
{
|
||||
AddBlockToGraph(block);
|
||||
|
||||
if (block->in() == start) {
|
||||
if (block_cache_.contains(block) && block->in() == start) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddBlockToGraph(block);
|
||||
|
||||
// Check if the placement location is past the end of the timeline
|
||||
if (start >= in()) {
|
||||
if (start > in()) {
|
||||
@@ -408,3 +408,22 @@ void TrackOutput::RippleRemoveArea(rational in, rational out, Block *insert)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::ReplaceBlock(Block *old, Block *replace)
|
||||
{
|
||||
Block* previous = old->previous();
|
||||
Block* next = old->next();
|
||||
|
||||
AddBlockToGraph(replace);
|
||||
|
||||
// Disconnect old block from its surroundings
|
||||
if (previous != nullptr) {
|
||||
Block::DisconnectBlocks(previous, old);
|
||||
Block::ConnectBlocks(previous, replace);
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
Block::DisconnectBlocks(old, next);
|
||||
Block::ConnectBlocks(replace, next);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,13 @@ public:
|
||||
*/
|
||||
void RippleRemoveArea(rational in, rational out, Block* insert = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Replaces Block `old` with Block `replace`
|
||||
*
|
||||
* Makes no modification to the lengths of either Blocks
|
||||
*/
|
||||
void ReplaceBlock(Block* old, Block* replace);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when a Block is added to this Track
|
||||
|
||||
@@ -43,9 +43,8 @@ TimelineView::TimelineView(QWidget *parent) :
|
||||
|
||||
connect(&scene_, SIGNAL(changed(const QList<QRectF>&)), this, SLOT(UpdateSceneRect()));
|
||||
|
||||
// Create playhead line and ensure it's always on top
|
||||
// Create playhead line
|
||||
playhead_line_ = new TimelineViewPlayheadItem();
|
||||
playhead_line_->setZValue(100);
|
||||
|
||||
scene_.addItem(playhead_line_);
|
||||
|
||||
@@ -267,6 +266,7 @@ void TimelineView::UpdateSceneRect()
|
||||
bounding_rect.setTopLeft(QPointF(0, 0));
|
||||
|
||||
// Ensure the scene height is always AT LEAST the height of the view
|
||||
// The scrollbar appears to have a 1px margin on the top and bottom, hence the -2
|
||||
int minimum_height = height() - horizontalScrollBar()->height() - 2;
|
||||
if (bounding_rect.height() < minimum_height) {
|
||||
bounding_rect.setHeight(minimum_height);
|
||||
@@ -283,39 +283,3 @@ void TimelineView::UpdateSceneRect()
|
||||
scene_.setSceneRect(bounding_rect);
|
||||
}
|
||||
|
||||
TimelineView::Tool::Tool(TimelineView *parent) :
|
||||
dragging_(false),
|
||||
parent_(parent)
|
||||
{
|
||||
}
|
||||
|
||||
TimelineView::Tool::~Tool(){}
|
||||
|
||||
void TimelineView::Tool::MousePress(QMouseEvent *){}
|
||||
|
||||
void TimelineView::Tool::MouseMove(QMouseEvent *){}
|
||||
|
||||
void TimelineView::Tool::MouseRelease(QMouseEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragEnter(QDragEnterEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragMove(QDragMoveEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragLeave(QDragLeaveEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragDrop(QDropEvent *){}
|
||||
|
||||
TimelineView *TimelineView::Tool::parent()
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
QPointF TimelineView::Tool::GetScenePos(const QPoint &screen_pos)
|
||||
{
|
||||
return parent()->mapToScene(screen_pos);
|
||||
}
|
||||
|
||||
QGraphicsItem *TimelineView::Tool::GetItemAtScenePos(const QPointF &scene_pos)
|
||||
{
|
||||
return parent()->scene_.itemAt(scene_pos, parent()->transform());
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ public slots:
|
||||
|
||||
signals:
|
||||
void RequestPlaceBlock(Block* block, rational start, int track);
|
||||
void RequestReplaceBlock(Block* old, Block* replace, int track);
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
@@ -97,6 +98,8 @@ private:
|
||||
|
||||
QGraphicsItem* GetItemAtScenePos(const QPointF& scene_pos);
|
||||
|
||||
rational ValidateMovement(rational movement, const QVector<TimelineViewGhostItem*> ghosts);
|
||||
|
||||
bool dragging_;
|
||||
|
||||
QPointF drag_start_;
|
||||
|
||||
@@ -29,7 +29,8 @@ TimelineViewPlayheadItem::TimelineViewPlayheadItem(QGraphicsItem *parent) :
|
||||
TimelineViewRect(parent),
|
||||
playhead_(0)
|
||||
{
|
||||
|
||||
// Ensure this item is always on top
|
||||
setZValue(100);
|
||||
}
|
||||
|
||||
void TimelineViewPlayheadItem::SetPlayhead(const int64_t &playhead)
|
||||
|
||||
@@ -18,5 +18,6 @@ set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/timelineview/tool/import.cpp
|
||||
widget/timelineview/tool/pointer.cpp
|
||||
widget/timelineview/tool/tool.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -51,7 +51,8 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event)
|
||||
drag_start_ = GetScenePos(event->pos());
|
||||
|
||||
// Set ghosts to start where the cursor entered
|
||||
rational ghost_start = parent()->SceneToTime(drag_start_.x());
|
||||
// FIXME: 100 = magic number so that imported clips are not right on the cursor when dragged in
|
||||
rational ghost_start = parent()->SceneToTime(drag_start_.x() - 100);
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
stream >> r >> item_ptr;
|
||||
@@ -92,22 +93,24 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event)
|
||||
void TimelineView::ImportTool::DragMove(QDragMoveEvent *event)
|
||||
{
|
||||
if (parent()->HasGhosts()) {
|
||||
QPointF pos = GetScenePos(event->pos());
|
||||
QPointF movement = pos - drag_start_;
|
||||
|
||||
rational time_movement = parent()->SceneToTime(movement.x());
|
||||
|
||||
int ghost_track = parent()->SceneToTrack(pos.y());
|
||||
int ghost_y = parent()->GetTrackY(ghost_track);
|
||||
int ghost_height = parent()->GetTrackHeight(ghost_track);
|
||||
|
||||
time_movement = ValidateMovement(time_movement, parent()->ghost_items_);
|
||||
|
||||
// Move ghosts to the mouse cursor
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
QPointF pos = GetScenePos(event->pos());
|
||||
QPointF movement = pos - drag_start_;
|
||||
|
||||
rational time_movement = parent()->SceneToTime(movement.x());
|
||||
|
||||
ghost->SetInAdjustment(time_movement);
|
||||
ghost->SetOutAdjustment(time_movement);
|
||||
|
||||
int ghost_track = parent()->SceneToTrack(pos.y());
|
||||
ghost->SetTrack(ghost_track);
|
||||
|
||||
int ghost_y = parent()->GetTrackY(ghost_track);
|
||||
int ghost_height = parent()->GetTrackHeight(ghost_track);
|
||||
|
||||
ghost->SetY(ghost_y);
|
||||
ghost->SetHeight(ghost_height);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "widget/timelineview/timelineview.h"
|
||||
|
||||
#include "node/block/gap/gap.h"
|
||||
|
||||
TimelineView::PointerTool::PointerTool(TimelineView *parent) :
|
||||
Tool(parent)
|
||||
{
|
||||
@@ -71,6 +73,9 @@ void TimelineView::PointerTool::MouseMove(QMouseEvent *event)
|
||||
ghost->SetScale(parent()->scale_);
|
||||
ghost->SetData(Node::PtrToValue(clip));
|
||||
|
||||
// FIXME: Very bad. Change immediately.
|
||||
ghost->SetTrack(parent()->SceneToTrack(drag_start_.y()));
|
||||
|
||||
ghost->setPos(clip_item->pos());
|
||||
|
||||
parent()->ghost_items_.append(ghost);
|
||||
@@ -89,12 +94,7 @@ void TimelineView::PointerTool::MouseMove(QMouseEvent *event)
|
||||
rational time_movement = parent()->SceneToTime(movement.x());
|
||||
|
||||
// Validate movement
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
rational validator = ghost->In() + time_movement;
|
||||
if (validator < 0) {
|
||||
time_movement = rational(0) - ghost->In();
|
||||
}
|
||||
}
|
||||
time_movement = ValidateMovement(time_movement, parent()->ghost_items_);
|
||||
|
||||
// Perform movement
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
@@ -110,13 +110,24 @@ void TimelineView::PointerTool::MouseRelease(QMouseEvent *event)
|
||||
|
||||
parent()->QGraphicsView::mouseReleaseEvent(event);
|
||||
|
||||
/*
|
||||
QObject block_memory_manager;
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
Block* b = Node::ValueToPtr<Block>(ghost->data());
|
||||
|
||||
emit parent()->RequestPlaceBlock(b, ghost->In());
|
||||
// Replace old Block with a new Gap
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->setParent(&block_memory_manager);
|
||||
gap->set_length(b->length());
|
||||
|
||||
emit parent()->RequestReplaceBlock(b, gap, ghost->Track());
|
||||
}
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
Block* b = Node::ValueToPtr<Block>(ghost->data());
|
||||
|
||||
emit parent()->RequestPlaceBlock(b, ghost->GetAdjustedIn(), ghost->Track());
|
||||
}
|
||||
*/
|
||||
|
||||
parent()->ClearGhosts();
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "widget/timelineview/timelineview.h"
|
||||
|
||||
TimelineView::Tool::Tool(TimelineView *parent) :
|
||||
dragging_(false),
|
||||
parent_(parent)
|
||||
{
|
||||
}
|
||||
|
||||
TimelineView::Tool::~Tool(){}
|
||||
|
||||
void TimelineView::Tool::MousePress(QMouseEvent *){}
|
||||
|
||||
void TimelineView::Tool::MouseMove(QMouseEvent *){}
|
||||
|
||||
void TimelineView::Tool::MouseRelease(QMouseEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragEnter(QDragEnterEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragMove(QDragMoveEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragLeave(QDragLeaveEvent *){}
|
||||
|
||||
void TimelineView::Tool::DragDrop(QDropEvent *){}
|
||||
|
||||
TimelineView *TimelineView::Tool::parent()
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
QPointF TimelineView::Tool::GetScenePos(const QPoint &screen_pos)
|
||||
{
|
||||
return parent()->mapToScene(screen_pos);
|
||||
}
|
||||
|
||||
QGraphicsItem *TimelineView::Tool::GetItemAtScenePos(const QPointF &scene_pos)
|
||||
{
|
||||
return parent()->scene_.itemAt(scene_pos, parent()->transform());
|
||||
}
|
||||
|
||||
rational TimelineView::Tool::ValidateMovement(rational movement, const QVector<TimelineViewGhostItem *> ghosts)
|
||||
{
|
||||
foreach (TimelineViewGhostItem* ghost, ghosts) {
|
||||
rational validator = ghost->In() + movement;
|
||||
if (validator < 0) {
|
||||
movement = rational(0) - ghost->In();
|
||||
}
|
||||
}
|
||||
|
||||
return movement;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ void TimeRuler::SetScroll(int s)
|
||||
void TimeRuler::paintEvent(QPaintEvent *)
|
||||
{
|
||||
// Nothing to paint if the timebase is invalid
|
||||
if (timebase_.denominator() == 0) {
|
||||
if (timebase_.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user