diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp index 364863ef7..9ce8994b4 100644 --- a/app/widget/timelinewidget/tool/add.cpp +++ b/app/widget/timelinewidget/tool/add.cpp @@ -25,6 +25,7 @@ #include "node/generator/shape/shapenode.h" #include "node/generator/solid/solid.h" #include "node/generator/text/textv3.h" +#include "widget/nodeparamview/nodeparamviewundo.h" #include "widget/timelinewidget/timelinewidget.h" #include "widget/timelinewidget/undo/timelineundopointer.h" @@ -94,8 +95,6 @@ void AddTool::MouseMove(TimelineViewMouseEvent *event) void AddTool::MouseRelease(TimelineViewMouseEvent *event) { - const Track::Reference& track = ghost_->GetTrack(); - if (ghost_) { if (!ghost_->GetAdjustedLength().isNull()) { MultiUndoCommand* command = new MultiUndoCommand(); @@ -104,62 +103,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) command->add_child(subtitle_section_command); } - ClipBlock* clip; - if (Core::instance()->GetSelectedAddableObject() == olive::Tool::kAddableSubtitle) { - clip = new SubtitleBlock(); - } else { - clip = new ClipBlock(); - } - clip->set_length_and_media_out(ghost_->GetAdjustedLength()); - clip->SetLabel(olive::Tool::GetAddableObjectName(Core::instance()->GetSelectedAddableObject())); - - NodeGraph* graph = static_cast(parent()->GetConnectedNode()->parent()); - - command->add_child(new NodeAddCommand(graph, clip)); - command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0))); - command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()), - track.index(), - clip, - ghost_->GetAdjustedIn())); - - Node *node_to_add = nullptr; - - switch (Core::instance()->GetSelectedAddableObject()) { - case olive::Tool::kAddableEmpty: - // Empty, nothing to be done - break; - case olive::Tool::kAddableSolid: - { - node_to_add = new SolidGenerator(); - break; - } - case olive::Tool::kAddableShape: - node_to_add = new ShapeNode(); - break; - case olive::Tool::kAddableTitle: - { - node_to_add = new TextGeneratorV3(); - break; - } - case olive::Tool::kAddableBars: - case olive::Tool::kAddableTone: - // Not implemented yet - qWarning() << "Unimplemented add object:" << Core::instance()->GetSelectedAddableObject(); - break; - case olive::Tool::kAddableSubtitle: - // The block itself is the node we want - break; - case olive::Tool::kAddableCount: - // Invalid value, do nothing - break; - } - - if (node_to_add) { - QPointF extra_node_offset(kDefaultDistanceFromOutput, 0); - command->add_child(new NodeAddCommand(graph, node_to_add)); - command->add_child(new NodeEdgeAddCommand(node_to_add, NodeInput(clip, ClipBlock::kBufferIn))); - command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset)); - } + CreateAddableClip(command, parent()->sequence(), ghost_->GetTrack(), ghost_->GetAdjustedIn(), ghost_->GetAdjustedLength()); Core::instance()->undo_stack()->push(command); } @@ -170,6 +114,80 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) } } +Node *AddTool::CreateAddableClip(MultiUndoCommand *command, Sequence *sequence, const Track::Reference &track, const rational &in, const rational &length, const QRectF &rect) +{ + ClipBlock* clip; + if (Core::instance()->GetSelectedAddableObject() == olive::Tool::kAddableSubtitle) { + clip = new SubtitleBlock(); + } else { + clip = new ClipBlock(); + } + clip->set_length_and_media_out(length); + clip->SetLabel(olive::Tool::GetAddableObjectName(Core::instance()->GetSelectedAddableObject())); + + NodeGraph* graph = sequence->parent(); + + command->add_child(new NodeAddCommand(graph, clip)); + command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0))); + command->add_child(new TrackPlaceBlockCommand(sequence->track_list(track.type()), + track.index(), + clip, + in)); + + Node *node_to_add = nullptr; + + switch (Core::instance()->GetSelectedAddableObject()) { + case olive::Tool::kAddableEmpty: + // Empty, nothing to be done + break; + case olive::Tool::kAddableSolid: + { + node_to_add = new SolidGenerator(); + break; + } + case olive::Tool::kAddableShape: + node_to_add = new ShapeNode(); + break; + case olive::Tool::kAddableTitle: + { + node_to_add = new TextGeneratorV3(); + break; + } + case olive::Tool::kAddableBars: + case olive::Tool::kAddableTone: + // Not implemented yet + qWarning() << "Unimplemented add object:" << Core::instance()->GetSelectedAddableObject(); + break; + case olive::Tool::kAddableSubtitle: + // The block itself is the node we want + break; + case olive::Tool::kAddableCount: + // Invalid value, do nothing + break; + } + + if (node_to_add) { + QPointF extra_node_offset(kDefaultDistanceFromOutput, 0); + command->add_child(new NodeAddCommand(graph, node_to_add)); + command->add_child(new NodeEdgeAddCommand(node_to_add, NodeInput(clip, ClipBlock::kBufferIn))); + command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset)); + + if (!rect.isNull()) { + if (ShapeNodeBase *snb = dynamic_cast(node_to_add)) { + NodeInput pos(snb, ShapeNodeBase::kPositionInput); + NodeInput sz(snb, ShapeNodeBase::kSizeInput); + + command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(sz, 0), rect.width())); + command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(sz, 1), rect.height())); + command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(pos, 0), rect.x())); + command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(pos, 1), rect.y())); + } + } + } + + return node_to_add; +} + void AddTool::MouseMoveInternal(const rational &cursor_frame, bool outwards) { // Calculate movement diff --git a/app/widget/timelinewidget/tool/add.h b/app/widget/timelinewidget/tool/add.h index 025d10e12..0320fddd8 100644 --- a/app/widget/timelinewidget/tool/add.h +++ b/app/widget/timelinewidget/tool/add.h @@ -34,6 +34,8 @@ public: virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; + static Node *CreateAddableClip(MultiUndoCommand *command, Sequence *sequence, const Track::Reference &track, const rational &in, const rational &length, const QRectF &rect = QRectF()); + protected: void MouseMoveInternal(const rational& cursor_frame, bool outwards); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index ded1dd4fe..be7e5f9ce 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -37,12 +37,14 @@ #include "common/timecodefunctions.h" #include "config/config.h" #include "core.h" +#include "node/block/gap/gap.h" #include "node/project/project.h" #include "render/rendermanager.h" #include "task/taskmanager.h" #include "viewerpreventsleep.h" #include "widget/menu/menu.h" #include "window/mainwindow/mainwindow.h" +#include "widget/timelinewidget/tool/add.h" #include "widget/timeruler/timeruler.h" namespace olive { @@ -93,6 +95,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped); connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged); connect(display_widget_, &ViewerDisplayWidget::QueueStarved, this, &ViewerWidget::ForceRequeueFromCurrentTime); + connect(display_widget_, &ViewerDisplayWidget::CreateAddableAt, this, &ViewerWidget::CreateAddableAt); connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom); connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate); connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove); @@ -385,6 +388,7 @@ void ViewerWidget::CacheSequenceInOut() void ViewerWidget::SetGizmos(Node *node) { + qDebug() << "setting gizmos to" << node; display_widget_->SetTimeTarget(GetConnectedNode()); display_widget_->SetGizmos(node); } @@ -476,6 +480,47 @@ void ViewerWidget::UpdateAudioProcessor() } } +void ViewerWidget::CreateAddableAt(QRectF f) +{ + if (Sequence *s = dynamic_cast(GetConnectedNode())) { + Track::Type type = Track::kVideo; + int track_index = -1; + TrackList *list = s->track_list(type); + const rational &in = GetTime(); + rational length = OLIVE_CONFIG("DefaultStillLength").value(); + rational out = in + length; + + // Find a free track where we won't overwrite anything + while (true) { + track_index++; + + if (track_index >= list->GetTrackCount()) { + // Just create a new track + break; + } + + Track *track = list->GetTrackAt(track_index); + if (track->IsLocked()) { + continue; + } + + Block *b = track->NearestBlockBeforeOrAt(in); + if (!b || (dynamic_cast(b) && b->out() >= out)) { + break; + } + } + + // Normalize around center of sequence + f.translate(-s->GetVideoParams().width()*0.5, -s->GetVideoParams().height()*0.5); + f.translate(f.width()*0.5, f.height()*0.5); + + MultiUndoCommand *command = new MultiUndoCommand(); + Node *clip = AddTool::CreateAddableClip(command, s, Track::Reference(type, track_index), in, length, f); + Core::instance()->undo_stack()->pushIfHasChildren(command); + SetGizmos(clip); + } +} + void ViewerWidget::CloseAudioProcessor() { audio_processor_.Close(); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 3a297fbc8..f251edcac 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -325,6 +325,8 @@ private slots: void UpdateAudioProcessor(); + void CreateAddableAt(QRectF f); + }; } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 76c5c09e2..376aea676 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -67,9 +67,10 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : show_fps_(false), frames_skipped_(0), show_widget_background_(false), - push_mode_(kPushNull) + push_mode_(kPushNull), + add_band_(nullptr) { - connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::UpdateCursor); + connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged); connect(this, &ViewerDisplayWidget::InnerWidgetMouseMove, this, &ViewerDisplayWidget::EmitColorAtCursor); @@ -105,6 +106,8 @@ void ViewerDisplayWidget::UpdateCursor() { if (Core::instance()->tool() == Tool::kHand) { setCursor(Qt::OpenHandCursor); + } else if (Core::instance()->tool() == Tool::kAdd) { + setCursor(Qt::CrossCursor); } else { unsetCursor(); } @@ -136,6 +139,11 @@ void ViewerDisplayWidget::SetBlank() update(); } +void ViewerDisplayWidget::ToolChanged() +{ + UpdateCursor(); +} + void ViewerDisplayWidget::SetDeinterlacing(bool e) { deinterlace_ = e; @@ -235,7 +243,16 @@ void ViewerDisplayWidget::IncrementSkippedFrames() void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { - if (event->button() == Qt::LeftButton && gizmos_ + if (event->button() == Qt::LeftButton && Core::instance()->tool() == Tool::kAdd + && (Core::instance()->GetSelectedAddableObject() == Tool::kAddableShape || Core::instance()->GetSelectedAddableObject() == Tool::kAddableTitle)) { + + add_band_start_ = event->pos(); + + add_band_ = new QRubberBand(QRubberBand::Rectangle, this); + add_band_->setGeometry(QRect(add_band_start_, add_band_start_)); + add_band_->show(); + + } else if (event->button() == Qt::LeftButton && gizmos_ && (current_gizmo_ = TryGizmoPress(gizmo_db_, TransformViewerSpaceToBufferSpace(event->pos())))) { // Handle gizmo click @@ -274,6 +291,10 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) hand_last_drag_pos_ = event->pos(); + } else if (add_band_) { + + add_band_->setGeometry(QRect(event->pos(), add_band_start_).normalized()); + } else if (current_gizmo_) { // Signal movement @@ -324,6 +345,14 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) hand_dragging_ = false; UpdateCursor(); + } else if (add_band_) { + + QRectF r = GenerateGizmoTransform().inverted().mapRect(add_band_->geometry()); + emit CreateAddableAt(r); + + add_band_->deleteLater(); + add_band_ = nullptr; + } else if (current_gizmo_) { // Handle gizmo diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index a8c993aa1..54320d33f 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -21,8 +21,9 @@ #ifndef VIEWERGLWIDGET_H #define VIEWERGLWIDGET_H -#include #include +#include +#include #include "node/color/colormanager/colormanager.h" #include "node/gizmo/text.h" @@ -163,6 +164,8 @@ public slots: */ void UpdateCursor(); + void ToolChanged(); + /** * @brief Enables/disables a basic deinterlace on the viewer */ @@ -208,6 +211,8 @@ signals: void QueueStarved(); + void CreateAddableAt(const QRectF &rect); + protected: /** * @brief Override the mouse press event for the DragStarted() signal and gizmos @@ -371,6 +376,9 @@ private: rational playback_timebase_; + QRubberBand *add_band_; + QPoint add_band_start_; + private slots: void EmitColorAtCursor(QMouseEvent* e); @@ -380,6 +388,7 @@ private slots: void SubtitlesChanged(const TimeRange &r); + }; }