documented EffectUI

This commit is contained in:
itsmattkc
2019-03-16 16:21:52 +11:00
parent 9b86bc4b32
commit 7d80c11d37
6 changed files with 383 additions and 51 deletions
+13 -17
View File
@@ -93,11 +93,6 @@ QString EffectField::ConvertValueToString(const QVariant &v)
return v.toString();
}
QWidget *EffectField::CreateWidget(QWidget *existing)
{
Q_ASSERT(false);
}
void EffectField::UpdateWidgetValue(QWidget *, double) {}
QVariant EffectField::GetValueAt(double timecode)
@@ -106,7 +101,7 @@ QVariant EffectField::GetValueAt(double timecode)
int before_keyframe;
int after_keyframe;
double progress;
get_keyframe_data(timecode, before_keyframe, after_keyframe, progress);
GetKeyframeData(timecode, before_keyframe, after_keyframe, progress);
const QVariant& before_data = keyframes.at(before_keyframe).data;
switch (type_) {
@@ -133,7 +128,7 @@ QVariant EffectField::GetValueAt(double timecode)
if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) {
// cubic bezier
double t = cubic_t_from_x(timecodeToFrame(timecode),
double t = cubic_t_from_x(SecondsToFrame(timecode),
before_key.time,
before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true),
after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false),
@@ -148,7 +143,7 @@ QVariant EffectField::GetValueAt(double timecode)
} else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier
// last keyframe is the bezier one
double t = quad_t_from_x(timecodeToFrame(timecode),
double t = quad_t_from_x(SecondsToFrame(timecode),
before_key.time,
before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true),
after_key.time);
@@ -160,7 +155,7 @@ QVariant EffectField::GetValueAt(double timecode)
} else {
// this keyframe is the bezier one
double t = quad_t_from_x(timecodeToFrame(timecode),
double t = quad_t_from_x(SecondsToFrame(timecode),
before_key.time,
after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false),
after_key.time);
@@ -215,7 +210,7 @@ void EffectField::SetValueAt(double time, const QVariant &value)
// Create keyframe here
// Convert seconds timecode to frame
long frame_timecode = timecodeToFrame(time);
long frame_timecode = SecondsToFrame(time);
// Check array if a keyframe at this time already exists
int keyframe_index = -1;
@@ -345,20 +340,20 @@ double EffectField::GetValidKeyframeHandlePosition(int key, bool post) {
return adjusted_key;
}
double EffectField::frameToTimecode(long frame) {
double EffectField::FrameToSeconds(long frame) {
return (double(frame) / GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate);
}
long EffectField::timecodeToFrame(double timecode) {
return qRound(timecode * GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate);
long EffectField::SecondsToFrame(double seconds) {
return qRound(seconds * GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate);
}
void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) {
void EffectField::GetKeyframeData(double timecode, int &before, int &after, double &progress) {
int before_keyframe_index = -1;
int after_keyframe_index = -1;
long before_keyframe_time = LONG_MIN;
long after_keyframe_time = LONG_MAX;
long frame = timecodeToFrame(timecode);
long frame = SecondsToFrame(timecode);
for (int i=0;i<keyframes.size();i++) {
long eval_keyframe_time = keyframes.at(i).time;
@@ -375,11 +370,12 @@ void EffectField::get_keyframe_data(double timecode, int &before, int &after, do
}
}
if ((type_ == EFFECT_FIELD_DOUBLE || type_ == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) {
if ((type_ == EFFECT_FIELD_DOUBLE || type_ == EFFECT_FIELD_COLOR)
&& (before_keyframe_index > -1 && after_keyframe_index > -1)) {
// interpolate
before = before_keyframe_index;
after = after_keyframe_index;
progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time));
progress = (timecode-FrameToSeconds(before_keyframe_time))/(FrameToSeconds(after_keyframe_time)-FrameToSeconds(before_keyframe_time));
} else if (before_keyframe_index > -1) {
before = before_keyframe_index;
after = before_keyframe_index;
+9 -12
View File
@@ -60,6 +60,11 @@ bool EffectRow::IsKeyframing() {
}
void EffectRow::SetKeyframingInternal(bool b) {
// No need to run this function if the keyframing state isn't actually changing.
if (b == keyframing_) {
return;
}
if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) {
keyframing_ = b;
emit KeyframingSetChanged(keyframing_);
@@ -77,6 +82,10 @@ bool EffectRow::IsKeyframable()
}
void EffectRow::SetKeyframingEnabled(bool enabled) {
if (enabled == keyframing_) {
return;
}
if (enabled) {
ComboAction* ca = new ComboAction();
@@ -257,18 +266,6 @@ void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) {
panel_effect_controls->update_keyframes();
}
void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) {
for (int j=0;j<FieldCount();j++) {
EffectField* f = Field(j);
for (int i=0;i<f->keyframes.size();i++) {
if (f->keyframes.at(i).time == time) {
ca->append(new KeyframeDelete(f, i));
break;
}
}
}
}
Effect *EffectRow::GetParentEffect()
{
return static_cast<Effect*>(parent());
+186 -3
View File
@@ -36,43 +36,226 @@ class ClickableLabel;
#include "effectfields.h"
/**
* @brief The EffectRow class
*
* Primarily a way of grouping EffectField objects together. As UI objects, Effects are largely formatted as a table
* and you can think of EffectRows as the rows of the table and EffectFields as the columns.
*
* Within Olive, keyframing is enabled on the EffectRow (rather than individual EffectFields) so all attached fields
* will be keyframed together.
*
* Unlike EffectField, there's no reason to derive from EffectRow as it's simply a container of fields and a few
* keyframe functions.
*/
class EffectRow : public QObject {
Q_OBJECT
public:
/**
* @brief EffectRow Constructor
*
* @param parent
*
* Every EffectRow object must be attached to a valid Effect object. The Effect object takes ownership of the
* EffectRow and automatically frees it through the QObject parent/child system. EffectRows are never intended to
* change parents throughout their lifetimes.
*
* @param n
*
* Row name. This is not used as an internal identifier, it's just for the user interface, so it can be translated
* with no issue.
*
* @param savable
*
* Whether the fields in this row should be saved to the project file. This is true by default. If the row contains
* non-value UI widgets, setting this to false is recommended.
*
* @param keyframable
*
* Whether keyframing can be enabled on this row or not. This is true by default. Some values you may want to prevent
* the user from keyframing (e.g. the filename of a VST plugin), which can be done by setting this to false.
*/
EffectRow(Effect* parent, const QString& n, bool savable = true, bool keyframable = true);
/**
* @brief Add a field to this row
*
* Ownership of the EffectField is transferred to this row and the row will free its memory. In the Effect's UI, this
* will add the field to an additional column.
*
* @param Field
*
* The field to add to this row.
*/
void AddField(EffectField* Field);
/**
* @brief Retrieve the EffectField at this index. Must be less than FieldCount().
*
* @param i
*
* Index to retrieve the EffectField at.
*
* @return
*
* EffectField at the provided index.
*/
EffectField* Field(int i);
int FieldCount();
void SetKeyframeOnAllFields(ComboAction *ca);
void delete_keyframe_at_time(ComboAction *ca, long time);
/**
* @brief Number of fields currently contained in this row.
*
* @return The number of fields currently contained in this row as an integer. Any field index (retrieved with
* Field()) is guaranteed to be valid >= 0 and < FieldCount().
*/
int FieldCount();
/**
* @brief Set a keyframe at the current playhead on all fields contained within this row
*
* @param ca
*
* The ComboAction to add this action to. This may not be nullptr.
*/
void SetKeyframeOnAllFields(ComboAction *ca);
/**
* @brief Get parent Effect
*
* Equivalent to `static_cast<Effect*>(parent())`.
*
* @return The parent Effect object that this row is attached to.
*/
Effect* GetParentEffect();
/**
* @brief Return the row's name
*
* @return The name specified in the constructor as a QString
*/
const QString& name();
/**
* @brief Get whether this row is keyframing or not
*
* @return True if this row is keyframing.
*/
bool IsKeyframing();
/**
* @brief Set whether this row is keyframing or not.
*
* It's not recommended to use this function for any user-initiated keyframe setting change as it doesn't create any
* undoable actions. Use SetKeyframingEnabled() instead for a user-friendly variant.
*/
void SetKeyframingInternal(bool);
/**
* @brief Get whether this row should be saved into a project file or not
*
* @return True if this row should be saved. This value is set in the constructor.
*/
bool IsSavable();
/**
* @brief Get whether this row can be keyframed or not.
*
* @return True if this row can be keyframed. This value is set in the constructor.
*/
bool IsKeyframable();
public slots:
/**
* @brief Go to previous keyframe
*
* Gets the closest keyframe prior to the current playhead and seeks to it.
*
* Attach to KeyframeNavigator::goto_previous_key() signal.
*/
void GoToPreviousKeyframe();
/**
* @brief Toggle a keyframe at this point in time
*
* Either deletes (if any child EffectFields have any keyframes here) or creates (if none do) a keyframe on all
* EffectField children at the current time.
*
* Attach to KeyframeNavigator::toggle_key() signal.
*/
void ToggleKeyframe();
/**
* @brief Go to next keyframe
*
* Gets the closest keyframe after the current playhead and seeks to it.
*
* Attach to KeyframeNavigator::goto_next_key() signal.
*/
void GoToNextKeyframe();
/**
* @brief Slot for whenever this EffectRow is focused.
*
* Connect UI objects gaining focus to this slot. Automatically updates the Graph Editor to attach to this row.
*/
void FocusRow();
signals:
/**
* @brief Keyframing setting changed signal
*
* Emitted whenever keyframing is enabled or disabled.
*
* @param
*
* True if keyframing was enabled, false if keyframing was disabled.
*/
void KeyframingSetChanged(bool);
private slots:
/**
* @brief Set keyframing enabled state
*
* A user-friendly function for enabling or disabling keyframes on this row. Preferred to SetKeyframingInternal()
* for any user-initiated change. Automatically creates an undoable action so users can undo the enabling/disabling.
* Also confirms with the user when disabling keyframing whether they wish to continue and remove all the current
* keyframes.
*
* Attach to KeyframeNavigator::keyframe_enabled_changed() signal.
*/
void SetKeyframingEnabled(bool);
private:
/**
* @brief Internal variable for the row's name
*
* Set in the constructor, retrieved with name().
*/
QString name_;
/**
* @brief Internal variable for whether this row can be keyframed.
*
* Set in the constructor, retrieved with IsKeyframable().
*/
bool keyframable_;
/**
* @brief Internal variable for whether this row is currently keyframing.
*
* Set by SetKeyframingInternal() and retrieved with IsKeyframing().
*/
bool keyframing_;
/**
* @brief Internal variable for whether this row should be saved.
*
* Set in the constructor, retrieved with IsSavable().
*/
bool savable_;
/**
* @brief Internal array of EffectField objects.
*
* It is not necessary to delete the elements in this array as they're already children of this QObject, so they'll
* get freed automatically.
*/
QVector<EffectField*> fields_;
};