The EffectField class. More...
#include <effectfield.h>
Public Types | |
enum | EffectFieldType { EFFECT_FIELD_DOUBLE, EFFECT_FIELD_COLOR, EFFECT_FIELD_STRING, EFFECT_FIELD_BOOL, EFFECT_FIELD_COMBO, EFFECT_FIELD_FONT, EFFECT_FIELD_FILE, EFFECT_FIELD_UI } |
The EffectFieldType enum. More... | |
Signals | |
void | Changed () |
Changed signal. More... | |
void | Clicked () |
Clicked signal. More... | |
void | EnabledChanged (bool) |
Enable change state signal. More... | |
Public Member Functions | |
EffectField (EffectRow *parent, const QString &i, EffectFieldType t) | |
EffectField Constructor. More... | |
EffectRow * | GetParentRow () |
Get the EffectRow that this field is a member of. More... | |
const EffectFieldType & | type () |
Get the type of data to expect from this field. More... | |
const QString & | id () |
Get the unique identifier of this field set in the constructor. More... | |
QVariant | GetValueAt (double timecode) |
Get the value of this field at a given timecode. More... | |
void | SetValueAt (double time, const QVariant &value) |
Set the value of this field at a given timecode. More... | |
double | Now () |
Get the current clip/media time. More... | |
void | PrepareDataForKeyframing (bool enabled, ComboAction *ca) |
Set up keyframing on this field. More... | |
int | GetColumnSpan () |
Get field's column span. More... | |
void | SetColumnSpan (int i) |
Set field's column span. More... | |
virtual QString | ConvertValueToString (const QVariant &v) |
Convert a value from this field to a string. More... | |
virtual QVariant | ConvertStringToValue (const QString &s) |
Convert a string to a value appropriate for this field. More... | |
virtual QWidget * | CreateWidget (QWidget *existing=nullptr)=0 |
Create a widget for the user to interact with this field. More... | |
virtual void | UpdateWidgetValue (QWidget *widget, double timecode) |
Update a widget created by CreateWidget() using the value at a given time. More... | |
double | GetValidKeyframeHandlePosition (int key, bool post) |
Get the correct X position/time value of a bezier keyframe's handles. More... | |
bool | IsEnabled () |
Return whether this field is enabled or not. More... | |
void | SetEnabled (bool e) |
Set the enabled state of this field. More... | |
Public Attributes | |
QVariant | persistent_data_ |
Persistent data object. More... | |
QVector< EffectKeyframe > | keyframes |
Keyframe array. More... | |
Private Member Functions | |
bool | HasKeyframes () |
Used by GetValueAt() to determine whether to use keyframe data or persistent data. More... | |
double | FrameToSeconds (long frame) |
Convert clip time in frames to clip time in seconds. More... | |
long | SecondsToFrame (double seconds) |
Convert clip time in seconds to clip time in frames. More... | |
void | GetKeyframeData (double timecode, int &before, int &after, double &d) |
Internal function for determining where we are between the available keyframes. More... | |
long | NowInFrames () |
Retrieve the current clip as a frame number. More... | |
Private Attributes | |
EffectFieldType | type_ |
Internal type variable set in the constructor. Access with type(). More... | |
QString | id_ |
Internal unique identifier for this field set in the constructor. Access with id(). More... | |
bool | enabled_ |
Internal enabled value. More... | |
int | colspan_ |
Internal column span value. More... | |
The EffectField class.
Any user-interactive element of an Effect. Usually a parameter that modifies the effect output, but sometimes just a UI object that performs some other function (e.g. LabelField and ButtonField).
EffectField provides a largely abstract interface for Effect classes to pull information from. The class itself handles keyframing between linear, bezier, and hold interpolation accessible through GetValueAt(). This class is abstract, and therefore never intended to be used on its own. Instead you should always use a derived class.
EffectField objects are not UI objects on their own. Instead, they're largely a system of values that can change over time. For a widget that the user can use to edit/modify these values, use CreateWidget().
Derived classes are expected to override at least CreateWidget() to create a visual interactive widget corresponding to the field. If this field is a value used in the Effect (as most will be), UpdateWidgetValue() should also be overridden to display the correct value for this field as the user moves around the Timeline.
If the field is intended to be saved and loaded from Olive project files (as most will be), ConvertStringToValue() and ConvertValueToString() may also have to be overridden depending on how the derived class's data works.
The EffectFieldType enum.
Predetermined types of fields. Used throughout Olive to identify what kind of data to expect from GetValueAt().
This enum is also currently used to match an external XML effect's fields with the correct derived class (e.g. EFFECT_FIELD_DOUBLE matches to DoubleField).
Enumerator | |
---|---|
EFFECT_FIELD_DOUBLE |
Values are doubles. Also corresponds to DoubleField. |
EFFECT_FIELD_COLOR |
Values are colors. Also corresponds to ColorField. |
EFFECT_FIELD_STRING |
Values are strings. Also corresponds to StringField. |
EFFECT_FIELD_BOOL |
Values are booleans. Also corresponds to BoolField. |
EFFECT_FIELD_COMBO |
Values are arbitrary data. Also corresponds to ComboField. |
EFFECT_FIELD_FONT |
Values are font family names (in string). Also corresponds to FontField. |
EFFECT_FIELD_FILE |
Values are filenames (in string). Also corresponds to FileField. |
EFFECT_FIELD_UI |
Values is a UI object with no data. Corresponds to nothing. |
EffectField::EffectField | ( | EffectRow * | parent, |
const QString & | i, | ||
EffectFieldType | t | ||
) |
EffectField Constructor.
Creates a new EffectField object.
parent | The EffectRow to add this field to. This must be a valid EffectRow. The EffectRow takes ownership of the field using the QObject parent/child system to automate memory management. EffectFields are never expected to change parent during their lifetime. |
i | Field ID. Must be non-empty. Must also be unique within this Effect. Used for saving/loading values into project files so that if ordering of fields are changed, or fields are added/removed from Effects later in development, saved values in project files will still link with the correct field. Also used as the uniform variable name in GLSL shaders. |
t | The type of data contained within this field. This is expected to be filled by a derived class. |
|
signal |
Changed signal.
Emitted whenever SetValueAt() is called in order to trigger a UI update and Viewer repaint. Note this is NOT triggered as the value changes from keyframing. Only when the user themselves triggers a change.
|
signal |
Clicked signal.
Emitted when the user clicks on a QWidget attached to this field. Derived classes should connect this to the clicked signal of any QWidget's created (or attached) in CreateWidget().
|
virtual |
Convert a string to a value appropriate for this field.
This function is the inverse of ConvertValueToString(), converting a string back to field data.
s | The string to convert to data. |
QVariant data converted from the provided string.
Reimplemented in DoubleField, BoolField, and ColorField.
|
virtual |
Convert a value from this field to a string.
When saving effect data to a project file, the data needs to be converted to a string format for saving in XML. The needs of this string representation may differ depending on the needs of the derived class, therefore you derived classes may need to override it.
Default behavior is a simple QVariant <-> QString conversion, which should suffice in most cases.
v | The QVariant data (retrieved from this field) to convert to string |
A string representation of the QVariant data provided.
Reimplemented in DoubleField, BoolField, and ColorField.
|
pure virtual |
Create a widget for the user to interact with this field.
EffectField objects are not UI objects on their own. Instead, they're largely a system of values that can change over time. This function creates a QWidget object that can be placed somewhere in the UI so the user can interact with and change the data in this field.
This function must be overridden by derived classes in order to create a widget that appropriate for that field's data. The derived class is also responsible for connecting signals like EnabledChanged(), Clicked(), and any other data that needs to be transferred between the widget and the field (setting up the signals and slots to do so). The field does NOT retain ownership (or any reference for that matter) to widgets it creates, so keeping the widget and field up to date with each other relies solely on setting up signals and slots. Infinite widgets can be created from a single field and used throughout Olive this way.
Ownership is passed to the caller, and therefore the caller is responsible for freeing it.
existing | Olive allows multiple effects to attach to one UI layout. Pass a QWidget to this parameter (instead of nullptr) to attach this field additionally to the widget's signals/slots without creating a new one. The QWidget must be a widget previously created from the same derived class type or the result is undefined. |
A new QWidget object for this EffectField, or the same QWidget passed to existing
if one was specified.
Implemented in DoubleField, ComboField, ButtonField, StringField, FontField, FileField, BoolField, ColorField, and LabelField.
|
signal |
Enable change state signal.
Emitted when the field's enabled state is changed through SetEnabled(). Derived classes should connect this to the setEnabled() slot of any QWidget's created (or attached) in CreateWidget().
|
private |
int EffectField::GetColumnSpan | ( | ) |
Get field's column span.
Used whenever constructing the effect's UI. EffectFields are visually laid out in a table, and some widgets can be set to take up multiple columns for a better visual flow.
The current column span.
|
private |
Internal function for determining where we are between the available keyframes.
timecode | Timecode to get keyframe data at |
before | The index (in the keyframes array) in the keyframe prior to this timecode. |
after | The index (in the keyframes array) in the keyframe after this timecode. |
d | The progress between the before keyframe and after keyframe from 0.0 to 1.0. |
EffectRow * EffectField::GetParentRow | ( | ) |
double EffectField::GetValidKeyframeHandlePosition | ( | int | key, |
bool | post | ||
) |
Get the correct X position/time value of a bezier keyframe's handles.
Retrieves the X value (time value) of a bezier keyframe's handles. Internally, the handles' X values are allowed to be arbitrary values. This however can lead to inadvertently creating impossible bezier curves (ones that, for example, mathematically loop over each other, but obviously a field can't have two values at the same time).
This function returns the keyframe handles' X values adjusted to prevent this from happening. All calculations are consistent (i.e. the post handle of one keyframe will be adjusted the same way as the pre handle of the keyframe before it). It's recommended to always use this function to retrieve keyframe handle X values.
key | Index of the keyframe (in keyframes ) to retrieve the handle position from. |
post | FALSE to retrieve the "pre" handle (handle to the left of the keyframe), TRUE to retrieve the "post" handle (handle to the right of the keyframe). |
The adjusted X value of that keyframe handle.
QVariant EffectField::GetValueAt | ( | double | timecode | ) |
Get the value of this field at a given timecode.
EffectFields are designed to be keyframable, meaning the user can make the values change over the course of the Sequence. This is the main function used through Olive to retrieve what value this field will be at a given time.
A common use case for this function would be EffectField::GetValueAt(EffectField::Now()), which will automatically retrieve the timecode at the current playhead.
If the parent EffectRow is NOT keyframing, this function will simply return persistent_data_. If it IS keyframing, this will use the values in keyframes
to determine what value should be specifically at this time. (bezier or linear interpolating it between values if necessary). Therefore this function should almost always be used to retrieve data from this field as the value will always be correct for the given time.
timecode | The time to retrieve the value in clip/media seconds (e.g. 0.0 is the very start of the media, 1.0 is one second into the media). |
A QVariant representation of the value at the given timecode.
|
private |
Used by GetValueAt() to determine whether to use keyframe data or persistent data.
TRUE if this keyframe data should be retrieved, FALSE if persistent data should be retrieved
const QString & EffectField::id | ( | ) |
Get the unique identifier of this field set in the constructor.
Mostly used for saving/loading or interacting with GLSL-based shader effects (see EffectField() for more details).
bool EffectField::IsEnabled | ( | ) |
Return whether this field is enabled or not.
TRUE if this field is enabled.
double EffectField::Now | ( | ) |
Get the current clip/media time.
A convenience function that can be plugged into GetValueAt() to get the value wherever the appropriate Sequence's playhead it.
Current clip/media time in seconds.
|
private |
void EffectField::PrepareDataForKeyframing | ( | bool | enabled, |
ComboAction * | ca | ||
) |
Set up keyframing on this field.
This should always be called if the user is enabling/disabling keyframing on the parent row. This function will move data between persistent_data_ and keyframes depending on whether keyframing is being enabled or disabled.
If keyframing is getting ENABLED, this function will create the first keyframe automatically at the current time using the current value in persistent_data_.
If keyframing is getting DISABLED, persistent_data_ is set to the current value at this time (GetValueAt(Now())) and delete all current keyframes.
enabled | TRUE if keyframing is getting enabled. |
ca | A valid ComboAction object. It's expected that this function will be part of a larger action to enable/disable keyframing on the parent EffectRow, so this function will add commands to this ComboAction. |
|
private |
void EffectField::SetColumnSpan | ( | int | i | ) |
Set field's column span.
Used whenever constructing the effect's UI. EffectFields are visually laid out in a table, and some widgets can be set to take up multiple columns for a better visual flow.
i | The column span to set on this field. |
void EffectField::SetEnabled | ( | bool | e | ) |
Set the enabled state of this field.
e | TRUE to enable this field, FALSE to disable it. |
void EffectField::SetValueAt | ( | double | time, |
const QVariant & | value | ||
) |
Set the value of this field at a given timecode.
EffectFields are designed to be keyframable, meaning the user can make the values change over the course of the Sequence. This is the main function used through Olive to set what value this field will be at a given time.
If the parent EffectRow is keyframing, this function will determine whether a keyframe exists at this time already. If it does, it will change the value at that keyframe to value
. Otherwise, it'll create a new keyframe at the specified time
with the specified value
.
If the parent EffectRow is not keyframing, the data is simply stored in persistent_data_
.
When constructing an Effect
time | The time to retrieve the value at in clip/media seconds (e.g. 0.0 is the very start of the media, 1.0 is one second into the media). |
value | The QVariant value to set at this time. |
const EffectField::EffectFieldType & EffectField::type | ( | ) |
Get the type of data to expect from this field.
A member of the EffectFieldType enum.
|
virtual |
Update a widget created by CreateWidget() using the value at a given time.
Use this function to update a QWidget (obtained from CreateWidget()) with the correct value from the field at a given time.
Since only the derived classes know what type of QWidget it created in CreateWidget() and how to work with them, derived classes are also expected to override this function if the field is an active value used in the Effect that should visually update as the user moves around the Timeline. However if the field does NOT need to update live (e.g. the field is just a UI wrapper like LabelField or ButtonField), this function does not need to be overridden as the default behavior (to do nothing) will suffice in those cases.
widget | The QWidget to set the value of (must be a QWidget obtained from CreateWidget() or the behavior is undefined). |
timecode | The time in clip/media seconds to retrieve data from. |
Reimplemented in DoubleField, ComboField, StringField, FontField, FileField, BoolField, and ColorField.
|
private |
Internal column span value.
|
private |
Internal enabled value.
|
private |
Internal unique identifier for this field set in the constructor. Access with id().
QVector<EffectKeyframe> EffectField::keyframes |
Keyframe array.
Contains all data about this field's keyframes, from the keyframe times, to their data, to their type (linear, bezier, or hold), to the bezier handles (if using bezier). If the row is not keyframing, this array is never used (persistent_data_
is used instead). If it is, this array will always be used unless the array is empty, in which case persistent_data_
will be used again.
QVariant EffectField::persistent_data_ |
Persistent data object.
If the parent EffectRow is not keyframing, all field data is stored and retrieved here. If the row IS keyframing, this variable goes basically unused unless keyframes
is empty.
NOTE: It is NOT recommended to access this variable directly. Use GetValueAt() instead.
|
private |
Internal type variable set in the constructor. Access with type().