Merge branch 'master' into ocio_node
This commit is contained in:
@@ -48,8 +48,6 @@ set(OLIVE_SOURCES
|
||||
node/keyframe.h
|
||||
node/node.cpp
|
||||
node/node.h
|
||||
node/nodecopypaste.cpp
|
||||
node/nodecopypaste.h
|
||||
node/param.cpp
|
||||
node/param.h
|
||||
node/splitvalue.h
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace olive {
|
||||
const QString PanNode::kSamplesInput = QStringLiteral("samples_in");
|
||||
const QString PanNode::kPanningInput = QStringLiteral("panning_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
PanNode::PanNode()
|
||||
{
|
||||
AddInput(kSamplesInput, NodeValue::kSamples, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -35,6 +37,9 @@ PanNode::PanNode()
|
||||
SetInputProperty(kPanningInput, QStringLiteral("min"), -1.0);
|
||||
SetInputProperty(kPanningInput, QStringLiteral("max"), 1.0);
|
||||
SetInputProperty(kPanningInput, QStringLiteral("view"), FloatSlider::kPercentage);
|
||||
|
||||
SetFlags(kAudioEffect);
|
||||
SetEffectInput(kSamplesInput);
|
||||
}
|
||||
|
||||
Node *PanNode::copy() const
|
||||
@@ -115,6 +120,8 @@ void PanNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr i
|
||||
|
||||
void PanNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kSamplesInput, tr("Samples"));
|
||||
SetInputName(kPanningInput, tr("Pan"));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace olive {
|
||||
const QString VolumeNode::kSamplesInput = QStringLiteral("samples_in");
|
||||
const QString VolumeNode::kVolumeInput = QStringLiteral("volume_in");
|
||||
|
||||
#define super MathNodeBase
|
||||
|
||||
VolumeNode::VolumeNode()
|
||||
{
|
||||
AddInput(kSamplesInput, NodeValue::kSamples, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -34,6 +36,9 @@ VolumeNode::VolumeNode()
|
||||
AddInput(kVolumeInput, NodeValue::kFloat, 1.0);
|
||||
SetInputProperty(kVolumeInput, QStringLiteral("min"), 0.0);
|
||||
SetInputProperty(kVolumeInput, QStringLiteral("view"), FloatSlider::kDecibel);
|
||||
|
||||
SetFlags(kAudioEffect);
|
||||
SetEffectInput(kSamplesInput);
|
||||
}
|
||||
|
||||
Node *VolumeNode::copy() const
|
||||
@@ -80,6 +85,8 @@ void VolumeNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPt
|
||||
|
||||
void VolumeNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kSamplesInput, tr("Samples"));
|
||||
SetInputName(kVolumeInput, tr("Volume"));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace olive {
|
||||
#define super Node
|
||||
|
||||
const QString Block::kLengthInput = QStringLiteral("length_in");
|
||||
const QString Block::kEnabledInput = QStringLiteral("enabled_in");
|
||||
|
||||
Block::Block() :
|
||||
previous_(nullptr),
|
||||
@@ -46,8 +45,6 @@ Block::Block() :
|
||||
SetInputProperty(kLengthInput, QStringLiteral("viewlock"), true);
|
||||
IgnoreHashingFrom(kLengthInput);
|
||||
|
||||
AddInput(kEnabledInput, NodeValue::kBoolean, true, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
|
||||
SetFlags(kDontShowInParamView);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ public:
|
||||
virtual void InvalidateCache(const TimeRange& range, const QString& from, int element = -1, InvalidateCacheOptions options = InvalidateCacheOptions()) override;
|
||||
|
||||
static const QString kLengthInput;
|
||||
static const QString kEnabledInput;
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ ClipBlock::ClipBlock() :
|
||||
|
||||
PrependInput(kBufferIn, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable));
|
||||
SetValueHintForInput(kBufferIn, ValueHint(NodeValue::kBuffer));
|
||||
|
||||
SetEffectInput(kBufferIn);
|
||||
}
|
||||
|
||||
Node *ClipBlock::copy() const
|
||||
@@ -206,10 +208,22 @@ void ClipBlock::InvalidateCache(const TimeRange& range, const QString& from, int
|
||||
|
||||
// Find connected viewer node
|
||||
auto viewers = FindInputNodesConnectedToInput<ViewerOutput>(NodeInput(this, kBufferIn));
|
||||
if (viewers.isEmpty()) {
|
||||
connected_viewer_ = nullptr;
|
||||
} else {
|
||||
connected_viewer_ = viewers.first();
|
||||
ViewerOutput *new_connected_viewer = viewers.isEmpty() ? nullptr : viewers.first();
|
||||
|
||||
if (new_connected_viewer != connected_viewer_) {
|
||||
if (connected_viewer_) {
|
||||
disconnect(connected_viewer_->GetTimelinePoints()->markers(), &TimelineMarkerList::MarkerAdded, this, &ClipBlock::PreviewChanged);
|
||||
disconnect(connected_viewer_->GetTimelinePoints()->markers(), &TimelineMarkerList::MarkerRemoved, this, &ClipBlock::PreviewChanged);
|
||||
disconnect(connected_viewer_->GetTimelinePoints()->markers(), &TimelineMarkerList::MarkerModified, this, &ClipBlock::PreviewChanged);
|
||||
}
|
||||
|
||||
connected_viewer_ = new_connected_viewer;
|
||||
|
||||
if (connected_viewer_) {
|
||||
connect(connected_viewer_->GetTimelinePoints()->markers(), &TimelineMarkerList::MarkerAdded, this, &ClipBlock::PreviewChanged);
|
||||
connect(connected_viewer_->GetTimelinePoints()->markers(), &TimelineMarkerList::MarkerRemoved, this, &ClipBlock::PreviewChanged);
|
||||
connect(connected_viewer_->GetTimelinePoints()->markers(), &TimelineMarkerList::MarkerModified, this, &ClipBlock::PreviewChanged);
|
||||
}
|
||||
}
|
||||
|
||||
super::InvalidateCache(adj, from, element, options);
|
||||
|
||||
@@ -34,6 +34,8 @@ const QString ColorManager::kConfigFilenameIn = QStringLiteral("config");
|
||||
const QString ColorManager::kDefaultColorspaceIn = QStringLiteral("default_input");
|
||||
const QString ColorManager::kReferenceSpaceIn = QStringLiteral("reference_space");
|
||||
|
||||
#define super Node
|
||||
|
||||
OCIO::ConstConfigRcPtr ColorManager::default_config_ = nullptr;
|
||||
|
||||
ColorManager::ColorManager() :
|
||||
@@ -253,6 +255,8 @@ void ColorManager::GetDefaultLumaCoefs(double *rgb) const
|
||||
|
||||
void ColorManager::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kConfigFilenameIn, tr("Configuration"));
|
||||
SetInputName(kDefaultColorspaceIn, tr("Default Input"));
|
||||
SetInputName(kReferenceSpaceIn, tr("Reference Space"));
|
||||
|
||||
@@ -33,6 +33,8 @@ const QString CornerPinDistortNode::kBottomRightInput = QStringLiteral("bottom_r
|
||||
const QString CornerPinDistortNode::kBottomLeftInput = QStringLiteral("bottom_left_in");
|
||||
const QString CornerPinDistortNode::kPerspectiveInput = QStringLiteral("perspective_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
CornerPinDistortNode::CornerPinDistortNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -48,10 +50,15 @@ CornerPinDistortNode::CornerPinDistortNode()
|
||||
gizmo_resize_handle_[1] = AddDraggableGizmo<PointGizmo>({NodeKeyframeTrackReference(NodeInput(this, kTopRightInput), 0), NodeKeyframeTrackReference(NodeInput(this, kTopRightInput), 1)});
|
||||
gizmo_resize_handle_[2] = AddDraggableGizmo<PointGizmo>({NodeKeyframeTrackReference(NodeInput(this, kBottomRightInput), 0), NodeKeyframeTrackReference(NodeInput(this, kBottomRightInput), 1)});
|
||||
gizmo_resize_handle_[3] = AddDraggableGizmo<PointGizmo>({NodeKeyframeTrackReference(NodeInput(this, kBottomLeftInput), 0), NodeKeyframeTrackReference(NodeInput(this, kBottomLeftInput), 1)});
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
void CornerPinDistortNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Texture"));
|
||||
SetInputName(kPerspectiveInput, tr("Perspective"));
|
||||
SetInputName(kTopLeftInput, tr("Top Left"));
|
||||
|
||||
@@ -33,6 +33,8 @@ const QString CropDistortNode::kRightInput = QStringLiteral("right_in");
|
||||
const QString CropDistortNode::kBottomInput = QStringLiteral("bottom_in");
|
||||
const QString CropDistortNode::kFeatherInput = QStringLiteral("feather_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
CropDistortNode::CropDistortNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -56,10 +58,15 @@ CropDistortNode::CropDistortNode()
|
||||
point_gizmo_[kGizmoScaleBottomRight] = AddDraggableGizmo<PointGizmo>({kRightInput, kBottomInput});
|
||||
point_gizmo_[kGizmoScaleCenterLeft] = AddDraggableGizmo<PointGizmo>({kLeftInput});
|
||||
point_gizmo_[kGizmoScaleCenterRight] = AddDraggableGizmo<PointGizmo>({kRightInput});
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
void CropDistortNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Texture"));
|
||||
SetInputName(kLeftInput, tr("Left"));
|
||||
SetInputName(kTopInput, tr("Top"));
|
||||
|
||||
@@ -26,6 +26,8 @@ const QString FlipDistortNode::kTextureInput = QStringLiteral("tex_in");
|
||||
const QString FlipDistortNode::kHorizontalInput = QStringLiteral("horiz_in");
|
||||
const QString FlipDistortNode::kVerticalInput = QStringLiteral("vert_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
FlipDistortNode::FlipDistortNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -33,6 +35,9 @@ FlipDistortNode::FlipDistortNode()
|
||||
AddInput(kHorizontalInput, NodeValue::kBoolean, false);
|
||||
|
||||
AddInput(kVerticalInput, NodeValue::kBoolean, false);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
Node* FlipDistortNode::copy() const
|
||||
@@ -62,6 +67,8 @@ QString FlipDistortNode::Description() const
|
||||
|
||||
void FlipDistortNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Input"));
|
||||
SetInputName(kHorizontalInput, tr("Horizontal"));
|
||||
SetInputName(kVerticalInput, tr("Vertical"));
|
||||
|
||||
@@ -32,7 +32,7 @@ const QString TransformDistortNode::kTextureInput = QStringLiteral("tex_in");
|
||||
const QString TransformDistortNode::kAutoscaleInput = QStringLiteral("autoscale_in");
|
||||
const QString TransformDistortNode::kInterpolationInput = QStringLiteral("interpolation_in");
|
||||
|
||||
#define super Node
|
||||
#define super MatrixGenerator
|
||||
|
||||
TransformDistortNode::TransformDistortNode()
|
||||
{
|
||||
@@ -64,11 +64,14 @@ TransformDistortNode::TransformDistortNode()
|
||||
point_gizmo_[i]->AddInput(NodeKeyframeTrackReference(NodeInput(this, kScaleInput), 1));
|
||||
point_gizmo_[i]->SetDragValueBehavior(PointGizmo::kAbsolute);
|
||||
}
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
void TransformDistortNode::Retranslate()
|
||||
{
|
||||
MatrixGenerator::Retranslate();
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kAutoscaleInput, tr("Auto-Scale"));
|
||||
SetInputName(kTextureInput, tr("Texture"));
|
||||
@@ -150,7 +153,7 @@ void TransformDistortNode::Hash(QCryptographicHash &hash, const NodeGlobals &glo
|
||||
}
|
||||
}
|
||||
|
||||
Node::Hash(out, GetValueHintForInput(kTextureInput), hash, globals, video_params);
|
||||
super::Hash(out, GetValueHintForInput(kTextureInput), hash, globals, video_params);
|
||||
}
|
||||
|
||||
void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, double y, const rational &time)
|
||||
|
||||
@@ -24,6 +24,9 @@ OpacityEffect::OpacityEffect()
|
||||
SetInputProperty(kValueInput, QStringLiteral("view"), FloatSlider::kPercentage);
|
||||
SetInputProperty(kValueInput, QStringLiteral("min"), 0.0);
|
||||
SetInputProperty(kValueInput, QStringLiteral("max"), 1.0);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
void OpacityEffect::Retranslate()
|
||||
|
||||
@@ -89,7 +89,7 @@ void NodeFactory::Destroy()
|
||||
library_.clear();
|
||||
}
|
||||
|
||||
Menu *NodeFactory::CreateMenu(QWidget* parent, bool create_none_item, Node::CategoryID restrict_to)
|
||||
Menu *NodeFactory::CreateMenu(QWidget* parent, bool create_none_item, Node::CategoryID restrict_to, uint64_t restrict_flags)
|
||||
{
|
||||
Menu* menu = new Menu(parent);
|
||||
menu->setToolTipsVisible(true);
|
||||
@@ -102,6 +102,10 @@ Menu *NodeFactory::CreateMenu(QWidget* parent, bool create_none_item, Node::Cate
|
||||
continue;
|
||||
}
|
||||
|
||||
if (restrict_flags && !(n->GetFlags() & restrict_flags)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hidden_.contains(i)) {
|
||||
// Skip this node
|
||||
continue;
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public:
|
||||
|
||||
static void Destroy();
|
||||
|
||||
static Menu* CreateMenu(QWidget *parent, bool create_none_item = false, Node::CategoryID restrict_to = Node::kCategoryUnknown);
|
||||
static Menu* CreateMenu(QWidget *parent, bool create_none_item = false, Node::CategoryID restrict_to = Node::kCategoryUnknown, uint64_t restrict_flags = 0);
|
||||
|
||||
static Node* CreateFromMenuAction(QAction* action);
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ const QString BlurFilterNode::kHorizInput = QStringLiteral("horiz_in");
|
||||
const QString BlurFilterNode::kVertInput = QStringLiteral("vert_in");
|
||||
const QString BlurFilterNode::kRepeatEdgePixelsInput = QStringLiteral("repeat_edge_pixels_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
BlurFilterNode::BlurFilterNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -43,6 +45,9 @@ BlurFilterNode::BlurFilterNode()
|
||||
AddInput(kVertInput, NodeValue::kBoolean, true);
|
||||
|
||||
AddInput(kRepeatEdgePixelsInput, NodeValue::kBoolean, true);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
Node *BlurFilterNode::copy() const
|
||||
@@ -72,6 +77,8 @@ QString BlurFilterNode::Description() const
|
||||
|
||||
void BlurFilterNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Input"));
|
||||
SetInputName(kMethodInput, tr("Method"));
|
||||
SetComboBoxStrings(kMethodInput, { tr("Box"), tr("Gaussian") });
|
||||
|
||||
@@ -26,6 +26,8 @@ const QString MosaicFilterNode::kTextureInput = QStringLiteral("tex_in");
|
||||
const QString MosaicFilterNode::kHorizInput = QStringLiteral("horiz_in");
|
||||
const QString MosaicFilterNode::kVertInput = QStringLiteral("vert_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
MosaicFilterNode::MosaicFilterNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -35,10 +37,15 @@ MosaicFilterNode::MosaicFilterNode()
|
||||
|
||||
AddInput(kVertInput, NodeValue::kFloat, 18.0);
|
||||
SetInputProperty(kVertInput, QStringLiteral("min"), 1.0);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
void MosaicFilterNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Texture"));
|
||||
SetInputName(kHorizInput, tr("Horizontal"));
|
||||
SetInputName(kVertInput, tr("Vertical"));
|
||||
|
||||
@@ -31,6 +31,8 @@ const QString StrokeFilterNode::kRadiusInput = QStringLiteral("radius_in");
|
||||
const QString StrokeFilterNode::kOpacityInput = QStringLiteral("opacity_in");
|
||||
const QString StrokeFilterNode::kInnerInput = QStringLiteral("inner_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
StrokeFilterNode::StrokeFilterNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -46,6 +48,9 @@ StrokeFilterNode::StrokeFilterNode()
|
||||
SetInputProperty(kOpacityInput, QStringLiteral("max"), 1.0f);
|
||||
|
||||
AddInput(kInnerInput, NodeValue::kBoolean, false);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
Node *StrokeFilterNode::copy() const
|
||||
@@ -75,6 +80,8 @@ QString StrokeFilterNode::Description() const
|
||||
|
||||
void StrokeFilterNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Input"));
|
||||
SetInputName(kColorInput, tr("Color"));
|
||||
SetInputName(kRadiusInput, tr("Radius"));
|
||||
|
||||
@@ -33,6 +33,8 @@ const QString MatrixGenerator::kScaleInput = QStringLiteral("scale_in");
|
||||
const QString MatrixGenerator::kUniformScaleInput = QStringLiteral("uniform_scale_in");
|
||||
const QString MatrixGenerator::kAnchorInput = QStringLiteral("anchor_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
MatrixGenerator::MatrixGenerator()
|
||||
{
|
||||
AddInput(kPositionInput, NodeValue::kVec2, QVector2D(0.0, 0.0));
|
||||
@@ -81,6 +83,8 @@ QString MatrixGenerator::Description() const
|
||||
|
||||
void MatrixGenerator::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kPositionInput, tr("Position"));
|
||||
SetInputName(kRotationInput, tr("Rotation"));
|
||||
SetInputName(kScaleInput, tr("Scale"));
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace olive {
|
||||
const QString NoiseGeneratorNode::kColorInput = QStringLiteral("color_in");
|
||||
const QString NoiseGeneratorNode::kStrengthInput = QStringLiteral("strength_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
NoiseGeneratorNode::NoiseGeneratorNode()
|
||||
{
|
||||
AddInput(kStrengthInput, NodeValue::kFloat, 20);
|
||||
@@ -59,6 +61,8 @@ QString NoiseGeneratorNode::Description() const
|
||||
|
||||
void NoiseGeneratorNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kStrengthInput, tr("Strength"));
|
||||
SetInputName(kColorInput, tr("Color"));
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace olive {
|
||||
const QString PolygonGenerator::kPointsInput = QStringLiteral("points_in");
|
||||
const QString PolygonGenerator::kColorInput = QStringLiteral("color_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
PolygonGenerator::PolygonGenerator()
|
||||
{
|
||||
AddInput(kPointsInput, NodeValue::kBezier, QVector2D(0, 0), InputFlags(kInputFlagArray));
|
||||
@@ -86,6 +88,8 @@ QString PolygonGenerator::Description() const
|
||||
|
||||
void PolygonGenerator::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kPointsInput, tr("Points"));
|
||||
SetInputName(kColorInput, tr("Color"));
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace olive {
|
||||
|
||||
const QString SolidGenerator::kColorInput = QStringLiteral("color_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
SolidGenerator::SolidGenerator()
|
||||
{
|
||||
// Default to a color that isn't black
|
||||
@@ -59,6 +61,8 @@ QString SolidGenerator::Description() const
|
||||
|
||||
void SolidGenerator::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kColorInput, tr("Color"));
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ const QString TextGeneratorV1::kVAlignInput = QStringLiteral("valign_in");
|
||||
const QString TextGeneratorV1::kFontInput = QStringLiteral("font_in");
|
||||
const QString TextGeneratorV1::kFontSizeInput = QStringLiteral("font_size_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
TextGeneratorV1::TextGeneratorV1()
|
||||
{
|
||||
AddInput(kTextInput, NodeValue::kText, tr("Sample Text"));
|
||||
@@ -75,6 +77,8 @@ QString TextGeneratorV1::Description() const
|
||||
|
||||
void TextGeneratorV1::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextInput, tr("Text"));
|
||||
SetInputName(kHtmlInput, tr("Enable HTML"));
|
||||
SetInputName(kFontInput, tr("Font"));
|
||||
|
||||
@@ -53,6 +53,8 @@ QString NodeGroup::Description() const
|
||||
|
||||
void NodeGroup::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
for (auto it=GetContextPositions().cbegin(); it!=GetContextPositions().cend(); it++) {
|
||||
it.key()->Retranslate();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ ValueNode::ValueNode()
|
||||
|
||||
void ValueNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTypeInput, QStringLiteral("Type"));
|
||||
SetInputName(kValueInput, QStringLiteral("Value"));
|
||||
|
||||
|
||||
@@ -195,4 +195,10 @@ NodeKeyframe::BezierType NodeKeyframe::get_opposing_bezier_type(NodeKeyframe::Be
|
||||
}
|
||||
}
|
||||
|
||||
bool NodeKeyframe::has_sibling_at_time(const rational &t) const
|
||||
{
|
||||
NodeKeyframe *k = parent()->GetKeyframeAtTimeOnTrack(input(), t, track(), element());
|
||||
return k && k != this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QVariant>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "common/timerange.h"
|
||||
#include "node/param.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -86,6 +87,14 @@ public:
|
||||
const rational& time() const;
|
||||
void set_time(const rational& time);
|
||||
|
||||
/**
|
||||
* @brief Dummy function for TimeBasedViewSelectionManager compatibility
|
||||
*
|
||||
* FIXME: Once we upgrade to C++17, we won't need this because we'll be able to check types in
|
||||
* TimeBasedViewSelectionManager's template functions
|
||||
*/
|
||||
TimeRange time_range() const { return TimeRange(time_, time_); }
|
||||
|
||||
/**
|
||||
* @brief The value of this keyframe (i.e. the value to use at this keyframe's time)
|
||||
*/
|
||||
@@ -167,6 +176,8 @@ public:
|
||||
next_ = keyframe;
|
||||
}
|
||||
|
||||
bool has_sibling_at_time(const rational &t) const;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when this keyframe's time is changed
|
||||
|
||||
@@ -25,7 +25,10 @@ const QString ColorDifferenceKeyNode::kShadowsInput = QStringLiteral("shadows_in
|
||||
const QString ColorDifferenceKeyNode::kHighlightsInput = QStringLiteral("highlights_in");
|
||||
const QString ColorDifferenceKeyNode::kMaskOnlyInput = QStringLiteral("mask_only_in");
|
||||
|
||||
ColorDifferenceKeyNode::ColorDifferenceKeyNode() {
|
||||
#define super Node
|
||||
|
||||
ColorDifferenceKeyNode::ColorDifferenceKeyNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
|
||||
AddInput(kGarbageMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -41,6 +44,9 @@ ColorDifferenceKeyNode::ColorDifferenceKeyNode() {
|
||||
SetInputProperty(kShadowsInput, QStringLiteral("min"), 0.0);
|
||||
|
||||
AddInput(kMaskOnlyInput, NodeValue::kBoolean, false);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
Node *ColorDifferenceKeyNode::copy() const
|
||||
@@ -70,6 +76,8 @@ QString ColorDifferenceKeyNode::Description() const
|
||||
|
||||
void ColorDifferenceKeyNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Input"));
|
||||
SetInputName(kGarbageMatteInput, tr("Garbage Matte"));
|
||||
SetInputName(kCoreMatteInput, tr("Core Matte"));
|
||||
|
||||
@@ -24,6 +24,8 @@ const QString DespillNode::kColorInput = QStringLiteral("color_in");
|
||||
const QString DespillNode::kMethodInput = QStringLiteral("method_in");
|
||||
const QString DespillNode::kPreserveLuminanceInput = QStringLiteral("preserve_luminance_input");
|
||||
|
||||
#define super Node
|
||||
|
||||
DespillNode::DespillNode()
|
||||
{
|
||||
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -33,6 +35,9 @@ DespillNode::DespillNode()
|
||||
AddInput(kMethodInput, NodeValue::kCombo, 0);
|
||||
|
||||
AddInput(kPreserveLuminanceInput, NodeValue::kBoolean, false);
|
||||
|
||||
SetFlags(kVideoEffect);
|
||||
SetEffectInput(kTextureInput);
|
||||
}
|
||||
|
||||
Node* DespillNode::copy() const
|
||||
@@ -62,12 +67,13 @@ QString DespillNode::Description() const
|
||||
|
||||
void DespillNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTextureInput, tr("Input"));
|
||||
|
||||
SetInputName(kColorInput, tr("Key Color"));
|
||||
SetComboBoxStrings(kColorInput, {tr("Green"), tr("Blue")});
|
||||
|
||||
|
||||
SetInputName(kMethodInput, tr("Method"));
|
||||
SetComboBoxStrings(kMethodInput, {tr("Average"), tr("Double Red Average"), tr("Double Average"), tr("Limit")});
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ const QString MathNode::kParamAIn = QStringLiteral("param_a_in");
|
||||
const QString MathNode::kParamBIn = QStringLiteral("param_b_in");
|
||||
const QString MathNode::kParamCIn = QStringLiteral("param_c_in");
|
||||
|
||||
#define super MathNodeBase
|
||||
|
||||
MathNode::MathNode()
|
||||
{
|
||||
AddInput(kMethodIn, NodeValue::kCombo, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
@@ -67,7 +69,7 @@ QString MathNode::Description() const
|
||||
|
||||
void MathNode::Retranslate()
|
||||
{
|
||||
Node::Retranslate();
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kMethodIn, tr("Method"));
|
||||
SetInputName(kParamAIn, tr("Value"));
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace olive {
|
||||
const QString MergeNode::kBaseIn = QStringLiteral("base_in");
|
||||
const QString MergeNode::kBlendIn = QStringLiteral("blend_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
MergeNode::MergeNode()
|
||||
{
|
||||
AddInput(kBaseIn, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
|
||||
@@ -63,6 +65,8 @@ QString MergeNode::Description() const
|
||||
|
||||
void MergeNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kBaseIn, tr("Base"));
|
||||
|
||||
SetInputName(kBlendIn, tr("Blend"));
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace olive {
|
||||
const QString TrigonometryNode::kMethodIn = QStringLiteral("method_in");
|
||||
const QString TrigonometryNode::kXIn = QStringLiteral("x_in");
|
||||
|
||||
#define super Node
|
||||
|
||||
TrigonometryNode::TrigonometryNode()
|
||||
{
|
||||
AddInput(kMethodIn, NodeValue::kCombo, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
@@ -59,6 +61,8 @@ QString TrigonometryNode::Description() const
|
||||
|
||||
void TrigonometryNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
QStringList strings = {tr("Sine"),
|
||||
tr("Cosine"),
|
||||
tr("Tangent"),
|
||||
|
||||
+52
-12
@@ -42,14 +42,18 @@ namespace olive {
|
||||
|
||||
#define super QObject
|
||||
|
||||
const QString Node::kEnabledInput = QStringLiteral("enabled_in");
|
||||
|
||||
Node::Node() :
|
||||
can_be_deleted_(true),
|
||||
override_color_(-1),
|
||||
folder_(nullptr),
|
||||
operation_stack_(0),
|
||||
cache_result_(false),
|
||||
flags_(kNone)
|
||||
flags_(kNone),
|
||||
effect_element_(-1)
|
||||
{
|
||||
AddInput(kEnabledInput, NodeValue::kBoolean, true);
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
@@ -76,18 +80,9 @@ NodeGraph *Node::parent() const
|
||||
return static_cast<NodeGraph*>(QObject::parent());
|
||||
}
|
||||
|
||||
Project* Node::project() const
|
||||
Project *Node::project() const
|
||||
{
|
||||
QObject *t = this->parent();
|
||||
|
||||
while (t) {
|
||||
if (Project *p = dynamic_cast<Project*>(t)) {
|
||||
return p;
|
||||
}
|
||||
t = t->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return Project::GetProjectFromObject(this);
|
||||
}
|
||||
|
||||
QString Node::ShortName() const
|
||||
@@ -103,6 +98,7 @@ QString Node::Description() const
|
||||
|
||||
void Node::Retranslate()
|
||||
{
|
||||
SetInputName(kEnabledInput, tr("Enabled"));
|
||||
}
|
||||
|
||||
QIcon Node::icon() const
|
||||
@@ -1997,6 +1993,50 @@ void Node::SetValueAtTime(const NodeInput &input, const rational &time, const QV
|
||||
}
|
||||
}
|
||||
|
||||
void FindPathInternal(std::list<Node *> &vec, Node *to, int &path_index)
|
||||
{
|
||||
Node *from = vec.back();
|
||||
|
||||
for (auto it=from->input_connections().cbegin(); it!=from->input_connections().cend(); it++) {
|
||||
vec.push_back(it->second);
|
||||
if (it->second == to) {
|
||||
// Found a path, determine if it's the one we want
|
||||
if (path_index == 0) {
|
||||
// It is!
|
||||
break;
|
||||
} else {
|
||||
path_index--;
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse to see if we can find it here
|
||||
FindPathInternal(vec, to, path_index);
|
||||
if (vec.back() == to) {
|
||||
// Found through recursion
|
||||
break;
|
||||
} else {
|
||||
// Must not be available through this path
|
||||
vec.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::list<Node *> Node::FindPath(Node *from, Node *to, int path_index)
|
||||
{
|
||||
std::list<Node *> v;
|
||||
|
||||
v.push_back(from);
|
||||
|
||||
FindPathInternal(v, to, path_index);
|
||||
|
||||
if (v.size() == 1) {
|
||||
// Failed to find path, return empty list
|
||||
v.pop_back();
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
Project *Node::ArrayInsertCommand::GetRelevantProject() const
|
||||
{
|
||||
return node_->project();
|
||||
|
||||
+21
-1
@@ -95,7 +95,9 @@ public:
|
||||
|
||||
enum Flag {
|
||||
kNone = 0,
|
||||
kDontShowInParamView = 0x1
|
||||
kDontShowInParamView = 0x1,
|
||||
kVideoEffect = 0x2,
|
||||
kAudioEffect = 0x4
|
||||
};
|
||||
|
||||
Node();
|
||||
@@ -539,6 +541,11 @@ public:
|
||||
|
||||
int InputArraySize(const QString& id) const;
|
||||
|
||||
NodeInput GetEffectInput()
|
||||
{
|
||||
return effect_input_.isEmpty() ? NodeInput() : NodeInput(this, effect_input_, effect_element_);
|
||||
}
|
||||
|
||||
class ValueHint {
|
||||
public:
|
||||
explicit ValueHint(const QVector<NodeValue::Type> &types = QVector<NodeValue::Type>(), int index = -1, const QString &tag = QString()) :
|
||||
@@ -949,6 +956,10 @@ public:
|
||||
|
||||
static void SetValueAtTime(const NodeInput &input, const rational &time, const QVariant &value, int track, MultiUndoCommand *command, bool insert_on_all_tracks_if_no_key);
|
||||
|
||||
static std::list<Node*> FindPath(Node *from, Node *to, int path_index = 0);
|
||||
|
||||
static const QString kEnabledInput;
|
||||
|
||||
protected:
|
||||
virtual void Hash(QCryptographicHash& hash, const NodeGlobals &globals, const VideoParams& video_params) const;
|
||||
|
||||
@@ -1027,6 +1038,12 @@ protected:
|
||||
|
||||
virtual void childEvent(QChildEvent *event) override;
|
||||
|
||||
void SetEffectInput(const QString &input, int element = -1)
|
||||
{
|
||||
effect_input_ = input;
|
||||
effect_element_ = element;
|
||||
}
|
||||
|
||||
void SetToolTip(const QString& s)
|
||||
{
|
||||
tooltip_ = s;
|
||||
@@ -1342,6 +1359,9 @@ private:
|
||||
|
||||
QVector<NodeGizmo*> gizmos_;
|
||||
|
||||
QString effect_input_;
|
||||
int effect_element_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 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 "nodecopypaste.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "core.h"
|
||||
#include "node/factory.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
#include "window/mainwindow/mainwindow.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
void NodeCopyPasteService::CopyNodesToClipboard(QVector<Node *> nodes, void *userdata)
|
||||
{
|
||||
QString copy_str;
|
||||
|
||||
QXmlStreamWriter writer(©_str);
|
||||
|
||||
// For any groups, add children
|
||||
for (int i=0; i<nodes.size(); i++) {
|
||||
// If this is a group, add the child nodes too
|
||||
if (NodeGroup *g = dynamic_cast<NodeGroup*>(nodes.at(i))) {
|
||||
for (auto it=g->GetContextPositions().cbegin(); it!=g->GetContextPositions().cend(); it++) {
|
||||
if (!nodes.contains(it.key())) {
|
||||
nodes.append(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::SaveData data(nodes.first()->project(), QString(), nodes);
|
||||
|
||||
CopyNodesToClipboardCallback(nodes, &data, userdata);
|
||||
|
||||
ProjectSerializer::Save(&writer, data);
|
||||
|
||||
Core::CopyStringToClipboard(copy_str);
|
||||
}
|
||||
|
||||
void NodeCopyPasteService::PasteNodesFromClipboard(void *userdata)
|
||||
{
|
||||
QString clipboard = Core::PasteStringFromClipboard();
|
||||
if (clipboard.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(clipboard);
|
||||
|
||||
Project temp;
|
||||
ProjectSerializer::Result res = ProjectSerializer::Load(&temp, &reader);
|
||||
|
||||
if (res.code() != ProjectSerializer::kSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<Node*> pasted_nodes;
|
||||
foreach (Node *n, temp.nodes()) {
|
||||
if (!temp.default_nodes().contains(n)) {
|
||||
// Move nodes out of Project
|
||||
n->setParent(nullptr);
|
||||
pasted_nodes.append(n);
|
||||
}
|
||||
}
|
||||
|
||||
if (pasted_nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PasteNodesToClipboardCallback(pasted_nodes, res.GetLoadData(), userdata);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef NODECOPYPASTEWIDGET_H
|
||||
#define NODECOPYPASTEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QUndoCommand>
|
||||
|
||||
#include "node/node.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "node/project/serializer/serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class NodeCopyPasteService
|
||||
{
|
||||
public:
|
||||
NodeCopyPasteService() = default;
|
||||
|
||||
protected:
|
||||
void CopyNodesToClipboard(QVector<Node *> nodes, void* userdata = nullptr);
|
||||
|
||||
void PasteNodesFromClipboard(void* userdata = nullptr);
|
||||
|
||||
virtual void CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *data, void *userdata){}
|
||||
|
||||
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NODECOPYPASTEWIDGET_H
|
||||
@@ -277,7 +277,7 @@ void Track::InputValueChangedEvent(const QString &input, int element)
|
||||
|
||||
void Track::Retranslate()
|
||||
{
|
||||
Node::Retranslate();
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kBlockInput, tr("Blocks"));
|
||||
SetInputName(kMutedInput, tr("Muted"));
|
||||
|
||||
@@ -68,6 +68,8 @@ ViewerOutput::ViewerOutput(bool create_buffer_inputs, bool create_default_stream
|
||||
}
|
||||
|
||||
SetFlags(kDontShowInParamView);
|
||||
|
||||
timeline_points_ = new TimelinePoints(this);
|
||||
}
|
||||
|
||||
Node *ViewerOutput::copy() const
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
|
||||
TimelinePoints* GetTimelinePoints()
|
||||
{
|
||||
return &timeline_points_;
|
||||
return timeline_points_;
|
||||
}
|
||||
|
||||
QVector<Track::Reference> GetEnabledStreamsAsReferences() const;
|
||||
@@ -252,7 +252,7 @@ private:
|
||||
|
||||
AudioParams cached_audio_params_;
|
||||
|
||||
TimelinePoints timeline_points_;
|
||||
TimelinePoints *timeline_points_;
|
||||
|
||||
bool video_cache_enabled_;
|
||||
bool audio_cache_enabled_;
|
||||
|
||||
@@ -169,6 +169,20 @@ void Project::RegenerateUuid()
|
||||
uuid_ = QUuid::createUuid();
|
||||
}
|
||||
|
||||
Project *Project::GetProjectFromObject(const QObject *o)
|
||||
{
|
||||
QObject *t = o->parent();
|
||||
|
||||
while (t) {
|
||||
if (Project *p = dynamic_cast<Project*>(t)) {
|
||||
return p;
|
||||
}
|
||||
t = t->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Project::ColorManagerValueChanged(const NodeInput &input, const TimeRange &range)
|
||||
{
|
||||
Q_UNUSED(input)
|
||||
|
||||
@@ -109,6 +109,14 @@ public:
|
||||
saved_url_ = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find project parent from object
|
||||
*
|
||||
* If an object is expected to be a child of a project, this function will traverse its parent
|
||||
* tree until it finds it.
|
||||
*/
|
||||
static Project *GetProjectFromObject(const QObject *o);
|
||||
|
||||
signals:
|
||||
void NameChanged();
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace olive {
|
||||
const QString ProjectSettingsNode::kCacheSetting = QStringLiteral("cache_setting");
|
||||
const QString ProjectSettingsNode::kCachePath = QStringLiteral("cache_path");
|
||||
|
||||
#define super Node
|
||||
|
||||
ProjectSettingsNode::ProjectSettingsNode()
|
||||
{
|
||||
AddInput(kCacheSetting, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
@@ -36,6 +38,8 @@ ProjectSettingsNode::ProjectSettingsNode()
|
||||
|
||||
void ProjectSettingsNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kCacheSetting, tr("Disk Cache Location"));
|
||||
SetInputName(kCachePath, tr("Disk Cache Path"));
|
||||
SetComboBoxStrings(kCacheSetting, {tr("Use Default Location"), tr("Store Alongside Project"), tr("Use Custom Location")});
|
||||
|
||||
@@ -405,7 +405,7 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
|
||||
}
|
||||
|
||||
// Trigger an import
|
||||
Core::instance()->ImportFiles(urls, this, static_cast<Folder*>(drop_item));
|
||||
Core::instance()->ImportFiles(urls, static_cast<Folder*>(drop_item));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,14 +55,14 @@ void ProjectSerializer::Destroy()
|
||||
instances_.clear();
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project, const QString &filename)
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project, const QString &filename, const QString &type)
|
||||
{
|
||||
QFile project_file(filename);
|
||||
|
||||
if (project_file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QXmlStreamReader reader(&project_file);
|
||||
|
||||
Result inner_result = Load(project, &reader);
|
||||
Result inner_result = Load(project, &reader, type);
|
||||
|
||||
project_file.close();
|
||||
|
||||
@@ -82,25 +82,162 @@ ProjectSerializer::Result ProjectSerializer::Load(Project *project, const QStrin
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project, QXmlStreamReader *reader)
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project, QXmlStreamReader *reader, const QString &type)
|
||||
{
|
||||
// Determine project version
|
||||
uint version = 0;
|
||||
Result res = kUnknownVersion;
|
||||
|
||||
while (!version && XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("olive") || reader->name() == QStringLiteral("project")) {
|
||||
while(!version && XMLReadNextStartElement(reader)) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("olive")
|
||||
|| reader->name() == QStringLiteral("project")) { // 0.1 projects only
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("version")) {
|
||||
version = reader->readElementText().toUInt();
|
||||
} else if (reader->name() == QStringLiteral("url")) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
|
||||
// HACK for 0.1 projects
|
||||
if (version == 190219) {
|
||||
res = LoadWithSerializerVersion(version, project, reader);
|
||||
}
|
||||
} else if (reader->name() == type) {
|
||||
// Found our data
|
||||
res = LoadWithSerializerVersion(version, project, reader);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Paste(const QString &type)
|
||||
{
|
||||
QString clipboard = Core::PasteStringFromClipboard();
|
||||
if (clipboard.isEmpty()) {
|
||||
return kNoData;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(clipboard);
|
||||
|
||||
Project temp;
|
||||
ProjectSerializer::Result res = ProjectSerializer::Load(&temp, &reader, type);
|
||||
|
||||
if (res.code() != ProjectSerializer::kSuccess) {
|
||||
return res;
|
||||
}
|
||||
|
||||
QVector<Node*> pasted_nodes;
|
||||
foreach (Node *n, temp.nodes()) {
|
||||
if (!temp.default_nodes().contains(n)) {
|
||||
// Move nodes out of Project
|
||||
n->setParent(nullptr);
|
||||
pasted_nodes.append(n);
|
||||
}
|
||||
}
|
||||
|
||||
res.SetLoadedNodes(pasted_nodes);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Save(const SaveData &data, const QString &type)
|
||||
{
|
||||
QString temp_save = FileFunctions::GetSafeTemporaryFilename(data.GetFilename());
|
||||
|
||||
QFile project_file(temp_save);
|
||||
|
||||
if (project_file.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QXmlStreamWriter writer(&project_file);
|
||||
|
||||
Result inner_result = Save(&writer, data, type);
|
||||
|
||||
project_file.close();
|
||||
|
||||
if (inner_result != kSuccess) {
|
||||
return inner_result;
|
||||
}
|
||||
|
||||
// Save was successful, we can now rewrite the original file
|
||||
if (FileFunctions::RenameFileAllowOverwrite(temp_save, data.GetFilename())) {
|
||||
return kSuccess;
|
||||
} else {
|
||||
Result r(kOverwriteError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
Result r(kFileError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Save(QXmlStreamWriter *writer, const SaveData &data, const QString &type)
|
||||
{
|
||||
writer->setAutoFormatting(true);
|
||||
|
||||
writer->writeStartDocument();
|
||||
|
||||
writer->writeStartElement("olive");
|
||||
|
||||
// By default, save as last serializer which, assuming the instances are ordered correctly,
|
||||
// will be the newest file format. But we may allow saving as older versions later on.
|
||||
ProjectSerializer *serializer = instances_.last();
|
||||
|
||||
// Version is stored in YYMMDD from whenever the project format was last changed
|
||||
// Allows easy integer math for checking project versions.
|
||||
writer->writeTextElement(QStringLiteral("version"), QString::number(serializer->Version()));
|
||||
|
||||
if (!data.GetFilename().isEmpty()) {
|
||||
writer->writeTextElement("url", data.GetFilename());
|
||||
}
|
||||
|
||||
writer->writeStartElement(type);
|
||||
|
||||
serializer->Save(writer, data, nullptr);
|
||||
|
||||
writer->writeEndElement(); // [type]
|
||||
|
||||
writer->writeEndElement(); // olive
|
||||
|
||||
writer->writeEndDocument();
|
||||
|
||||
if (writer->hasError()) {
|
||||
return kXmlError;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Copy(const SaveData &data, const QString &type)
|
||||
{
|
||||
QString copy_str;
|
||||
QXmlStreamWriter writer(©_str);
|
||||
|
||||
ProjectSerializer::Result res = ProjectSerializer::Save(&writer, data, type);
|
||||
|
||||
if (res == kSuccess) {
|
||||
Core::CopyStringToClipboard(copy_str);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ProjectSerializer::IsCancelled() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::LoadWithSerializerVersion(uint version, Project *project, QXmlStreamReader *reader)
|
||||
{
|
||||
// Failed to find version in file
|
||||
if (version == 0) {
|
||||
return kUnknownVersion;
|
||||
@@ -135,78 +272,21 @@ ProjectSerializer::Result ProjectSerializer::Load(Project *project, QXmlStreamRe
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Save(const SaveData &data)
|
||||
void ProjectSerializer::SaveData::SetOnlySerializeNodesAndResolveGroups(QVector<Node *> nodes)
|
||||
{
|
||||
QString temp_save = FileFunctions::GetSafeTemporaryFilename(data.GetFilename());
|
||||
|
||||
QFile project_file(temp_save);
|
||||
|
||||
if (project_file.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QXmlStreamWriter writer(&project_file);
|
||||
|
||||
Result inner_result = Save(&writer, data);
|
||||
|
||||
project_file.close();
|
||||
|
||||
if (inner_result != kSuccess) {
|
||||
return inner_result;
|
||||
// For any groups, add children
|
||||
for (int i=0; i<nodes.size(); i++) {
|
||||
// If this is a group, add the child nodes too
|
||||
if (NodeGroup *g = dynamic_cast<NodeGroup*>(nodes.at(i))) {
|
||||
for (auto it=g->GetContextPositions().cbegin(); it!=g->GetContextPositions().cend(); it++) {
|
||||
if (!nodes.contains(it.key())) {
|
||||
nodes.append(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save was successful, we can now rewrite the original file
|
||||
if (FileFunctions::RenameFileAllowOverwrite(temp_save, data.GetFilename())) {
|
||||
return kSuccess;
|
||||
} else {
|
||||
Result r(kOverwriteError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
Result r(kFileError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Save(QXmlStreamWriter *writer, const SaveData &data)
|
||||
{
|
||||
writer->setAutoFormatting(true);
|
||||
|
||||
writer->writeStartDocument();
|
||||
|
||||
writer->writeStartElement("olive");
|
||||
|
||||
// By default, save as last serializer which, assuming the instances are ordered correctly,
|
||||
// will be the newest file format. But we may allow saving as older versions later on.
|
||||
ProjectSerializer *serializer = instances_.last();
|
||||
|
||||
// Version is stored in YYMMDD from whenever the project format was last changed
|
||||
// Allows easy integer math for checking project versions.
|
||||
writer->writeTextElement(QStringLiteral("version"), QString::number(serializer->Version()));
|
||||
|
||||
if (!data.GetFilename().isEmpty()) {
|
||||
writer->writeTextElement("url", data.GetFilename());
|
||||
}
|
||||
|
||||
writer->writeStartElement(QStringLiteral("project"));
|
||||
|
||||
serializer->Save(writer, data, nullptr);
|
||||
|
||||
writer->writeEndElement(); // project
|
||||
|
||||
writer->writeEndElement(); // olive
|
||||
|
||||
writer->writeEndDocument();
|
||||
|
||||
if (writer->hasError()) {
|
||||
return kXmlError;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
bool ProjectSerializer::IsCancelled() const
|
||||
{
|
||||
return false;
|
||||
SetOnlySerializeNodes(nodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ public:
|
||||
kUnknownVersion,
|
||||
kFileError,
|
||||
kXmlError,
|
||||
kOverwriteError
|
||||
kOverwriteError,
|
||||
kNoData
|
||||
};
|
||||
|
||||
using SerializedProperties = QHash<Node*, QMap<QString, QString> >;
|
||||
@@ -62,6 +63,8 @@ public:
|
||||
|
||||
SerializedProperties properties;
|
||||
|
||||
std::vector<TimelineMarker*> markers;
|
||||
|
||||
};
|
||||
|
||||
class Result
|
||||
@@ -84,6 +87,10 @@ public:
|
||||
|
||||
void SetLoadData(const LoadData &p) { load_data_ = p; }
|
||||
|
||||
const QVector<Node*> &GetLoadedNodes() const { return loaded_nodes_; }
|
||||
|
||||
void SetLoadedNodes(const QVector<Node*> &n) { loaded_nodes_ = n; }
|
||||
|
||||
private:
|
||||
ResultCode code_;
|
||||
|
||||
@@ -91,17 +98,17 @@ public:
|
||||
|
||||
LoadData load_data_;
|
||||
|
||||
QVector<Node*> loaded_nodes_;
|
||||
|
||||
};
|
||||
|
||||
class SaveData
|
||||
{
|
||||
public:
|
||||
SaveData(Project *project, const QString &filename, const QVector<Node*> &only = QVector<Node*>(), const SerializedProperties &p = SerializedProperties())
|
||||
SaveData(Project *project, const QString &filename = QString())
|
||||
{
|
||||
project_ = project;
|
||||
filename_ = filename;
|
||||
only_serialize_nodes_ = only;
|
||||
properties_ = p;
|
||||
}
|
||||
|
||||
Project *GetProject() const
|
||||
@@ -115,11 +122,13 @@ public:
|
||||
}
|
||||
|
||||
const QVector<Node*> &GetOnlySerializeNodes() const { return only_serialize_nodes_; }
|
||||
|
||||
void SetOnlySerializeNodes(const QVector<Node*> &only) { only_serialize_nodes_ = only; }
|
||||
void SetOnlySerializeNodesAndResolveGroups(QVector<Node*> only);
|
||||
|
||||
const std::vector<TimelineMarker*> &GetOnlySerializeMarkers() const { return only_serialize_markers_; }
|
||||
void SetOnlySerializeMarkers(const std::vector<TimelineMarker*> &only) { only_serialize_markers_ = only; }
|
||||
|
||||
const SerializedProperties &GetProperties() const { return properties_; }
|
||||
|
||||
void SetProperties(const SerializedProperties &p) { properties_ = p; }
|
||||
|
||||
private:
|
||||
@@ -131,17 +140,21 @@ public:
|
||||
|
||||
SerializedProperties properties_;
|
||||
|
||||
std::vector<TimelineMarker*> only_serialize_markers_;
|
||||
|
||||
};
|
||||
|
||||
static void Initialize();
|
||||
|
||||
static void Destroy();
|
||||
|
||||
static Result Load(Project *project, const QString &filename);
|
||||
static Result Load(Project *project, QXmlStreamReader *read_device);
|
||||
static Result Load(Project *project, const QString &filename, const QString &type);
|
||||
static Result Load(Project *project, QXmlStreamReader *read_device, const QString &type);
|
||||
static Result Paste(const QString &type);
|
||||
|
||||
static Result Save(const SaveData &data);
|
||||
static Result Save(QXmlStreamWriter *write_device, const SaveData &data);
|
||||
static Result Save(const SaveData &data, const QString &type);
|
||||
static Result Save(QXmlStreamWriter *write_device, const SaveData &data, const QString &type);
|
||||
static Result Copy(const SaveData &data, const QString &type);
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const = 0;
|
||||
@@ -153,6 +166,8 @@ protected:
|
||||
bool IsCancelled() const;
|
||||
|
||||
private:
|
||||
static Result LoadWithSerializerVersion(uint version, Project *project, QXmlStreamReader *reader);
|
||||
|
||||
static QVector<ProjectSerializer*> instances_;
|
||||
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "serializer210528.h"
|
||||
|
||||
#include "config/config.h"
|
||||
#include "node/factory.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -29,133 +30,125 @@ ProjectSerializer210528::LoadData ProjectSerializer210528::Load(Project *project
|
||||
XMLNodeData xml_node_data;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("url")) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("project")) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
|
||||
Node *context = xml_node_data.node_ptrs.value(context_ptr);
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
|
||||
if (!context) {
|
||||
qWarning() << "Failed to find pointer for context";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
Node *node = xml_node_data.node_ptrs.value(node_ptr);
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (node) {
|
||||
context->SetNodePositionInContext(node, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
Node *context = xml_node_data.node_ptrs.value(context_ptr);
|
||||
|
||||
if (!context) {
|
||||
qWarning() << "Failed to find pointer for context";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
Node *node = xml_node_data.node_ptrs.value(node_ptr);
|
||||
|
||||
if (node) {
|
||||
context->SetNodePositionInContext(node, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +605,7 @@ void ProjectSerializer210528::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
}
|
||||
}
|
||||
|
||||
markers->AddMarker(TimeRange(in, out), name);
|
||||
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
|
||||
}
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "serializer210907.h"
|
||||
|
||||
#include "config/config.h"
|
||||
#include "node/factory.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -29,133 +30,125 @@ ProjectSerializer210907::LoadData ProjectSerializer210907::Load(Project *project
|
||||
XMLNodeData xml_node_data;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("url")) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("project")) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
|
||||
Node *context = xml_node_data.node_ptrs.value(context_ptr);
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
|
||||
if (!context) {
|
||||
qWarning() << "Failed to find pointer for context";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
Node *node = xml_node_data.node_ptrs.value(node_ptr);
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (node) {
|
||||
context->SetNodePositionInContext(node, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
Node *context = xml_node_data.node_ptrs.value(context_ptr);
|
||||
|
||||
if (!context) {
|
||||
qWarning() << "Failed to find pointer for context";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
Node *node = xml_node_data.node_ptrs.value(node_ptr);
|
||||
|
||||
if (node) {
|
||||
context->SetNodePositionInContext(node, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,7 +597,7 @@ void ProjectSerializer210907::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
}
|
||||
}
|
||||
|
||||
markers->AddMarker(TimeRange(in, out), name);
|
||||
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
|
||||
}
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "serializer211228.h"
|
||||
|
||||
#include "config/config.h"
|
||||
#include "node/factory.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -31,157 +32,149 @@ ProjectSerializer211228::LoadData ProjectSerializer211228::Load(Project *project
|
||||
XMLNodeData xml_node_data;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("url")) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("project")) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
|
||||
if (context_ptr) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
if (node_ptr) {
|
||||
positions[context_ptr].insert(node_ptr, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (context_ptr) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
if (node_ptr) {
|
||||
positions[context_ptr].insert(node_ptr, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Attempted to load context with no pointer";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if (reader->name() == QStringLiteral("properties")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr ptr = 0;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
|
||||
// Only attribute we're looking for right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
QMap<QString, QString> properties_for_node;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
properties_for_node.insert(reader->name().toString(), reader->readElementText());
|
||||
}
|
||||
properties.insert(ptr, properties_for_node);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Attempted to load context with no pointer";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if (reader->name() == QStringLiteral("properties")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr ptr = 0;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
|
||||
// Only attribute we're looking for right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
QMap<QString, QString> properties_for_node;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
properties_for_node.insert(reader->name().toString(), reader->readElementText());
|
||||
}
|
||||
properties.insert(ptr, properties_for_node);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,7 +647,7 @@ void ProjectSerializer211228::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
}
|
||||
}
|
||||
|
||||
markers->AddMarker(TimeRange(in, out), name);
|
||||
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
|
||||
}
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "serializer220403.h"
|
||||
|
||||
#include "config/config.h"
|
||||
#include "node/factory.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -30,158 +31,164 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
|
||||
QMap<quintptr, QMap<quintptr, Node::Position> > positions;
|
||||
XMLNodeData xml_node_data;
|
||||
|
||||
LoadData load_data;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("url")) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("project")) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("layout")) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
// Since the main window's functions have to occur in the GUI thread (and we're likely
|
||||
// loading in a secondary thread), we load all necessary data into a separate struct so we
|
||||
// can continue loading and queue it with the main window so it can handle the data
|
||||
// appropriately in its own thread.
|
||||
|
||||
project->SetLayoutInfo(MainWindowLayoutInfo::fromXml(reader, xml_node_data.node_ptrs));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
|
||||
project->SetUuid(QUuid::fromString(reader->readElementText()));
|
||||
|
||||
} else if (reader->name() == QStringLiteral("nodes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
bool is_root = false;
|
||||
bool is_cm = false;
|
||||
bool is_settings = false;
|
||||
QString id;
|
||||
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) {
|
||||
is_root = true;
|
||||
} else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) {
|
||||
is_cm = true;
|
||||
} else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) {
|
||||
is_settings = true;
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (is_root) {
|
||||
node = project->root();
|
||||
} else if (is_cm) {
|
||||
node = project->color_manager();
|
||||
} else if (is_settings) {
|
||||
node = project->settings();
|
||||
} else {
|
||||
node = NodeFactory::CreateFromID(id);
|
||||
}
|
||||
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
LoadNode(node, xml_node_data, reader);
|
||||
node->setParent(project);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("markers")) {
|
||||
|
||||
if (context_ptr) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("marker")) {
|
||||
TimelineMarker *marker = new TimelineMarker();
|
||||
LoadMarker(reader, marker);
|
||||
load_data.markers.push_back(marker);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
if (node_ptr) {
|
||||
positions[context_ptr].insert(node_ptr, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("positions")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
|
||||
if (reader->name() == QStringLiteral("context")) {
|
||||
|
||||
quintptr context_ptr = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
context_ptr = attr.value().toULongLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (context_ptr) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr node_ptr;
|
||||
Node::Position node_pos;
|
||||
|
||||
if (LoadPosition(reader, &node_ptr, &node_pos)) {
|
||||
if (node_ptr) {
|
||||
positions[context_ptr].insert(node_ptr, node_pos);
|
||||
} else {
|
||||
qWarning() << "Failed to find pointer for node position";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Attempted to load context with no pointer";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if (reader->name() == QStringLiteral("properties")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr ptr = 0;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
|
||||
// Only attribute we're looking for right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
QMap<QString, QString> properties_for_node;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
properties_for_node.insert(reader->name().toString(), reader->readElementText());
|
||||
}
|
||||
properties.insert(ptr, properties_for_node);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Attempted to load context with no pointer";
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if (reader->name() == QStringLiteral("properties")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr ptr = 0;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
|
||||
// Only attribute we're looking for right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
QMap<QString, QString> properties_for_node;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
properties_for_node.insert(reader->name().toString(), reader->readElementText());
|
||||
}
|
||||
properties.insert(ptr, properties_for_node);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Skip this
|
||||
reader->skipCurrentElement();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,8 +208,6 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
|
||||
// Make connections
|
||||
PostConnect(xml_node_data);
|
||||
|
||||
LoadData load_data;
|
||||
|
||||
// Resolve serialized properties (if any)
|
||||
for (auto it=properties.cbegin(); it!=properties.cend(); it++) {
|
||||
Node *node = xml_node_data.node_ptrs.value(it.key());
|
||||
@@ -218,74 +223,94 @@ void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &dat
|
||||
{
|
||||
Project *project = data.GetProject();
|
||||
|
||||
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
|
||||
if (!data.GetOnlySerializeMarkers().empty()) {
|
||||
|
||||
writer->writeStartElement(QStringLiteral("nodes"));
|
||||
writer->writeStartElement(QStringLiteral("markers"));
|
||||
|
||||
const QVector<Node*> &using_node_list = (data.GetOnlySerializeNodes().isEmpty()) ? project->nodes() : data.GetOnlySerializeNodes();
|
||||
for (auto it=data.GetOnlySerializeMarkers().cbegin(); it!=data.GetOnlySerializeMarkers().cend(); it++) {
|
||||
TimelineMarker *marker = *it;
|
||||
|
||||
foreach (Node* node, using_node_list) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
|
||||
if (node == project->root()) {
|
||||
writer->writeAttribute(QStringLiteral("root"), QStringLiteral("1"));
|
||||
} else if (node == project->color_manager()) {
|
||||
writer->writeAttribute(QStringLiteral("cm"), QStringLiteral("1"));
|
||||
} else if (node == project->settings()) {
|
||||
writer->writeAttribute(QStringLiteral("settings"), QStringLiteral("1"));
|
||||
SaveMarker(writer, marker);
|
||||
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), node->id());
|
||||
writer->writeEndElement(); // markers
|
||||
|
||||
SaveNode(node, writer);
|
||||
} else {
|
||||
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
|
||||
|
||||
writer->writeEndElement(); // nodes
|
||||
writer->writeStartElement(QStringLiteral("nodes"));
|
||||
|
||||
writer->writeStartElement(QStringLiteral("positions"));
|
||||
const QVector<Node*> &using_node_list = (data.GetOnlySerializeNodes().isEmpty()) ? project->nodes() : data.GetOnlySerializeNodes();
|
||||
|
||||
foreach (Node* context, using_node_list) {
|
||||
const Node::PositionMap &map = context->GetContextPositions();
|
||||
foreach (Node* node, using_node_list) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
if (!map.isEmpty()) {
|
||||
writer->writeStartElement(QStringLiteral("context"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(context)));
|
||||
|
||||
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
|
||||
if (data.GetOnlySerializeNodes().isEmpty() || data.GetOnlySerializeNodes().contains(jt.key())) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
SavePosition(writer, jt.key(), jt.value());
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
if (node == project->root()) {
|
||||
writer->writeAttribute(QStringLiteral("root"), QStringLiteral("1"));
|
||||
} else if (node == project->color_manager()) {
|
||||
writer->writeAttribute(QStringLiteral("cm"), QStringLiteral("1"));
|
||||
} else if (node == project->settings()) {
|
||||
writer->writeAttribute(QStringLiteral("settings"), QStringLiteral("1"));
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // context
|
||||
}
|
||||
}
|
||||
writer->writeAttribute(QStringLiteral("id"), node->id());
|
||||
|
||||
writer->writeEndElement(); // positions
|
||||
SaveNode(node, writer);
|
||||
|
||||
writer->writeStartElement(QStringLiteral("properties"));
|
||||
|
||||
for (auto it=data.GetProperties().cbegin(); it!=data.GetProperties().cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(it.key())));
|
||||
|
||||
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
|
||||
writer->writeTextElement(jt.key(), jt.value());
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node
|
||||
writer->writeEndElement(); // nodes
|
||||
|
||||
writer->writeStartElement(QStringLiteral("positions"));
|
||||
|
||||
foreach (Node* context, using_node_list) {
|
||||
const Node::PositionMap &map = context->GetContextPositions();
|
||||
|
||||
if (!map.isEmpty()) {
|
||||
writer->writeStartElement(QStringLiteral("context"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(context)));
|
||||
|
||||
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
|
||||
if (data.GetOnlySerializeNodes().isEmpty() || data.GetOnlySerializeNodes().contains(jt.key())) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
SavePosition(writer, jt.key(), jt.value());
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // context
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // positions
|
||||
|
||||
writer->writeStartElement(QStringLiteral("properties"));
|
||||
|
||||
for (auto it=data.GetProperties().cbegin(); it!=data.GetProperties().cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(it.key())));
|
||||
|
||||
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
|
||||
writer->writeTextElement(jt.key(), jt.value());
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // properties
|
||||
|
||||
// Save main window project layout
|
||||
project->GetLayoutInfo().toXml(writer);
|
||||
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // properties
|
||||
|
||||
// Save main window project layout
|
||||
project->GetLayoutInfo().toXml(writer);
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const
|
||||
@@ -961,6 +986,36 @@ void ProjectSerializer220403::SaveTimelinePoints(QXmlStreamWriter *writer, Timel
|
||||
writer->writeEndElement(); // markers
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::LoadMarker(QXmlStreamReader *reader, TimelineMarker *marker) const
|
||||
{
|
||||
rational in, out;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
marker->set_name(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("color")) {
|
||||
marker->set_color(attr.value().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
marker->set_time(TimeRange(in, out));
|
||||
|
||||
// This element has no inner text, so just skip it
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::SaveMarker(QXmlStreamWriter *writer, TimelineMarker *marker) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("name"), marker->name());
|
||||
writer->writeAttribute(QStringLiteral("in"), marker->time_range().in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), marker->time_range().out().toString());
|
||||
writer->writeAttribute(QStringLiteral("color"), QString::number(marker->color()));
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const
|
||||
{
|
||||
rational range_in = workarea->in();
|
||||
@@ -996,35 +1051,22 @@ void ProjectSerializer220403::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
{
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("marker")) {
|
||||
QString name;
|
||||
rational in, out;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
name = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
markers->AddMarker(TimeRange(in, out), name);
|
||||
TimelineMarker *marker = new TimelineMarker(markers);
|
||||
LoadMarker(reader, marker);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::SaveMarkerList(QXmlStreamWriter *writer, TimelineMarkerList *markers) const
|
||||
{
|
||||
foreach (TimelineMarker* marker, markers->list()) {
|
||||
for (auto it=markers->cbegin(); it!=markers->cend(); it++) {
|
||||
TimelineMarker* marker = *it;
|
||||
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("name"), marker->name());
|
||||
|
||||
writer->writeAttribute(QStringLiteral("in"), marker->time().in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), marker->time().out().toString());
|
||||
SaveMarker(writer, marker);
|
||||
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@ private:
|
||||
|
||||
void SaveTimelinePoints(QXmlStreamWriter *writer, TimelinePoints *points) const;
|
||||
|
||||
void LoadMarker(QXmlStreamReader *reader, TimelineMarker *marker) const;
|
||||
|
||||
void SaveMarker(QXmlStreamWriter *writer, TimelineMarker *marker) const;
|
||||
|
||||
void LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const;
|
||||
|
||||
void SaveWorkArea(QXmlStreamWriter *writer, TimelineWorkArea *workarea) const;
|
||||
|
||||
@@ -41,6 +41,8 @@ TimeOffsetNode::TimeOffsetNode()
|
||||
|
||||
void TimeOffsetNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTimeInput, QStringLiteral("Time"));
|
||||
SetInputName(kInputInput, QStringLiteral("Input"));
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ TimeRange TimeRemapNode::OutputTimeAdjustment(const QString &input, int element,
|
||||
|
||||
void TimeRemapNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kTimeInput, QStringLiteral("Time"));
|
||||
SetInputName(kInputInput, QStringLiteral("Input"));
|
||||
}
|
||||
|
||||
+22
-9
@@ -246,20 +246,33 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const Node::ValueHint
|
||||
|
||||
// Generate row for node
|
||||
NodeValueDatabase database = GenerateDatabase(n, range);
|
||||
NodeValueRow row = GenerateRow(&database, n, range);
|
||||
|
||||
//qDebug() << "FIXME: Implement pre-process of row";
|
||||
// Check for bypass
|
||||
bool is_enabled;
|
||||
if (!database[Node::kEnabledInput].Has(NodeValue::kBoolean)) {
|
||||
// Fallback if we couldn't find a bool value
|
||||
is_enabled = true;
|
||||
} else {
|
||||
is_enabled = database[Node::kEnabledInput].Get(NodeValue::kBoolean).toBool();
|
||||
}
|
||||
|
||||
// Generate output table
|
||||
NodeValueTable table = database.Merge();
|
||||
if (is_enabled) {
|
||||
NodeValueRow row = GenerateRow(&database, n, range);
|
||||
//qDebug() << "FIXME: Implement pre-process of row";
|
||||
|
||||
// By this point, the node should have all the inputs it needs to render correctly
|
||||
n->Value(row, GenerateGlobals(video_params_, range), &table);
|
||||
// Generate output table
|
||||
NodeValueTable table = database.Merge();
|
||||
|
||||
// Post-process table
|
||||
PostProcessTable(n, hint, range, table);
|
||||
// By this point, the node should have all the inputs it needs to render correctly
|
||||
n->Value(row, GenerateGlobals(video_params_, range), &table);
|
||||
|
||||
return table;
|
||||
// Post-process table
|
||||
PostProcessTable(n, hint, range, table);
|
||||
|
||||
return table;
|
||||
} else {
|
||||
return database.Merge();
|
||||
}
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::GenerateBlockTable(const Track *track, const TimeRange &range)
|
||||
|
||||
Reference in New Issue
Block a user