markers: reimplemented copy/paste
This commit is contained in:
@@ -406,7 +406,7 @@ void CurveView::FirstChanceMouseRelease(QMouseEvent *event)
|
||||
void CurveView::KeyframeDragStart(QMouseEvent *event)
|
||||
{
|
||||
drag_keyframe_values_.resize(GetSelectedKeyframes().size());
|
||||
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
NodeKeyframe *key = GetSelectedKeyframes().at(i);
|
||||
drag_keyframe_values_[i] = key->value();
|
||||
}
|
||||
@@ -418,7 +418,7 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
|
||||
{
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
// Lock to X axis only and set original values on all keys
|
||||
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
NodeKeyframe *key = GetSelectedKeyframes().at(i);
|
||||
key->set_value(drag_keyframe_values_.at(i));
|
||||
}
|
||||
@@ -429,7 +429,7 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
|
||||
double scaled_diff = (mapToScene(event->pos()).y() - drag_start_.y()) / GetYScale();
|
||||
|
||||
// Validate movement - ensure no keyframe goes above its max point or below its min point
|
||||
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
NodeKeyframe *key = GetSelectedKeyframes().at(i);
|
||||
|
||||
FloatSlider::DisplayType display = GetFloatDisplayTypeFromKeyframe(key);
|
||||
@@ -453,13 +453,13 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
|
||||
}
|
||||
|
||||
// Set values
|
||||
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
NodeKeyframe *key = GetSelectedKeyframes().at(i);
|
||||
FloatSlider::DisplayType display = GetFloatDisplayTypeFromKeyframe(key);
|
||||
key->set_value(FloatSlider::TransformDisplayToValue(FloatSlider::TransformValueToDisplay(drag_keyframe_values_.at(i).toDouble(), display) - scaled_diff, display));
|
||||
}
|
||||
|
||||
NodeKeyframe *tip_item = GetSelectedKeyframes().first();
|
||||
NodeKeyframe *tip_item = GetSelectedKeyframes().front();
|
||||
|
||||
bool ok;
|
||||
double num_value = tip_item->value().toDouble(&ok);
|
||||
@@ -472,7 +472,7 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
|
||||
|
||||
void CurveView::KeyframeDragRelease(QMouseEvent *event, MultiUndoCommand *command)
|
||||
{
|
||||
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
|
||||
NodeKeyframe *k = GetSelectedKeyframes().at(i);
|
||||
if (!qFuzzyCompare(k->value().toDouble(), drag_keyframe_values_.at(i).toDouble())) {
|
||||
command->add_child(new NodeParamSetKeyframeValueCommand(k, k->value(), drag_keyframe_values_.at(i)));
|
||||
|
||||
@@ -251,16 +251,16 @@ void CurveWidget::ConnectInputInternal(Node *node, const QString &input, int ele
|
||||
|
||||
void CurveWidget::SelectionChanged()
|
||||
{
|
||||
const QVector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
|
||||
const std::vector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
|
||||
|
||||
SetKeyframeButtonChecked(false);
|
||||
SetKeyframeButtonEnabled(!selected.isEmpty());
|
||||
SetKeyframeButtonEnabled(!selected.empty());
|
||||
|
||||
if (!selected.isEmpty()) {
|
||||
if (!selected.empty()) {
|
||||
bool all_same_type = true;
|
||||
NodeKeyframe::Type type = selected.first()->type();
|
||||
NodeKeyframe::Type type = selected.front()->type();
|
||||
|
||||
for (int i=1;i<selected.size();i++) {
|
||||
for (size_t i=1;i<selected.size();i++) {
|
||||
NodeKeyframe* prev_item = selected.at(i-1);
|
||||
NodeKeyframe* this_item = selected.at(i);
|
||||
|
||||
@@ -287,8 +287,8 @@ void CurveWidget::KeyframeTypeButtonTriggered(bool checked)
|
||||
}
|
||||
|
||||
// Get selected items and do nothing if there are none
|
||||
const QVector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
|
||||
if (selected.isEmpty()) {
|
||||
const std::vector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
|
||||
if (selected.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -462,11 +462,11 @@ void KeyframeView::ShowContextMenu()
|
||||
QAction* bezier_key_action = nullptr;
|
||||
QAction* hold_key_action = nullptr;
|
||||
|
||||
if (!GetSelectedKeyframes().isEmpty()) {
|
||||
if (!GetSelectedKeyframes().empty()) {
|
||||
bool all_keys_are_same_type = true;
|
||||
NodeKeyframe::Type type = GetSelectedKeyframes().first()->type();
|
||||
NodeKeyframe::Type type = GetSelectedKeyframes().front()->type();
|
||||
|
||||
for (int i=1;i<GetSelectedKeyframes().size();i++) {
|
||||
for (size_t i=1;i<GetSelectedKeyframes().size();i++) {
|
||||
NodeKeyframe* key_item = GetSelectedKeyframes().at(i);
|
||||
NodeKeyframe* prev_item = GetSelectedKeyframes().at(i-1);
|
||||
|
||||
@@ -507,7 +507,7 @@ void KeyframeView::ShowContextMenu()
|
||||
|
||||
ContextMenuEvent(m);
|
||||
|
||||
if (!GetSelectedKeyframes().isEmpty()) {
|
||||
if (!GetSelectedKeyframes().empty()) {
|
||||
m.addSeparator();
|
||||
|
||||
QAction* properties_action = m.addAction(tr("P&roperties"));
|
||||
@@ -542,7 +542,7 @@ void KeyframeView::ShowContextMenu()
|
||||
|
||||
void KeyframeView::ShowKeyframePropertiesDialog()
|
||||
{
|
||||
if (!GetSelectedKeyframes().isEmpty()) {
|
||||
if (!GetSelectedKeyframes().empty()) {
|
||||
KeyframePropertiesDialog kd(GetSelectedKeyframes(), timebase(), this);
|
||||
kd.exec();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
const QVector<NodeKeyframe*> &GetSelectedKeyframes() const
|
||||
const std::vector<NodeKeyframe*> &GetSelectedKeyframes() const
|
||||
{
|
||||
return selection_manager_.GetSelectedObjects();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "node/distort/transform/transformdistortnode.h"
|
||||
#include "node/factory.h"
|
||||
#include "node/group/group.h"
|
||||
#include "node/project/serializer/serializer.h"
|
||||
#include "node/traverser.h"
|
||||
#include "ui/icons/icons.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
@@ -45,7 +46,6 @@ const double NodeView::kMinimumScale = 0.1;
|
||||
|
||||
NodeView::NodeView(QWidget *parent) :
|
||||
HandMovableView(parent),
|
||||
NodeCopyPasteService(QStringLiteral("nodes")),
|
||||
drop_edge_(nullptr),
|
||||
create_edge_(nullptr),
|
||||
create_edge_output_item_(nullptr),
|
||||
@@ -204,7 +204,31 @@ void NodeView::CopySelected(bool cut)
|
||||
return;
|
||||
}
|
||||
|
||||
CopyNodesToClipboard(selected_nodes_);
|
||||
QString copy_str;
|
||||
QXmlStreamWriter writer(©_str);
|
||||
|
||||
ProjectSerializer::SaveData sdata(selected_nodes_.first()->project());
|
||||
sdata.SetOnlySerializeNodesAndResolveGroups(selected_nodes_);
|
||||
|
||||
ProjectSerializer::SerializedProperties properties;
|
||||
|
||||
for (Node *n : selected_nodes_) {
|
||||
NodeViewItem *item = GetAssumedItemForSelectedNode(n);
|
||||
|
||||
if (item) {
|
||||
Node::Position pos = item->GetNodePositionData();
|
||||
|
||||
properties[n][QStringLiteral("x")] = QString::number(pos.position.x());
|
||||
properties[n][QStringLiteral("y")] = QString::number(pos.position.y());
|
||||
properties[n][QStringLiteral("expanded")] = QString::number(pos.expanded);
|
||||
}
|
||||
}
|
||||
|
||||
sdata.SetProperties(properties);
|
||||
|
||||
ProjectSerializer::Save(&writer, sdata, QStringLiteral("nodes"));
|
||||
|
||||
Core::CopyStringToClipboard(copy_str);
|
||||
|
||||
if (cut) {
|
||||
DeleteSelected();
|
||||
@@ -213,9 +237,31 @@ void NodeView::CopySelected(bool cut)
|
||||
|
||||
void NodeView::Paste()
|
||||
{
|
||||
if (!contexts_.isEmpty()) {
|
||||
PasteNodesFromClipboard();
|
||||
if (contexts_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result res = ProjectSerializer::Paste(QStringLiteral("nodes"));
|
||||
if (res.GetLoadedNodes().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node::PositionMap map;
|
||||
|
||||
for (auto it=res.GetLoadData().properties.cbegin(); it!=res.GetLoadData().properties.cend(); it++) {
|
||||
Node::Position pos;
|
||||
|
||||
const QMap<QString, QString> &node_props = it.value();
|
||||
pos.position.setX(node_props.value(QStringLiteral("x")).toDouble());
|
||||
pos.position.setY(node_props.value(QStringLiteral("y")).toDouble());
|
||||
pos.expanded = node_props.value(QStringLiteral("expanded")).toDouble();
|
||||
|
||||
qDebug() << it.key() << pos.position;
|
||||
|
||||
map.insert(it.key(), pos);
|
||||
}
|
||||
|
||||
PostPaste(res.GetLoadedNodes(), map);
|
||||
}
|
||||
|
||||
void NodeView::Duplicate()
|
||||
@@ -1007,43 +1053,6 @@ bool NodeView::eventFilter(QObject *object, QEvent *event)
|
||||
return super::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void NodeView::CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *sdata, void *userdata)
|
||||
{
|
||||
ProjectSerializer::SerializedProperties properties;
|
||||
|
||||
for (Node *n : nodes) {
|
||||
NodeViewItem *item = GetAssumedItemForSelectedNode(n);
|
||||
|
||||
if (item) {
|
||||
Node::Position pos = item->GetNodePositionData();
|
||||
|
||||
properties[n][QStringLiteral("x")] = QString::number(pos.position.x());
|
||||
properties[n][QStringLiteral("y")] = QString::number(pos.position.y());
|
||||
properties[n][QStringLiteral("expanded")] = QString::number(pos.expanded);
|
||||
}
|
||||
}
|
||||
|
||||
sdata->SetProperties(properties);
|
||||
}
|
||||
|
||||
void NodeView::PasteNodesToClipboardCallback(const QVector<Node *> &nodes, const ProjectSerializer::LoadData &ldata, void *userdata)
|
||||
{
|
||||
Node::PositionMap map;
|
||||
|
||||
for (auto it=ldata.properties.cbegin(); it!=ldata.properties.cend(); it++) {
|
||||
Node::Position pos;
|
||||
|
||||
const QMap<QString, QString> &node_props = it.value();
|
||||
pos.position.setX(node_props.value(QStringLiteral("x")).toDouble());
|
||||
pos.position.setY(node_props.value(QStringLiteral("y")).toDouble());
|
||||
pos.expanded = node_props.value(QStringLiteral("expanded")).toDouble();
|
||||
|
||||
map.insert(it.key(), pos);
|
||||
}
|
||||
|
||||
PostPaste(nodes, map);
|
||||
}
|
||||
|
||||
void NodeView::changeEvent(QEvent *e)
|
||||
{
|
||||
// Add translation code
|
||||
@@ -1548,7 +1557,7 @@ void NodeView::PostPaste(const QVector<Node *> &new_nodes, const Node::PositionM
|
||||
AttachedItem &ai = new_attached[i];
|
||||
|
||||
if (ai.item) {
|
||||
ai.original_pos = first_item->pos() - ai.item->pos();
|
||||
ai.original_pos = ai.item->pos() - first_item->pos();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "node/graph.h"
|
||||
#include "node/nodecopypaste.h"
|
||||
#include "nodeviewedge.h"
|
||||
#include "nodeviewcontext.h"
|
||||
#include "nodeviewminimap.h"
|
||||
@@ -42,7 +41,7 @@ namespace olive {
|
||||
* This widget takes a NodeGraph object and constructs a QGraphicsScene representing its data, viewing and allowing
|
||||
* the user to make modifications to it.
|
||||
*/
|
||||
class NodeView : public HandMovableView, public NodeCopyPasteService
|
||||
class NodeView : public HandMovableView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -139,9 +138,6 @@ protected:
|
||||
|
||||
virtual bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
virtual void CopyNodesToClipboardCallback(const QVector<Node *> &nodes, ProjectSerializer::SaveData *data, void* userdata) override;
|
||||
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &ldata, void *userdata) override;
|
||||
|
||||
virtual void changeEvent(QEvent *e) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
void DeclareDrawnObject(T *object, const QRectF &pos)
|
||||
{
|
||||
drawn_objects_.append({object, pos});
|
||||
drawn_objects_.push_back({object, pos});
|
||||
}
|
||||
|
||||
bool Select(T *key)
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
Q_ASSERT(key);
|
||||
|
||||
if (!IsSelected(key)) {
|
||||
selected_.append(key);
|
||||
selected_.push_back(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,13 @@ public:
|
||||
{
|
||||
Q_ASSERT(key);
|
||||
|
||||
return selected_.removeOne(key);
|
||||
auto it = std::find(selected_.cbegin(), selected_.cend(), key);
|
||||
if (it == selected_.cend()) {
|
||||
return false;
|
||||
} else {
|
||||
selected_.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearSelection()
|
||||
@@ -77,10 +83,10 @@ public:
|
||||
|
||||
bool IsSelected(T *key) const
|
||||
{
|
||||
return selected_.contains(key);
|
||||
return std::find(selected_.cbegin(), selected_.cend(), key) != selected_.cend();
|
||||
}
|
||||
|
||||
const QVector<T*> &GetSelectedObjects() const
|
||||
const std::vector<T*> &GetSelectedObjects() const
|
||||
{
|
||||
return selected_;
|
||||
}
|
||||
@@ -142,7 +148,7 @@ public:
|
||||
|
||||
bool IsDragging() const
|
||||
{
|
||||
return !dragging_.isEmpty();
|
||||
return !dragging_.empty();
|
||||
}
|
||||
|
||||
void DragStart(T *initial_item, QMouseEvent *event)
|
||||
@@ -150,7 +156,7 @@ public:
|
||||
initial_drag_item_ = initial_item;
|
||||
|
||||
dragging_.resize(selected_.size());
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
for (size_t i=0; i<selected_.size(); i++) {
|
||||
T *obj = selected_.at(i);
|
||||
|
||||
dragging_[i] = obj->time();
|
||||
@@ -164,7 +170,7 @@ public:
|
||||
rational time_diff = view_->SceneToTimeNoGrid(view_->mapToScene(event->pos()).x() - drag_mouse_start_.x());
|
||||
|
||||
// Validate movement
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
for (size_t i=0; i<selected_.size(); i++) {
|
||||
rational proposed_time = dragging_.at(i) + time_diff;
|
||||
T *sel = selected_.at(i);
|
||||
|
||||
@@ -199,7 +205,7 @@ public:
|
||||
}
|
||||
|
||||
// Apply movement
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
for (size_t i=0; i<selected_.size(); i++) {
|
||||
selected_.at(i)->set_time(dragging_.at(i) + time_diff);
|
||||
}
|
||||
|
||||
@@ -219,7 +225,7 @@ public:
|
||||
{
|
||||
QToolTip::hideText();
|
||||
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
for (size_t i=0; i<selected_.size(); i++) {
|
||||
command->add_child(new SetTimeCommand(selected_.at(i), selected_.at(i)->time(), dragging_.at(i)));
|
||||
}
|
||||
|
||||
@@ -314,11 +320,11 @@ private:
|
||||
TimeBasedView *view_;
|
||||
|
||||
using DrawnObject = QPair<T*, QRectF>;
|
||||
QVector<DrawnObject> drawn_objects_;
|
||||
std::vector<DrawnObject> drawn_objects_;
|
||||
|
||||
QVector<T*> selected_;
|
||||
std::vector<T*> selected_;
|
||||
|
||||
QVector<rational> dragging_;
|
||||
std::vector<rational> dragging_;
|
||||
|
||||
T *initial_drag_item_;
|
||||
|
||||
@@ -328,7 +334,7 @@ private:
|
||||
|
||||
QRubberBand *rubberband_;
|
||||
QPoint rubberband_start_;
|
||||
QVector<T*> rubberband_preselected_;
|
||||
std::vector<T*> rubberband_preselected_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "dialog/sequence/sequence.h"
|
||||
#include "dialog/speedduration/speeddurationdialog.h"
|
||||
#include "node/block/transition/transition.h"
|
||||
#include "node/project/serializer/serializer.h"
|
||||
#include "tool/add.h"
|
||||
#include "tool/beam.h"
|
||||
#include "tool/edit.h"
|
||||
@@ -60,7 +61,6 @@ namespace olive {
|
||||
|
||||
TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
super(true, true, parent),
|
||||
NodeCopyPasteService(QStringLiteral("timeline")),
|
||||
rubberband_(QRubberBand::Rectangle, this),
|
||||
active_tool_(nullptr),
|
||||
use_audio_time_units_(false),
|
||||
@@ -312,66 +312,6 @@ void TimelineWidget::DisconnectNodeEvent(ViewerOutput *n)
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::CopyNodesToClipboardCallback(const QVector<Node *> &nodes, ProjectSerializer::SaveData *sdata, void *userdata)
|
||||
{
|
||||
// Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere
|
||||
QVector<Block*>& selected = *static_cast<QVector<Block*>*>(userdata);
|
||||
rational earliest_in = RATIONAL_MAX;
|
||||
ProjectSerializer::SerializedProperties properties;
|
||||
|
||||
foreach (Block* block, selected) {
|
||||
earliest_in = qMin(earliest_in, block->in());
|
||||
}
|
||||
|
||||
foreach (Block* block, selected) {
|
||||
properties[block][QStringLiteral("in")] = (block->in() - earliest_in).toString();
|
||||
properties[block][QStringLiteral("track")] = block->track()->ToReference().ToString();
|
||||
}
|
||||
|
||||
sdata->SetProperties(properties);
|
||||
}
|
||||
|
||||
void TimelineWidget::PasteNodesToClipboardCallback(const QVector<Node *> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata)
|
||||
{
|
||||
bool insert = *(bool*)userdata;
|
||||
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
foreach (Node *n, nodes) {
|
||||
command->add_child(new NodeAddCommand(GetConnectedNode()->project(), n));
|
||||
}
|
||||
|
||||
rational paste_start = GetTime();
|
||||
|
||||
if (insert) {
|
||||
rational paste_end = GetTime();
|
||||
|
||||
for (auto it=load_data.properties.cbegin(); it!=load_data.properties.cend(); it++) {
|
||||
rational length = static_cast<Block*>(it.key())->length();
|
||||
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
|
||||
|
||||
paste_end = qMax(paste_end, paste_start + in + length);
|
||||
}
|
||||
|
||||
if (paste_end != paste_start) {
|
||||
InsertGapsAt(paste_start, paste_end - paste_start, command);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it=load_data.properties.cbegin(); it!=load_data.properties.cend(); it++) {
|
||||
Block *block = static_cast<Block*>(it.key());
|
||||
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
|
||||
Track::Reference track = Track::Reference::FromString(it.value()[QStringLiteral("track")]);
|
||||
|
||||
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
|
||||
track.index(),
|
||||
block,
|
||||
paste_start + in));
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void TimelineWidget::SelectAll()
|
||||
{
|
||||
QVector<Block*> newly_selected_blocks;
|
||||
@@ -633,20 +573,17 @@ void TimelineWidget::CopySelected(bool cut)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ruler()->hasFocus()) {
|
||||
ruler()->CopySelected(cut);
|
||||
if (ruler()->hasFocus() && ruler()->CopySelected(cut)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<Block*> selected = GetSelectedBlocks();
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
if (selected_blocks_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<Node*> selected_nodes;
|
||||
|
||||
foreach (Block* block, selected) {
|
||||
foreach (Block* block, selected_blocks_) {
|
||||
selected_nodes.append(block);
|
||||
|
||||
QVector<Node*> deps = block->GetDependencies();
|
||||
@@ -658,7 +595,25 @@ void TimelineWidget::CopySelected(bool cut)
|
||||
}
|
||||
}
|
||||
|
||||
CopyNodesToClipboard(selected_nodes, &selected);
|
||||
ProjectSerializer::SaveData sdata(selected_nodes.first()->project());
|
||||
sdata.SetOnlySerializeNodesAndResolveGroups(selected_nodes);
|
||||
|
||||
// Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere
|
||||
rational earliest_in = RATIONAL_MAX;
|
||||
ProjectSerializer::SerializedProperties properties;
|
||||
|
||||
foreach (Block* block, selected_blocks_) {
|
||||
earliest_in = qMin(earliest_in, block->in());
|
||||
}
|
||||
|
||||
foreach (Block* block, selected_blocks_) {
|
||||
properties[block][QStringLiteral("in")] = (block->in() - earliest_in).toString();
|
||||
properties[block][QStringLiteral("track")] = block->track()->ToReference().ToString();
|
||||
}
|
||||
|
||||
sdata.SetProperties(properties);
|
||||
|
||||
ProjectSerializer::Copy(sdata, QStringLiteral("timeline"));
|
||||
|
||||
if (cut) {
|
||||
DeleteSelected();
|
||||
@@ -671,12 +626,50 @@ void TimelineWidget::Paste(bool insert)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ruler()->underMouse()) {
|
||||
ruler()->PasteMarkers(insert, GetTime());
|
||||
if (ruler()->hasFocus() && ruler()->PasteMarkers(insert, GetTime())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PasteNodesFromClipboard(&insert);
|
||||
ProjectSerializer::Result res = ProjectSerializer::Paste(QStringLiteral("timeline"));
|
||||
if (res.GetLoadedNodes().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
foreach (Node *n, res.GetLoadedNodes()) {
|
||||
command->add_child(new NodeAddCommand(GetConnectedNode()->project(), n));
|
||||
}
|
||||
|
||||
rational paste_start = GetTime();
|
||||
|
||||
if (insert) {
|
||||
rational paste_end = GetTime();
|
||||
|
||||
for (auto it=res.GetLoadData().properties.cbegin(); it!=res.GetLoadData().properties.cend(); it++) {
|
||||
rational length = static_cast<Block*>(it.key())->length();
|
||||
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
|
||||
|
||||
paste_end = qMax(paste_end, paste_start + in + length);
|
||||
}
|
||||
|
||||
if (paste_end != paste_start) {
|
||||
InsertGapsAt(paste_start, paste_end - paste_start, command);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it=res.GetLoadData().properties.cbegin(); it!=res.GetLoadData().properties.cend(); it++) {
|
||||
Block *block = static_cast<Block*>(it.key());
|
||||
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
|
||||
Track::Reference track = Track::Reference::FromString(it.value()[QStringLiteral("track")]);
|
||||
|
||||
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
|
||||
track.index(),
|
||||
block,
|
||||
paste_start + in));
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void TimelineWidget::DeleteInToOut(bool ripple)
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "node/block/transition/transition.h"
|
||||
#include "node/nodecopypaste.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "timeline/timelinecommon.h"
|
||||
#include "timelineandtrackview.h"
|
||||
@@ -45,7 +44,7 @@ namespace olive {
|
||||
*
|
||||
* Encapsulates TimelineViews, TimeRulers, and scrollbars for a complete widget to manipulate Timelines
|
||||
*/
|
||||
class TimelineWidget : public TimeBasedWidget, public NodeCopyPasteService, public SnapService
|
||||
class TimelineWidget : public TimeBasedWidget, public SnapService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -277,9 +276,6 @@ protected:
|
||||
virtual void ConnectNodeEvent(ViewerOutput* n) override;
|
||||
virtual void DisconnectNodeEvent(ViewerOutput* n) override;
|
||||
|
||||
virtual void CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *data, void *userdata) override;
|
||||
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata) override;
|
||||
|
||||
private:
|
||||
QVector<Timeline::EditToInfo> GetEditToInfo(const rational &playhead_time, Timeline::MovementMode mode);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "common/qtutils.h"
|
||||
#include "core.h"
|
||||
#include "dialog/markerproperties/markerpropertiesdialog.h"
|
||||
#include "node/project/serializer/serializer.h"
|
||||
#include "widget/colorlabelmenu/colorlabelmenu.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
#include "widget/timebased/timebasedwidget.h"
|
||||
@@ -38,7 +39,6 @@ namespace olive {
|
||||
|
||||
SeekableWidget::SeekableWidget(QWidget* parent) :
|
||||
super(parent),
|
||||
NodeCopyPasteService(QStringLiteral("markers")),
|
||||
timeline_points_(nullptr),
|
||||
dragging_(false),
|
||||
ignore_next_focus_out_(false),
|
||||
@@ -91,21 +91,68 @@ void SeekableWidget::DeleteSelected()
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void SeekableWidget::CopySelected(bool cut)
|
||||
bool SeekableWidget::CopySelected(bool cut)
|
||||
{
|
||||
qDebug() << "COPY IS STUB";
|
||||
//CopyMarkersToClipboard(selection_manager_.GetSelectedObjects());
|
||||
if (!selection_manager_.GetSelectedObjects().empty()) {
|
||||
ProjectSerializer::SaveData sdata(Project::GetProjectFromObject(timeline_points_));
|
||||
sdata.SetOnlySerializeMarkers(selection_manager_.GetSelectedObjects());
|
||||
|
||||
if (cut) {
|
||||
DeleteSelected();
|
||||
ProjectSerializer::Copy(sdata, QStringLiteral("markers"));
|
||||
|
||||
if (cut) {
|
||||
DeleteSelected();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SeekableWidget::PasteMarkers(bool insert, rational insert_time)
|
||||
bool SeekableWidget::PasteMarkers(bool insert, rational insert_time)
|
||||
{
|
||||
//MultiUndoCommand *command = new MultiUndoCommand();
|
||||
//PasteMarkersFromClipboard(timeline_points()->markers(), command, insert_time);
|
||||
qDebug() << "PASTE IS STUB";
|
||||
ProjectSerializer::Result res = ProjectSerializer::Paste(QStringLiteral("markers"));
|
||||
if (res == ProjectSerializer::kSuccess) {
|
||||
const std::vector<TimelineMarker*> &markers = res.GetLoadData().markers;
|
||||
if (!markers.empty()) {
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
// Normalize markers to start at playhead
|
||||
rational min = RATIONAL_MAX;
|
||||
for (auto it=markers.cbegin(); it!=markers.cend(); it++) {
|
||||
min = qMin(min, (*it)->time());
|
||||
}
|
||||
min -= GetTime();
|
||||
|
||||
// Avoid duplicates
|
||||
bool loop;
|
||||
do {
|
||||
loop = false;
|
||||
for (auto it=markers.cbegin(); it!=markers.cend(); it++) {
|
||||
rational proposed_time = (*it)->time() - min;
|
||||
|
||||
if (timeline_points_->markers()->GetMarkerAtTime(proposed_time)) {
|
||||
min -= timebase();
|
||||
loop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (loop);
|
||||
|
||||
for (auto it=markers.cbegin(); it!=markers.cend(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
|
||||
m->set_time(m->time() - min);
|
||||
|
||||
command->add_child(new MarkerAddCommand(timeline_points_->markers(), m));
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SeekableWidget::mousePressEvent(QMouseEvent *event)
|
||||
@@ -148,7 +195,7 @@ void SeekableWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
super::mouseDoubleClickEvent(event);
|
||||
|
||||
if (selection_manager_.GetObjectAtPoint(event->pos()) && !selection_manager_.GetSelectedObjects().isEmpty()) {
|
||||
if (selection_manager_.GetObjectAtPoint(event->pos()) && !selection_manager_.GetSelectedObjects().empty()) {
|
||||
ShowMarkerProperties();
|
||||
}
|
||||
}
|
||||
@@ -315,7 +362,7 @@ void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y)
|
||||
|
||||
bool SeekableWidget::ShowContextMenu(const QPoint &p)
|
||||
{
|
||||
if (selection_manager_.GetObjectAtPoint(p) && !selection_manager_.GetSelectedObjects().isEmpty()) {
|
||||
if (selection_manager_.GetObjectAtPoint(p) && !selection_manager_.GetSelectedObjects().empty()) {
|
||||
// Show marker-specific menu
|
||||
Menu m;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "node/nodecopypaste.h"
|
||||
#include "timeline/timelinepoints.h"
|
||||
#include "widget/menu/menu.h"
|
||||
#include "widget/snapservice/snapservice.h"
|
||||
@@ -33,7 +32,7 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
class SeekableWidget : public TimeBasedView, public NodeCopyPasteService
|
||||
class SeekableWidget : public TimeBasedView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -53,9 +52,9 @@ public:
|
||||
|
||||
void DeleteSelected();
|
||||
|
||||
void CopySelected(bool cut);
|
||||
bool CopySelected(bool cut);
|
||||
|
||||
void PasteMarkers(bool insert, rational insert_time);
|
||||
bool PasteMarkers(bool insert, rational insert_time);
|
||||
|
||||
void DeselectAllMarkers();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user