1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
|
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NODEINPUT_H
#define NODEINPUT_H
#include "common/timerange.h"
#include "keyframe.h"
#include "param.h"
OLIVE_NAMESPACE_ENTER
/**
* @brief A node parameter designed to take either user input or data from another node
*/
class NodeInput : public NodeParam
{
Q_OBJECT
public:
using KeyframeTrack = QList<NodeKeyframePtr>;
/**
* @brief NodeInput Constructor
*
* @param id
*
* Unique ID associated with this parameter for this Node. This ID only has to be unique within this Node. Used for
* saving/loading data from this Node so that parameter order can be changed without issues loading data saved by an
* older version. This of course assumes that parameters don't change their ID.
*/
NodeInput(const QString &id, const DataType& type, const QVector<QVariant>& default_value);
NodeInput(const QString &id, const DataType& type, const QVariant& default_value);
NodeInput(const QString &id, const DataType& type);
virtual bool IsArray() const;
/**
* @brief Returns kInput
*/
virtual Type type() override;
virtual QString name() override;
virtual void Load(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled) override;
virtual void Save(QXmlStreamWriter* writer) const override;
/**
* @brief The data type this parameter outputs
*
* This can be used in conjunction with NodeInput::can_accept_type() to determine whether this parameter can be
* connected to it.
*/
const DataType& data_type() const;
/**
* @brief If this input is connected to an output, retrieve the output parameter
*
* @return
*
* The output parameter if connected or nullptr if not
*/
NodeOutput* get_connected_output() const;
/**
* @brief If this input is connected to an output, retrieve the Node whose output is connected
*
* @return
*
* The connected Node if connected or nullptr if not
*/
Node* get_connected_node() const;
/**
* @brief Calculate what the stored value should be at a certain time
*
* If this is a multi-track data type (e.g. kVec2), this will automatically combine the result into a QVector2D.
*/
QVariant get_value_at_time(const rational& time) const;
QVector<QVariant> get_split_values_at_time(const rational& time) const;
/**
* @brief Calculate the stored value for a specific track
*
* For most data types, there is only one track (e.g. `track == 0`), but multi-track data types like kVec2 will
* produce the X value on track 0 and the Y value on track 1.
*/
QVariant get_value_at_time_for_track(const rational& time, int track) const;
/**
* @brief Retrieve a list of keyframe objects for all tracks at a given time
*
* List may be empty if this input is not keyframing or has no keyframes at this time.
*/
QList<NodeKeyframePtr> get_keyframe_at_time(const rational& time) const;
/**
* @brief Retrieve the keyframe object at a given time for a given track
*
* @return
*
* The keyframe object at this time or nullptr if there isn't one or if is_keyframing() is false.
*/
NodeKeyframePtr get_keyframe_at_time_on_track(const rational& time, int track) const;
/**
* @brief Gets the closest keyframe to a time
*
* If is_keyframing() is false or keyframes_ is empty, this will return nullptr.
*/
NodeKeyframePtr get_closest_keyframe_to_time_on_track(const rational& time, int track) const;
/**
* @brief Get closest keyframe that's before the time on any track
*
* If no keyframe is before this time, returns nullptr.
*/
NodeKeyframePtr get_closest_keyframe_before_time(const rational& time) const;
/**
* @brief Get closest keyframe that's before the time on any track
*
* If no keyframe is before this time, returns nullptr.
*/
NodeKeyframePtr get_closest_keyframe_after_time(const rational& time) const;
/**
* @brief A heuristic to determine what type a keyframe should be if it's inserted at a certain time (between keyframes)
*/
NodeKeyframe::Type get_best_keyframe_type_for_time(const rational& time, int track) const;
/**
* @brief Retrieve the number of
*/
int get_number_of_keyframe_tracks() const;
/**
* @brief Gets the earliest keyframe on any track
*/
NodeKeyframePtr get_earliest_keyframe() const;
/**
* @brief Gets the latest keyframe on any track
*/
NodeKeyframePtr get_latest_keyframe() const;
/**
* @brief Inserts a keyframe at the given time and returns a reference to it
*/
void insert_keyframe(NodeKeyframePtr key);
/**
* @brief Removes the keyframe
*/
void remove_keyframe(NodeKeyframePtr key);
/**
* @brief Hacky convenience function to turn a raw pointer into a shared pointer
*/
NodeKeyframePtr get_keyframe_shared_ptr_from_raw(NodeKeyframe *raw) const;
/**
* @brief Return whether a keyframe exists at this time
*
* If is_keyframing() is false, this will always return false. This checks all tracks and will return true if *any*
* track has a keyframe.
*/
bool has_keyframe_at_time(const rational &time) const;
/**
* @brief Return whether keyframing is enabled on this input or not
*/
bool is_keyframing() const;
/**
* @brief Set whether keyframing is enabled on this input or not
*/
void set_is_keyframing(bool k);
/**
* @brief Return whether this input can be keyframed or not
*/
bool is_keyframable() const;
/**
* @brief Returns whether the value that this input returns is always the same or is expected to change
*
* Equivalent to `!(is_connected() || is_keyframing())`
*/
bool is_static() const;
/**
* @brief Get non-keyframed value
*/
QVariant get_standard_value() const;
/**
* @brief Get non-keyframed value split into components (the way it's stored)
*/
const QVector<QVariant>& get_split_standard_value() const;
/**
* @brief Set non-keyframed value
*/
void set_standard_value(const QVariant& value, int track = 0);
/**
* @brief Return list of keyframes in this parameter
*/
const QVector<KeyframeTrack> &keyframe_tracks() const;
/**
* @brief Set whether this input can be keyframed or not
*/
void set_is_keyframable(bool k);
/**
* @brief Copy all values including keyframe information and connections from another NodeInput
*/
static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true, bool traverse_arrays = true);
/**
* @brief Set an arbitrary property on this input to influence a UI representation's behavior
*
* NodeInputs also utilize QObject's property key/value system for arbitrary properties that can influence the UI
* representation's behavior.
*
* Currently supported properties:
*
* - `min` - For any numeral type represented with a slider, prevents values going BELOW this number
* - `max` - For any numeral type represented with a slider, prevents values going ABOVE this number
* - `view` - For any numeral type represented with a slider, shows number either as `db`, `percent`, or `normal`
* - `disablex` - For kVec2, kVec3, kVec4 and kColor types, disables the first/X/R UI widget
* - `disabley` - For kVec2, kVec3, kVec4 and kColor types, disables the second/Y/G UI widget
* - `disablez` - For kVec3, kVec4 and kColor types, disables the third/Z/B UI widget
* - `disablew` - For kVec4 and kColor types, disables the fourth/W/A UI widget
*/
void set_property(const QString& key, const QVariant& value);
/**
* @brief Retrieve a property (or an empty QVariant if it hasn't been set)
*/
QVariant get_property(const QString& key) const;
/**
* @brief Return whether a certain property has been set or not
*/
bool has_property(const QString& key) const;
/**
* @brief Get properties hashmap (useful for iterating)
*/
const QHash<QString, QVariant>& properties() const;
QVector<QVariant> split_normal_value_into_track_values(const QVariant &value) const;
QVariant combine_track_values_into_normal_value(const QVector<QVariant>& split) const;
QStringList get_combobox_strings() const;
void set_combobox_strings(const QStringList& strings);
static QString ValueToString(const DataType& data_type, const QVariant& value);
static QVariant StringToValue(const DataType &data_type, const QString &string);
void GetDependencies(QList<Node*>& list, bool traverse, bool exclusive_only) const;
QVariant GetDefaultValue() const;
QVariant GetDefaultValueForTrack(int track) const;
QList<Node*> GetDependencies(bool traverse = true, bool exclusive_only = false) const;
QList<Node*> GetExclusiveDependencies() const;
QList<Node*> GetImmediateDependencies() const;
signals:
void ValueChanged(const OLIVE_NAMESPACE::TimeRange& range);
void KeyframeEnableChanged(bool);
void KeyframeAdded(NodeKeyframePtr key);
void KeyframeRemoved(NodeKeyframePtr key);
void PropertyChanged(const QString& s, const QVariant& v);
protected:
virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled);
virtual void SaveInternal(QXmlStreamWriter* writer) const;
private:
void Init(NodeParam::DataType type);
void SetDefaultValue(const QVector<QVariant> &default_value);
QString ValueToString(const QVariant& value) const;
QVariant StringToValue(const QString &string, QList<XMLNodeData::FootageConnection> &footage_connections);
void SaveConnections(QXmlStreamWriter* writer) const;
/**
* @brief Returns whether a data type can be interpolated or not
*/
static bool type_can_be_interpolated(DataType type);
/**
* @brief We use Qt signals/slots for keyframe communication but store them as shared ptrs. This function converts
* a raw ptr to a list index
*/
int FindIndexOfKeyframeFromRawPtr(NodeKeyframe* raw_ptr) const;
/**
* @brief Internal insert function, automatically does an insertion sort based on the keyframe's time
*/
void insert_keyframe_internal(NodeKeyframePtr key);
/**
* @brief Return whether the standard value should be used over keyframe data
*/
bool is_using_standard_value(int track) const;
/**
* @brief Intelligently determine how what time range is affected by a keyframe
*/
TimeRange get_range_affected_by_keyframe(NodeKeyframe *key) const;
/**
* @brief Gets a time range between the previous and next keyframes of index
*/
TimeRange get_range_around_index(int index, int track) const;
/**
* @brief Convenience function - equivalent to calling `emit ValueChanged(range.in(), range.out())`
*/
void emit_time_range(const TimeRange& range);
/**
* @brief Convenience function - equivalent to calling `emit_time_range(get_range_affected_by_keyframe(key))`
*/
void emit_range_affected_by_keyframe(NodeKeyframe* key);
/**
* @brief Internal list of accepted data types
*
* Use can_accept_type() to check if a type is in this list
*/
DataType data_type_;
/**
* @brief Internal keyframable value
*/
bool keyframable_;
/**
* @brief Non-keyframed value
*/
QVector<QVariant> standard_value_;
/**
* @brief Default value that can be reset if the user requests
*/
QVector<QVariant> default_value_;
/**
* @brief Internal keyframe array
*
* If keyframing is enabled, this data is used instead of standard_value.
*/
QVector< QList<NodeKeyframePtr> > keyframe_tracks_;
/**
* @brief Internal keyframing enabled setting
*/
bool keyframing_;
/**
* @brief Internal properties variable
*/
QHash<QString, QVariant> properties_;
private slots:
/**
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
*/
void KeyframeTimeChanged();
/**
* @brief Slot when a keyframe's value changes to signal that the cache needs updating
*/
void KeyframeValueChanged();
/**
* @brief Slot when a keyframe's type changes to signal that the cache needs updating
*/
void KeyframeTypeChanged();
/**
* @brief Slot when a keyframe's bezier in value changes to signal that the cache needs updating
*/
void KeyframeBezierInChanged();
/**
* @brief Slot when a keyframe's bezier out value changes to signal that the cache needs updating
*/
void KeyframeBezierOutChanged();
};
OLIVE_NAMESPACE_EXIT
#endif // NODEINPUT_H
|