merged fxrestructure

This commit is contained in:
itsmattkc
2019-03-16 20:14:36 +11:00
289 changed files with 8975 additions and 6556 deletions
+37 -37
View File
@@ -20,7 +20,7 @@
#include "audiomonitor.h"
#include "project/sequence.h"
#include "timeline/sequence.h"
#include "rendering/audio.h"
#include "panels/panels.h"
#include "panels/timeline.h"
@@ -39,60 +39,60 @@ extern "C" {
}
AudioMonitor::AudioMonitor(QWidget *parent) :
QWidget(parent)
QWidget(parent)
{
clear_timer.setInterval(500);
connect(&clear_timer, SIGNAL(timeout()), this, SLOT(clear()));
clear_timer.setInterval(500);
connect(&clear_timer, SIGNAL(timeout()), this, SLOT(clear()));
}
void AudioMonitor::set_value(const QVector<double> &ivalues) {
values = ivalues;
update();
values = ivalues;
update();
QMetaObject::invokeMethod(&clear_timer, "start", Qt::QueuedConnection);
QMetaObject::invokeMethod(&clear_timer, "start", Qt::QueuedConnection);
}
void AudioMonitor::clear() {
clear_timer.stop();
clear_timer.stop();
values.fill(1);
update();
values.fill(1);
update();
}
void AudioMonitor::resizeEvent(QResizeEvent *e) {
gradient = QLinearGradient(QPoint(0, rect().top()), QPoint(0, rect().bottom()));
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(0.25, Qt::yellow);
gradient.setColorAt(1, Qt::green);
QWidget::resizeEvent(e);
gradient = QLinearGradient(QPoint(0, rect().top()), QPoint(0, rect().bottom()));
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(0.25, Qt::yellow);
gradient.setColorAt(1, Qt::green);
QWidget::resizeEvent(e);
}
void AudioMonitor::paintEvent(QPaintEvent *) {
if (olive::ActiveSequence != nullptr && values.size() > 0) {
QPainter p(this);
int channel_x = AUDIO_MONITOR_GAP;
int channel_count = values.size();
int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP;
int i;
for (i=0;i<channel_count;i++) {
QRect r(channel_x, AUDIO_MONITOR_PEAK_HEIGHT + AUDIO_MONITOR_GAP, channel_width, height());
p.fillRect(r, gradient);
if (olive::ActiveSequence != nullptr && values.size() > 0) {
QPainter p(this);
int channel_x = AUDIO_MONITOR_GAP;
int channel_count = values.size();
int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP;
int i;
for (i=0;i<channel_count;i++) {
QRect r(channel_x, AUDIO_MONITOR_PEAK_HEIGHT + AUDIO_MONITOR_GAP, channel_width, height());
p.fillRect(r, gradient);
bool peak = false;
bool peak = false;
r.setHeight(qRound(r.height()*(values.at(i))));
peak = (r.height() == 0);
r.setHeight(qRound(r.height()*(values.at(i))));
peak = (r.height() == 0);
QRect peak_rect(channel_x, 0, channel_width, AUDIO_MONITOR_PEAK_HEIGHT);
if (peak) {
p.fillRect(peak_rect, QColor(255, 0, 0));
} else {
p.fillRect(peak_rect, QColor(64, 0, 0));
}
QRect peak_rect(channel_x, 0, channel_width, AUDIO_MONITOR_PEAK_HEIGHT);
if (peak) {
p.fillRect(peak_rect, QColor(255, 0, 0));
} else {
p.fillRect(peak_rect, QColor(64, 0, 0));
}
p.fillRect(r, QColor(0, 0, 0, 160));
p.fillRect(r, QColor(0, 0, 0, 160));
channel_x += channel_width + AUDIO_MONITOR_GAP;
}
}
channel_x += channel_width + AUDIO_MONITOR_GAP;
}
}
}
+60 -9
View File
@@ -24,28 +24,79 @@
#include <QWidget>
#include <QTimer>
/**
* @brief The AudioMonitor class
*
* Used to show a visual representation of audio currently playing
*/
class AudioMonitor : public QWidget
{
Q_OBJECT
Q_OBJECT
public:
explicit AudioMonitor(QWidget *parent = 0);
void set_value(const QVector<double>& values);
/**
* @brief AudioMonitor Constructor
* @param parent
*
* QWidget parent object.
*/
explicit AudioMonitor(QWidget *parent = nullptr);
/**
* @brief Set the current audio value
*
* The main interface for updating the audio monitor. Using this function will redraw the monitor with the values
* specified.
*
* @param values
*
* An array of doubles between 0.0 and 1.0 to display the amplitude. 0.0 is no audio, 1.0 is full volume. Each array
* entry is a channel and the audio monitor will automatically adjust to the channel count in the array.
*/
void set_value(const QVector<double>& values);
protected:
void paintEvent(QPaintEvent *);
void resizeEvent(QResizeEvent *);
/**
* @brief Internal paint event
*
* Paints the
*/
void paintEvent(QPaintEvent *);
/**
* @brief Internal resize event handler
*
* Triggers a repaint when the widget is resized.
*/
void resizeEvent(QResizeEvent *);
signals:
public slots:
private:
QLinearGradient gradient;
QVector<double> values;
QTimer clear_timer;
/**
* @brief Internal gradient object from red to yellow to green
*/
QLinearGradient gradient;
/**
* @brief Internal value storage
*/
QVector<double> values;
/**
* @brief Internal timer to clear the audio monitor after a certain amount of time
*
* If it doesn't receive any values within a certain amount of time, it's assumed audio is no longer playing and the
* monitor is cleared.
*/
QTimer clear_timer;
private slots:
void clear();
/**
* @brief Slot to clear the audio monitor
*/
void clear();
};
#endif // AUDIOMONITOR_H
+65
View File
@@ -0,0 +1,65 @@
#include "blur.h"
void olive::ui::blur(QImage& result, const QRect& rect, int radius, bool alphaOnly) {
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
int i1 = 0;
int i2 = 3;
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef BLUR_H
#define BLUR_H
#include <QImage>
#include <QRect>
namespace olive {
namespace ui {
/**
* @brief Convenience function for blurring a QImage
*
* @param result
*
* QImage to blur
*
* @param rect
*
* The rectangle of the QImage to blur. Use QImage::rect() to blur the entire image.
*
* @param radius
*
* The blur radius - how much to blur the image.
*
* @param alphaOnly
*
* True if only the alpha channel should be blurred rather than the entire RGBA space.
*/
void blur(QImage& result, const QRect& rect, int radius, bool alphaOnly);
}
}
#endif // BLUR_H
+4 -3
View File
@@ -20,13 +20,14 @@
#include "checkboxex.h"
#include "project/undo.h"
#include "undo/undostack.h"
#include "undo/undo.h"
CheckboxEx::CheckboxEx(QWidget* parent) : QCheckBox(parent) {
// connect(this, SIGNAL(clicked(bool)), this, SLOT(checkbox_command()));
}
void CheckboxEx::checkbox_command() {
CheckboxCommand* c = new CheckboxCommand(this);
olive::UndoStack.push(c);
CheckboxCommand* c = new CheckboxCommand(this);
olive::UndoStack.push(c);
}
+17 -11
View File
@@ -33,7 +33,7 @@
#include "ui/checkboxex.h"
#include "ui/icons.h"
#include "debug.h"
#include "global/debug.h"
CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) {
selected = false;
@@ -52,8 +52,8 @@ CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) {
header = new QLabel(title_bar);
collapse_button = new QPushButton(title_bar);
collapse_button->setIconSize(collapse_button->iconSize()*0.5);
collapse_button->setStyleSheet("QPushButton { border: none; }");
setText(tr("<untitled>"));
collapse_button->setFlat(true);
SetTitle(tr("<untitled>"));
title_bar_layout->addWidget(collapse_button);
title_bar_layout->addWidget(enabled_check);
title_bar_layout->addWidget(header);
@@ -80,35 +80,41 @@ void CollapsibleWidget::header_click(bool s, bool deselect) {
if (deselect) emit deselect_others(this);
}
bool CollapsibleWidget::is_focused() {
bool CollapsibleWidget::IsFocused() {
if (hasFocus()) return true;
return title_bar->hasFocus();
}
bool CollapsibleWidget::is_expanded() {
bool CollapsibleWidget::IsExpanded() {
return contents->isVisible();
}
bool CollapsibleWidget::IsSelected()
{
return selected;
}
void CollapsibleWidget::set_button_icon(bool open) {
collapse_button->setIcon(open ? olive::icon::DownArrow : olive::icon::RightArrow);
}
void CollapsibleWidget::setContents(QWidget* c) {
void CollapsibleWidget::SetContents(QWidget* c) {
bool existing = (contents != nullptr);
contents = c;
if (!existing) {
layout->addWidget(contents);
connect(enabled_check, SIGNAL(toggled(bool)), this, SLOT(on_enabled_change(bool)));
connect(enabled_check, SIGNAL(toggled(bool)), contents, SLOT(setEnabled(bool)));
connect(collapse_button, SIGNAL(clicked()), this, SLOT(on_visible_change()));
}
}
void CollapsibleWidget::setText(const QString &s) {
header->setText(s);
QString CollapsibleWidget::Title()
{
return header->text();
}
void CollapsibleWidget::on_enabled_change(bool b) {
contents->setEnabled(b);
void CollapsibleWidget::SetTitle(const QString &s) {
header->setText(s);
}
void CollapsibleWidget::on_visible_change() {
+11 -10
View File
@@ -35,7 +35,7 @@
class CollapsibleWidgetHeader : public QWidget {
Q_OBJECT
public:
CollapsibleWidgetHeader(QWidget* parent = 0);
CollapsibleWidgetHeader(QWidget* parent = nullptr);
bool selected;
protected:
void mousePressEvent(QMouseEvent* event);
@@ -48,17 +48,19 @@ class CollapsibleWidget : public QWidget
{
Q_OBJECT
public:
CollapsibleWidget(QWidget* parent = 0);
void setContents(QWidget* c);
void setText(const QString &);
bool is_focused();
bool is_expanded();
CollapsibleWidget(QWidget* parent = nullptr);
void SetContents(QWidget* c);
QString Title();
void SetTitle(const QString &);
bool IsFocused();
bool IsExpanded();
bool IsSelected();
protected:
CheckboxEx* enabled_check;
bool selected;
QWidget* contents;
CollapsibleWidgetHeader* title_bar;
QWidget* contents;
private:
bool selected;
QLabel* header;
QVBoxLayout* layout;
QPushButton* collapse_button;
@@ -71,7 +73,6 @@ signals:
void visibleChanged();
private slots:
void on_enabled_change(bool b);
void on_visible_change();
public slots:
+15 -33
View File
@@ -20,52 +20,34 @@
#include "colorbutton.h"
#include "project/undo.h"
#include <QColorDialog>
ColorButton::ColorButton(QWidget *parent)
: QPushButton(parent), color(Qt::white) {
set_button_color();
connect(this, SIGNAL(clicked(bool)), this, SLOT(open_dialog()));
: QPushButton(parent), color(Qt::white) {
set_button_color();
connect(this, SIGNAL(clicked(bool)), this, SLOT(open_dialog()));
}
QColor ColorButton::get_color() {
return color;
return color;
}
void ColorButton::set_color(QColor c) {
previousColor = color;
color = c;
set_button_color();
}
const QColor &ColorButton::getPreviousValue() {
return previousColor;
color = c;
set_button_color();
}
void ColorButton::set_button_color() {
QPalette pal = palette();
pal.setColor(QPalette::Button, color);
setPalette(pal);
QPalette pal = palette();
pal.setColor(QPalette::Button, color);
setPalette(pal);
}
void ColorButton::open_dialog() {
QColor new_color = QColorDialog::getColor(color, nullptr, tr("Set Color"));
if (new_color.isValid() && color != new_color) {
set_color(new_color);
set_button_color();
emit color_changed();
}
}
ColorCommand::ColorCommand(ColorButton* s, QColor o, QColor n)
: sender(s), old_color(o), new_color(n) {}
void ColorCommand::undo() {
sender->set_color(old_color);
}
void ColorCommand::redo() {
sender->set_color(new_color);
QColor new_color = QColorDialog::getColor(color, nullptr, tr("Set Color"));
if (new_color.isValid() && color != new_color) {
set_color(new_color);
set_button_color();
emit color_changed(color);
}
}
+8 -21
View File
@@ -26,31 +26,18 @@
#include <QUndoCommand>
class ColorButton : public QPushButton {
Q_OBJECT
Q_OBJECT
public:
ColorButton(QWidget* parent = 0);
QColor get_color();
void set_color(QColor c);
const QColor& getPreviousValue();
ColorButton(QWidget* parent = nullptr);
QColor get_color();
void set_color(QColor c);
private:
QColor color;
QColor previousColor;
void set_button_color();
QColor color;
void set_button_color();
signals:
void color_changed();
void color_changed(const QColor& c);
private slots:
void open_dialog();
};
class ColorCommand : public QUndoCommand {
public:
ColorCommand(ColorButton* s, QColor o, QColor n);
void undo();
void redo();
private:
ColorButton* sender;
QColor old_color;
QColor new_color;
void open_dialog();
};
#endif // COLORBUTTON_H
+12 -52
View File
@@ -20,63 +20,23 @@
#include "comboboxex.h"
#include "project/undo.h"
#include "panels/project.h"
#include "mainwindow.h"
#include <QUndoCommand>
#include <QWheelEvent>
class ComboBoxExCommand : public QUndoCommand {
public:
ComboBoxExCommand(ComboBoxEx* obj, int old_index, int new_index) :
combobox(obj), old_val(old_index), new_val(new_index), done(true), old_project_changed(olive::MainWindow->isWindowModified()) {}
void undo() {
combobox->setCurrentIndex(old_val);
done = false;
olive::MainWindow->setWindowModified(old_project_changed);
}
void redo() {
if (!done) {
combobox->setCurrentIndex(new_val);
}
olive::MainWindow->setWindowModified(true);
}
private:
ComboBoxEx* combobox;
int old_val;
int new_val;
bool done;
bool old_project_changed;
};
ComboBoxEx::ComboBoxEx(QWidget *parent) : QComboBox(parent), index(0) {
connect(this, SIGNAL(activated(int)), this, SLOT(index_changed(int)));
ComboBoxEx::ComboBoxEx(QWidget *parent) :
QComboBox(parent)
{
}
void ComboBoxEx::setCurrentIndexEx(int i) {
index = i;
setCurrentIndex(i);
void ComboBoxEx::setScrollingEnabled(bool b)
{
scrolling_enabled_ = b;
}
void ComboBoxEx::setCurrentTextEx(const QString &text) {
setCurrentText(text);
index = currentIndex();
}
int ComboBoxEx::getPreviousIndex() {
return previousIndex;
}
void ComboBoxEx::index_changed(int i) {
if (index != i) {
previousIndex = index;
// undo_stack.push(new ComboBoxExCommand(this, index, i));
index = i;
}
}
void ComboBoxEx::wheelEvent(QWheelEvent* e) {
void ComboBoxEx::wheelEvent(QWheelEvent *e)
{
if (scrolling_enabled_) {
QComboBox::wheelEvent(e);
} else {
e->ignore();
}
}
+6 -11
View File
@@ -22,21 +22,16 @@
#define COMBOBOXEX_H
#include <QComboBox>
#include <QDebug>
class ComboBoxEx : public QComboBox {
Q_OBJECT
Q_OBJECT
public:
ComboBoxEx(QWidget* parent = 0);
void setCurrentIndexEx(int i);
void setCurrentTextEx(const QString &text);
int getPreviousIndex();
private slots:
void index_changed(int);
ComboBoxEx(QWidget* parent = nullptr);
void setScrollingEnabled(bool b);
protected:
virtual void wheelEvent(QWheelEvent* e) override;
private:
int index;
int previousIndex;
void wheelEvent(QWheelEvent* e);
bool scrolling_enabled_;
};
#endif // COMBOBOXEX_H
+312
View File
@@ -0,0 +1,312 @@
#include "effectui.h"
#include <QPoint>
#include <QMenu>
#include "timeline/clip.h"
#include "ui/menuhelper.h"
#include "ui/keyframenavigator.h"
#include "ui/clickablelabel.h"
#include "panels/panels.h"
EffectUI::EffectUI(Effect* e) :
effect_(e)
{
Q_ASSERT(e != nullptr);
QString effect_name;
// If this effect is actually a transition
if (e->meta->type == EFFECT_TYPE_TRANSITION) {
Transition* t = static_cast<Transition*>(e);
// Since effects can have two clip attachments, find out which one is selected
Clip* selected_clip = t->parent_clip;
bool both_selected = false;
// Check if this is a shared transition
if (t->secondary_clip != nullptr) {
// Check which clips are selected
if (t->secondary_clip->IsSelected()) {
selected_clip = t->secondary_clip;
if (t->parent_clip->IsSelected()) {
// Both clips are selected
both_selected = true;
}
} else if (!t->parent_clip->IsSelected()) {
// Neither are selected, but the naming scheme (no "opening" or "closing" modifier) will be the same
both_selected = true;
}
}
// See if the transition is the clip's opening or closing transition and label it accordingly
if (both_selected) {
effect_name = t->name;
} else if (selected_clip->opening_transition.get() == t) {
effect_name = tr("%1 (Opening)").arg(t->name);
} else {
effect_name = tr("%1 (Closing)").arg(t->name);
}
} else {
// Otherwise just set the title normally
effect_name = e->name;
}
SetTitle(effect_name);
QWidget* ui = new QWidget(this);
SetContents(ui);
layout_ = new QGridLayout(ui);
layout_->setSpacing(4);
connect(title_bar,
SIGNAL(customContextMenuRequested(const QPoint&)),
this,
SLOT(show_context_menu(const QPoint&)));
int maximum_column = 0;
widgets_.resize(e->row_count());
for (int i=0;i<e->row_count();i++) {
EffectRow* row = e->row(i);
ClickableLabel* row_label = new ClickableLabel(row->name());
connect(row_label, SIGNAL(clicked()), row, SLOT(FocusRow()));
labels_.append(row_label);
layout_->addWidget(row_label, i, 0);
widgets_[i].resize(row->FieldCount());
int column = 1;
for (int j=0;j<row->FieldCount();j++) {
EffectField* field = row->Field(j);
QWidget* widget = field->CreateWidget();
widgets_[i][j] = widget;
layout_->addWidget(widget, i, column, 1, field->GetColumnSpan());
column += field->GetColumnSpan();
}
// Find maximum column to place keyframe controls
maximum_column = qMax(row->FieldCount(), maximum_column);
}
// Create keyframe controls
maximum_column++;
keyframe_navigators_.resize(e->row_count());
for (int i=0;i<e->row_count();i++) {
EffectRow* row = e->row(i);
KeyframeNavigator* nav;
if (row->IsKeyframable()) {
nav = new KeyframeNavigator();
nav->enable_keyframes(row->IsKeyframing());
AttachKeyframeNavigationToRow(row, nav);
layout_->addWidget(nav, i, maximum_column);
} else {
nav = nullptr;
}
keyframe_navigators_[i] = nav;
}
enabled_check->setChecked(e->IsEnabled());
connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(SetEnabled(bool)));
connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(FieldChanged()));
}
void EffectUI::AddAdditionalEffect(Effect *e)
{
// Ensure this is the same kind of effect and will be fully compatible
Q_ASSERT(e->meta == effect_->meta);
// Add multiple modifer to header label (but only once)
if (additional_effects_.isEmpty()) {
QString new_title = tr("%1 (multiple)").arg(Title());
SetTitle(new_title);
}
// Add effect to list
additional_effects_.append(e);
// Attach this UI's widgets to the additional effect
for (int i=0;i<effect_->row_count();i++) {
EffectRow* row = effect_->row(i);
// Attach existing keyframe navigator to this effect's row
AttachKeyframeNavigationToRow(e->row(i), keyframe_navigators_.at(i));
for (int j=0;j<row->FieldCount();j++) {
// Attach existing field widget to this effect's field
e->row(i)->Field(j)->CreateWidget(Widget(i, j));
}
}
}
Effect *EffectUI::GetEffect()
{
return effect_;
}
int EffectUI::GetRowY(int row, QWidget* mapToWidget) {
// Currently to get a Y value in the context of `mapToWidget`, we use `panel_effect_controls` as the base. Mapping
// to global doesn't work for some reason, so this is the best reference point we have.
QLabel* row_label = labels_.at(row);
// Get center point of label (label->rect()->center()->y() - instead of y()+height/2 - produces an inaccurate result)
return row_label->y()
+ row_label->height() / 2
+ mapToWidget->mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y()
- title_bar->height();
}
void EffectUI::UpdateFromEffect()
{
Effect* effect = GetEffect();
for (int j=0;j<effect->row_count();j++) {
EffectRow* row = effect->row(j);
for (int k=0;k<row->FieldCount();k++) {
EffectField* field = row->Field(k);
// Check if this UI object is attached to one effect or many
if (additional_effects_.isEmpty()) {
field->UpdateWidgetValue(Widget(j, k), field->Now());
} else {
bool same_value = true;
for (int i=0;i<additional_effects_.size();i++) {
EffectField* previous_field = i > 0 ? additional_effects_.at(i-1)->row(j)->Field(k) : field;
EffectField* additional_field = additional_effects_.at(i)->row(j)->Field(k);
if (additional_field->GetValueAt(additional_field->Now()) != previous_field->GetValueAt(previous_field->Now())) {
same_value = false;
break;
}
}
if (same_value) {
field->UpdateWidgetValue(Widget(j, k), field->Now());
} else {
field->UpdateWidgetValue(Widget(j, k), qSNaN());
}
}
}
}
}
bool EffectUI::IsAttachedToClip(Clip *c)
{
if (GetEffect()->parent_clip == c) {
return true;
}
for (int i=0;i<additional_effects_.size();i++) {
if (additional_effects_.at(i)->parent_clip == c) {
return true;
}
}
return false;
}
QWidget *EffectUI::Widget(int row, int field)
{
return widgets_.at(row).at(field);
}
void EffectUI::AttachKeyframeNavigationToRow(EffectRow *row, KeyframeNavigator *nav)
{
if (nav == nullptr) {
return;
}
connect(nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe()));
connect(nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe()));
connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe()));
connect(nav, SIGNAL(keyframe_enabled_changed(bool)), row, SLOT(SetKeyframingEnabled(bool)));
connect(nav, SIGNAL(clicked()), row, SLOT(FocusRow()));
connect(row, SIGNAL(KeyframingSetChanged(bool)), nav, SLOT(enable_keyframes(bool)));
}
void EffectUI::show_context_menu(const QPoint& pos) {
if (effect_->meta->type == EFFECT_TYPE_EFFECT) {
QMenu menu;
Clip* c = effect_->parent_clip;
int index = c->IndexOfEffect(effect_);
QAction* cut_action = menu.addAction(tr("Cu&t"));
connect(cut_action, SIGNAL(triggered(bool)), this, SIGNAL(CutRequested()));
QAction* copy_action = menu.addAction(tr("&Copy"));
connect(copy_action, SIGNAL(triggered(bool)), this, SIGNAL(CopyRequested()));
olive::MenuHelper.create_effect_paste_action(&menu);
menu.addSeparator();
if (index > 0) {
menu.addAction(tr("Move &Up"), this, SLOT(move_up()));
}
if (index < c->effects.size() - 1) {
menu.addAction(tr("Move &Down"), this, SLOT(move_down()));
}
menu.addSeparator();
menu.addAction(tr("D&elete"), this, SLOT(delete_self()));
menu.addSeparator();
menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file()));
menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file()));
menu.exec(title_bar->mapToGlobal(pos));
}
}
+199
View File
@@ -0,0 +1,199 @@
#ifndef EFFECTUI_H
#define EFFECTUI_H
#include "collapsiblewidget.h"
#include "effects/effect.h"
/**
* @brief The EffectUI class
*
* EffectUI is a complete QWidget-based representation of an Effect that can be added to any Qt layout. It overrides
* CollapsibleWidget (meaning the Effect can be collapsed to just a titlebar to save space). The titlebar is
* automatically set to the Effect's name and the contents are composed of a grid layout (QGridLayout) corresponding
* to the Effect's EffectRow and EffectField children.
*
* Many EffectUIs can be created from a single Effect, and many Effects can be attached to a single EffectUI (provided
* the Effects are all the same type). Neither gains ownership of each other and deleting an EffectUI without any other
* work is perfectly safe (deleting an Effect with an open EffectUI however, is not).
*/
class EffectUI : public CollapsibleWidget {
Q_OBJECT
public:
/**
* @brief EffectUI Constructor
*
* Creates a QWidget-based UI representation of an Effect.
*
* @param e
*
* The Effect to make a UI of. It must be a valid object.
*/
EffectUI(Effect* e);
/**
* @brief Attach additional effects to this UI
*
* Olive allows users to modify several effects (of the same type) with one UI representation. To do this, you can
* add any amount of extra Effect objects using this function and the UI will attach all of its UI functions to that
* Effect as well without creating any new QWidgets.
*
* @param e
*
* The Effect to add to this UI object.
*/
void AddAdditionalEffect(Effect* e);
/**
* @brief Get the primary Effect that this UI object was created for
*
* @return
*
* The Effect object passed to the constrcutor whe creating this EffectUI.
*/
Effect* GetEffect();
/**
* @brief Get the Y position of a given row
*
* Retrieve the on-screen Y position of the attached Effect's EffectRow at a given index. This is primarily used for
* displaying UI elements that align with the the row's on-screen widgets (e.g. keyframes in the EffectControls
* panel).
*
* The Y value provided is specifically the center point of the row's name label. It gets mapped to a provided
* QWidget object so it can be used locally by that QWidget without further modification.
*
* @param row
*
* The index of the EffectRow to retrieve the Y position of.
*
* @param mapToWidget
*
* The widget to map the Y value to.
*
* @return
*
* The row's Y position.
*/
int GetRowY(int row, QWidget *mapToWidget);
/**
* @brief Update widgets with the current Effect's values.
*
* When the Timeline playhead moves, the current values in the Effect might change if its fields are keyframed.
* In order to visually update these values on the UI, this function should be called. It will loop through all
* fields of all attached effects and update them to the value at the current Timeline playhead.
*
* Currently this function is called by update_ui() which is also responsible for updating other parts of the UI
* like the Timeline and Viewer so they all get updated together.
*/
void UpdateFromEffect();
/**
* @brief Check if a given Clip has an Effect referenced by this EffectUI
*
* Olive allows users to modify several effects (of the same type) with one UI representation. The behavior is if
* multiple clips are selected that have effects of the same type, all those Effects can be modified by the same
* EffectUI object. However this behavior is undesirable if a single Clip has more than one of the same type of Effect
* (e.g. two or more blurs). In this scenario, the user will most likely expect two separate UI objects for each of
* these effects individually, rather than consolidating them into one UI object.
*
* To address this, EffectControls will check this function to determine if this EffectUI already references
* an Effect of this type from this Clip. If it does, it's assumed a new EffectUI should be made rather than
* consolidating that Effect into the same EffectUI.
*
* @param c
*
* The Clip to determine whether an Effect of this type is already referenced by this EffectUI.
*
* @return
*
* True is an Effect from this Clip is already attached to this EffectUI.
*/
bool IsAttachedToClip(Clip* c);
signals:
/**
* @brief Cut signal
*
* Emitted when the user selects Cut from the right-click context menu.
*/
void CutRequested();
/**
* @brief Copy signal
*
* Emitted when the user selects Copy from the right-click context menu.
*/
void CopyRequested();
private:
/**
* @brief Retrieve the QWidget corresponding a specific EffectField
*
* Convenience function equivalent to widgets_.at(row).at(field).
*
* @param row
*
* EffectRow index to retrieve field QWidget from
*
* @param field
*
* EffectField index to retrieve QWidget from
*
* @return
*
* The QWidget at this row and field index.
*/
QWidget* Widget(int row, int field);
/**
* @brief Internal reference to the Effect this object was constructed around.
*/
Effect* effect_;
/**
* @brief Internal array of additional Effect objects attached to this UI.
*/
QVector<Effect*> additional_effects_;
/**
* @brief Layout for UI widgets
*/
QGridLayout* layout_;
/**
* @brief Grid array of QWidgets corresponding to the Effect's rows and fields
*/
QVector< QVector<QWidget*> > widgets_;
/**
* @brief Array of QLabel objects corresponding to each row's name().
*/
QVector<QLabel*> labels_;
/**
* @brief Array of KeyframeNavigator objects corresponding to each row.
*/
QVector<KeyframeNavigator*> keyframe_navigators_;
/**
* @brief Attach a KeyframeNavigator object to an EffectRow.
*
* Internal function for connecting a KeyframeNavigator UI object to an EffectRow.
*
* @param row
*
* The EffectRow object.
*
* @param nav
*
* The KeyframeNavigator object.
*/
void AttachKeyframeNavigationToRow(EffectRow* row, KeyframeNavigator* nav);
private slots:
/**
* @brief Slot for titlebar's right-click signal to show a context menu for extra Effect functions.
*/
void show_context_menu(const QPoint&);
};
#endif // EFFECTUI_H
+33 -38
View File
@@ -27,54 +27,49 @@
#include <QFileDialog>
EmbeddedFileChooser::EmbeddedFileChooser(QWidget* parent) : QWidget(parent) {
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setMargin(0);
file_label = new QLabel(this);
update_label();
layout->addWidget(file_label);
QPushButton* browse_button = new QPushButton("...", this);
browse_button->setFixedWidth(25);
layout->addWidget(browse_button);
connect(browse_button, SIGNAL(clicked(bool)), this, SLOT(browse()));
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setMargin(0);
file_label = new QLabel(this);
update_label();
layout->addWidget(file_label);
QPushButton* browse_button = new QPushButton("...", this);
browse_button->setFixedWidth(25);
layout->addWidget(browse_button);
connect(browse_button, SIGNAL(clicked(bool)), this, SLOT(browse()));
}
const QString &EmbeddedFileChooser::getFilename() {
return filename;
}
const QString &EmbeddedFileChooser::getPreviousValue() {
return old_filename;
return filename;
}
void EmbeddedFileChooser::setFilename(const QString &s) {
old_filename = filename;
filename = s;
update_label();
emit changed();
filename = s;
update_label();
emit changed(filename);
}
void EmbeddedFileChooser::update_label() {
QString l = "<html>" + tr("File:") + " ";
if (filename.isEmpty()) {
l += "(none)";
} else {
bool file_exists = QFileInfo::exists(filename);
if (!file_exists) l += "<font color='red'>";
QString short_fn = filename.mid(filename.lastIndexOf('/')+1);
if (short_fn.size() > 20) {
l += "..." + short_fn.right(20);
} else {
l += short_fn;
}
if (!file_exists) l += "</font>";
}
l += "</html>";
file_label->setText(l);
QString l = "<html>" + tr("File:") + " ";
if (filename.isEmpty()) {
l += "(none)";
} else {
bool file_exists = QFileInfo::exists(filename);
if (!file_exists) l += "<font color='red'>";
QString short_fn = filename.mid(filename.lastIndexOf('/')+1);
if (short_fn.size() > 20) {
l += "..." + short_fn.right(20);
} else {
l += short_fn;
}
if (!file_exists) l += "</font>";
}
l += "</html>";
file_label->setText(l);
}
void EmbeddedFileChooser::browse() {
QString fn = QFileDialog::getOpenFileName(this);
if (!fn.isEmpty()) {
setFilename(fn);
}
QString fn = QFileDialog::getOpenFileName(this);
if (!fn.isEmpty()) {
setFilename(fn);
}
}
+9 -11
View File
@@ -26,22 +26,20 @@
class QLabel;
class EmbeddedFileChooser : public QWidget {
Q_OBJECT
Q_OBJECT
public:
EmbeddedFileChooser(QWidget* parent = 0);
EmbeddedFileChooser(QWidget* parent = 0);
const QString& getFilename();
const QString& getPreviousValue();
void setFilename(const QString& s);
const QString& getFilename();
void setFilename(const QString& s);
signals:
void changed();
void changed(const QString& s);
private:
QLabel* file_label;
QString filename;
QString old_filename;
void update_label();
QLabel* file_label;
QString filename;
void update_label();
private slots:
void browse();
void browse();
};
#endif // EMBEDDEDFILECHOOSER_H
+2 -2
View File
@@ -21,7 +21,7 @@
#include "focusfilter.h"
#include "panels/panels.h"
#include "project/sequence.h"
#include "timeline/sequence.h"
#include "ui/timelineheader.h"
FocusFilter olive::FocusFilter;
@@ -197,7 +197,7 @@ void FocusFilter::delete_function() {
} else if (panel_sequence_viewer->headers->hasFocus()) {
panel_sequence_viewer->headers->delete_markers();
} else if (panel_effect_controls->is_focused()) {
panel_effect_controls->delete_effects();
panel_effect_controls->DeleteSelectedEffects();
} else if (panel_project->is_focused()) {
panel_project->delete_selected_media();
} else if (panel_effect_controls->keyframe_focus()) {
+5 -10
View File
@@ -22,19 +22,14 @@
#include <QFontDatabase>
FontCombobox::FontCombobox(QWidget* parent) : ComboBoxEx(parent) {
addItems(QFontDatabase().families());
FontCombobox::FontCombobox(QWidget* parent) : QComboBox(parent) {
addItems(QFontDatabase().families());
value = currentText();
value = currentText();
connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(updateInternals()));
}
const QString& FontCombobox::getPreviousValue() {
return previousValue;
connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(updateInternals()));
}
void FontCombobox::updateInternals() {
previousValue = value;
value = currentText();
value = currentText();
}
+6 -8
View File
@@ -21,18 +21,16 @@
#ifndef FONTCOMBOBOX_H
#define FONTCOMBOBOX_H
#include "comboboxex.h"
#include <QComboBox>
class FontCombobox : public ComboBoxEx {
Q_OBJECT
class FontCombobox : public QComboBox {
Q_OBJECT
public:
FontCombobox(QWidget* parent = 0);
const QString &getPreviousValue();
FontCombobox(QWidget* parent = nullptr);
private slots:
void updateInternals();
void updateInternals();
private:
QString previousValue;
QString value;
QString value;
};
#endif // FONTCOMBOBOX_H
+49 -50
View File
@@ -26,19 +26,18 @@
#include <QMenu>
#include <cfloat>
#include "io/config.h"
#include "global/config.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "panels/viewer.h"
#include "project/sequence.h"
#include "timeline/sequence.h"
#include "ui/keyframedrawing.h"
#include "project/undo.h"
#include "project/effect.h"
#include "project/clip.h"
#include "undo/undo.h"
#include "undo/undostack.h"
#include "effects/effect.h"
#include "timeline/clip.h"
#include "ui/rectangleselect.h"
#include "debug.h"
#include "global/debug.h"
const double kGraphZoomSpeed = 0.05;
const int kGraphSize = 100;
@@ -120,15 +119,15 @@ void GraphView::set_view_to_selection() {
double min_dbl = DBL_MAX;
double max_dbl = DBL_MIN;
for (int i=0;i<selected_keys.size();i++) {
const EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
const EffectKeyframe& key = row->Field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
min_time = qMin(key.time, min_time);
max_time = qMax(key.time, max_time);
min_dbl = qMin(key.data.toDouble(), min_dbl);
max_dbl = qMax(key.data.toDouble(), max_dbl);
}
min_time -= row->parent_effect->parent_clip->clip_in();
max_time -= row->parent_effect->parent_clip->clip_in();
min_time -= row->GetParentEffect()->parent_clip->clip_in();
max_time -= row->GetParentEffect()->parent_clip->clip_in();
set_view_to_rect(min_time, min_dbl, max_time, max_dbl);
}
@@ -142,9 +141,9 @@ void GraphView::set_view_to_all() {
long max_time = LONG_MIN;
double min_dbl = DBL_MAX;
double max_dbl = DBL_MIN;
for (int i=0;i<row->fieldCount();i++) {
for (int j=0;j<row->field(i)->keyframes.size();j++) {
const EffectKeyframe& key = row->field(i)->keyframes.at(j);
for (int i=0;i<row->FieldCount();i++) {
for (int j=0;j<row->Field(i)->keyframes.size();j++) {
const EffectKeyframe& key = row->Field(i)->keyframes.at(j);
min_time = qMin(key.time, min_time);
max_time = qMax(key.time, max_time);
min_dbl = qMin(key.data.toDouble(), min_dbl);
@@ -153,8 +152,8 @@ void GraphView::set_view_to_all() {
}
}
if (can_set) {
min_time -= row->parent_effect->parent_clip->clip_in();
max_time -= row->parent_effect->parent_clip->clip_in();
min_time -= row->GetParentEffect()->parent_clip->clip_in();
max_time -= row->GetParentEffect()->parent_clip->clip_in();
set_view_to_rect(min_time, min_dbl, max_time, max_dbl);
}
@@ -242,10 +241,10 @@ void GraphView::paintEvent(QPaintEvent *) {
QPen line_pen;
line_pen.setWidth(kBezierLineSize);
for (int i=row->fieldCount()-1;i>=0;i--) {
EffectField* field = row->field(i);
for (int i=row->FieldCount()-1;i>=0;i--) {
EffectField* field = row->Field(i);
if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
// sort keyframes by time
QVector<int> sorted_keys = sort_keys_from_field(field);
@@ -259,15 +258,15 @@ void GraphView::paintEvent(QPaintEvent *) {
int key_x = get_screen_x(key.time);
int key_y = get_screen_y(key.data.toDouble());
line_pen.setColor(get_curve_color(i, row->fieldCount()));
line_pen.setColor(get_curve_color(i, row->FieldCount()));
p.setPen(line_pen);
if (j == 0) {
p.drawLine(0, key_y, key_x, key_y);
} else {
const EffectKeyframe& last_key = field->keyframes.at(sorted_keys.at(j-1));
double pre_handle = field->get_validated_keyframe_handle(sorted_keys.at(j), false);
double last_post_handle = field->get_validated_keyframe_handle(sorted_keys.at(j-1), true);
double pre_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j), false);
double last_post_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j-1), true);
if (last_key.type == EFFECT_KEYFRAME_HOLD) {
// hold
@@ -385,9 +384,9 @@ void GraphView::mousePressEvent(QMouseEvent *event) {
update_ui(false);
click_add_proc = true;
} else {
for (int i=0;i<row->fieldCount();i++) {
EffectField* field = row->field(i);
if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
for (int i=0;i<row->FieldCount();i++) {
EffectField* field = row->Field(i);
if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
for (int j=0;j<field->keyframes.size();j++) {
const EffectKeyframe& key = field->keyframes.at(j);
int key_x = get_screen_x(key.time);
@@ -488,8 +487,8 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
selected_keys.resize(rect_select_offset);
selected_keys_fields.resize(rect_select_offset);
for (int i=0;i<row->fieldCount();i++) {
EffectField* f = row->field(i);
for (int i=0;i<row->FieldCount();i++) {
EffectField* f = row->Field(i);
for (int j=0;j<f->keyframes.size();j++) {
bool already_selected = false;
for (int k=0;k<selected_keys.size();k++) {
@@ -514,11 +513,11 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
switch (current_handle) {
case kBezierHandleNone:
for (int i=0;i<selected_keys.size();i++) {
row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].time = qRound(selected_keys_old_vals.at(i) + (double(event->pos().x() - start_x)/x_zoom));
row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].time = qRound(selected_keys_old_vals.at(i) + (double(event->pos().x() - start_x)/x_zoom));
if (event->modifiers() & Qt::ShiftModifier) {
row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = selected_keys_old_doubles.at(i);
row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = selected_keys_old_doubles.at(i);
} else {
row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = qRound(selected_keys_old_doubles.at(i) + (double(start_y - event->pos().y())/y_zoom));
row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = qRound(selected_keys_old_doubles.at(i) + (double(start_y - event->pos().y())/y_zoom));
}
}
moved_keys = true;
@@ -551,7 +550,7 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
}
}
EffectKeyframe& key = row->field(handle_field)->keyframes[handle_index];
EffectKeyframe& key = row->Field(handle_field)->keyframes[handle_index];
key.pre_handle_x = qMin(0.0, new_pre_handle_x);
key.pre_handle_y = new_pre_handle_y;
key.post_handle_x = qMax(0.0, new_post_handle_x);
@@ -569,9 +568,9 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
bool hovering_key = false;
for (int i=0;i<row->fieldCount();i++) {
for (int j=0;j<row->field(i)->keyframes.size();j++) {
const EffectKeyframe& key = row->field(i)->keyframes.at(j);
for (int i=0;i<row->FieldCount();i++) {
for (int j=0;j<row->Field(i)->keyframes.size();j++) {
const EffectKeyframe& key = row->Field(i)->keyframes.at(j);
int key_x = get_screen_x(key.time);
int key_y = get_screen_y(key.data.toDouble());
QRect test_rect(
@@ -603,8 +602,8 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
}
if (!hovering_key) {
for (int i=0;i<row->fieldCount();i++) {
EffectField* f = row->field(i);
for (int i=0;i<row->FieldCount();i++) {
EffectField* f = row->Field(i);
if (field_visibility.at(i)) {
QVector<int> sorted_keys = sort_keys_from_field(f);
@@ -702,13 +701,13 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
void GraphView::mouseReleaseEvent(QMouseEvent *) {
if (click_add_proc) {
olive::UndoStack.push(new KeyframeFieldSet(click_add_field, click_add_key));
olive::UndoStack.push(new KeyframeAdd(click_add_field, click_add_key));
} else if (moved_keys && selected_keys.size() > 0) {
ComboAction* ca = new ComboAction();
switch (current_handle) {
case kBezierHandleNone:
for (int i=0;i<selected_keys.size();i++) {
EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)];
EffectKeyframe& key = row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)];
ca->append(new SetLong(&key.time, selected_keys_old_vals.at(i), key.time));
ca->append(new SetQVariant(&key.data, selected_keys_old_doubles.at(i), key.data));
}
@@ -716,7 +715,7 @@ void GraphView::mouseReleaseEvent(QMouseEvent *) {
case kBezierHandlePre:
case kBezierHandlePost:
{
EffectKeyframe& key = row->field(handle_field)->keyframes[handle_index];
EffectKeyframe& key = row->Field(handle_field)->keyframes[handle_index];
ca->append(new SetDouble(&key.pre_handle_x, old_pre_handle_x, key.pre_handle_x));
ca->append(new SetDouble(&key.pre_handle_y, old_pre_handle_y, key.pre_handle_y));
ca->append(new SetDouble(&key.post_handle_x, old_post_handle_x, key.post_handle_x));
@@ -831,11 +830,11 @@ void GraphView::set_row(EffectRow *r) {
emit selection_changed(false, -1);
row = r;
if (row != nullptr) {
field_visibility.resize(row->fieldCount());
for (int i=0;i<row->fieldCount();i++) {
field_visibility[i] = row->field(i)->is_enabled();
field_visibility.resize(row->FieldCount());
for (int i=0;i<row->FieldCount();i++) {
field_visibility[i] = row->Field(i)->IsEnabled();
}
visible_in = row->parent_effect->parent_clip->timeline_in();
visible_in = row->GetParentEffect()->parent_clip->timeline_in();
set_view_to_all();
} else {
update();
@@ -847,7 +846,7 @@ void GraphView::set_selected_keyframe_type(int type) {
if (selected_keys.size() > 0) {
ComboAction* ca = new ComboAction();
for (int i=0;i<selected_keys.size();i++) {
EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)];
EffectKeyframe& key = row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)];
ca->append(new SetInt(&key.type, type));
}
olive::UndoStack.push(ca);
@@ -864,7 +863,7 @@ void GraphView::delete_selected_keys() {
if (row != nullptr) {
QVector<EffectField*> fields;
for (int i=0;i<selected_keys_fields.size();i++) {
fields.append(row->field(selected_keys_fields.at(i)));
fields.append(row->Field(selected_keys_fields.at(i)));
}
delete_keyframes(fields, selected_keys);
}
@@ -874,8 +873,8 @@ void GraphView::select_all() {
if (row != nullptr) {
selected_keys.clear();
selected_keys_fields.clear();
for (int i=0;i<row->fieldCount();i++) {
EffectField* field = row->field(i);
for (int i=0;i<row->FieldCount();i++) {
EffectField* field = row->Field(i);
for (int j=0;j<field->keyframes.size();j++) {
selected_keys.append(j);
selected_keys_fields.append(i);
@@ -903,7 +902,7 @@ void GraphView::set_zoom(double xz, double yz) {
int GraphView::get_screen_x(double d) {
if (row != nullptr) {
d -= row->parent_effect->parent_clip->clip_in();
d -= row->GetParentEffect()->parent_clip->clip_in();
}
return qRound((d*x_zoom) - x_scroll);
}
@@ -915,7 +914,7 @@ int GraphView::get_screen_y(double d) {
long GraphView::get_value_x(int i) {
long frame = qRound((i + x_scroll)/x_zoom);
if (row != nullptr) {
frame += row->parent_effect->parent_clip->clip_in();
frame += row->GetParentEffect()->parent_clip->clip_in();
}
return frame;
}
@@ -931,7 +930,7 @@ void GraphView::selection_update() {
int selected_key_type = -1;
for (int i=0;i<selected_keys.size();i++) {
const EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
const EffectKeyframe& key = row->Field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
selected_keys_old_vals.append(key.time);
selected_keys_old_doubles.append(key.data.toDouble());
+2 -2
View File
@@ -24,8 +24,8 @@
#include <QWidget>
#include <QVector>
#include "project/effectrow.h"
#include "project/effectfield.h"
#include "effects/effectrow.h"
#include "effects/effectfields.h"
QColor get_curve_color(int index, int length);
+18 -2
View File
@@ -1,6 +1,9 @@
#include "icons.h"
#include "oliveglobal.h"
#include <QDebug>
#include "global/global.h"
#include "global/config.h"
QIcon olive::icon::LeftArrow;
QIcon olive::icon::RightArrow;
@@ -27,14 +30,27 @@ QIcon olive::icon::CreateIconFromSVG(const QString &path)
{
QIcon icon;
QPainter p;
// Draw the icon as a solid color
QPixmap normal(path);
if (olive::styling::UseDarkIcons()) {
p.begin(&normal);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(normal.rect(), QColor(32, 32, 32));
p.end();
}
icon.addPixmap(normal, QIcon::Normal, QIcon::On);
// Create semi-transparent disabled icon
QPixmap disabled(normal.size());
disabled.fill(Qt::transparent);
// draw semi-transparent version of icon for the disabled variant
QPainter p(&disabled);
p.begin(&disabled);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.setOpacity(0.5);
p.drawPixmap(0, 0, normal);
p.end();
+26 -26
View File
@@ -20,42 +20,42 @@
#include "keyframedrawing.h"
#include "project/effect.h"
#include "project/clip.h"
#include "effects/effect.h"
#include "timeline/clip.h"
#define KEYFRAME_POINT_COUNT 4
// routine for drawing a keyframe onscreen
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r, int g, int b) {
if (darker) {
r *= 0.625;
g *= 0.625;
b *= 0.625;
}
p.setPen(QColor(0, 0, 0));
p.setBrush(QColor(r, g, b));
if (darker) {
r *= 0.625;
g *= 0.625;
b *= 0.625;
}
p.setPen(QColor(0, 0, 0));
p.setBrush(QColor(r, g, b));
switch (type) {
case EFFECT_KEYFRAME_LINEAR:
{
QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)};
p.drawPolygon(points, KEYFRAME_POINT_COUNT);
}
break;
case EFFECT_KEYFRAME_BEZIER:
p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE);
break;
case EFFECT_KEYFRAME_HOLD:
p.drawRect(QRect(x - KEYFRAME_SIZE, y - KEYFRAME_SIZE, KEYFRAME_SIZE*2, KEYFRAME_SIZE*2));
break;
}
switch (type) {
case EFFECT_KEYFRAME_LINEAR:
{
QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)};
p.drawPolygon(points, KEYFRAME_POINT_COUNT);
}
break;
case EFFECT_KEYFRAME_BEZIER:
p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE);
break;
case EFFECT_KEYFRAME_HOLD:
p.drawRect(QRect(x - KEYFRAME_SIZE, y - KEYFRAME_SIZE, KEYFRAME_SIZE*2, KEYFRAME_SIZE*2));
break;
}
p.setBrush(Qt::NoBrush);
p.setBrush(Qt::NoBrush);
}
// adjusts keyframe's internal time (in clip time) to timeline time
long adjust_row_keyframe(EffectRow* row, long time, long visible_in) {
return time
- row->parent_effect->parent_clip->clip_in()
+ (row->parent_effect->parent_clip->timeline_in() - visible_in);
- row->GetParentEffect()->parent_clip->clip_in()
+ (row->GetParentEffect()->parent_clip->timeline_in() - visible_in);
}
+5 -1
View File
@@ -24,10 +24,13 @@
#include <QPushButton>
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>
#include "ui/icons.h"
KeyframeNavigator::KeyframeNavigator(QWidget *parent, bool addLeftPad) : QWidget(parent) {
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
key_controls = new QHBoxLayout(this);
key_controls->setSpacing(0);
key_controls->setMargin(0);
@@ -60,7 +63,8 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent, bool addLeftPad) : QWidget
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_next_key()));
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked()));
keyframe_enable = new QPushButton(olive::icon::Clock, "", this);
keyframe_enable = new QPushButton(this);
keyframe_enable->setIcon(olive::icon::Clock);
keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
keyframe_enable->setIconSize(keyframe_enable->iconSize()*0.75);
keyframe_enable->setCheckable(true);
+18 -16
View File
@@ -28,26 +28,28 @@ class QPushButton;
class KeyframeNavigator : public QWidget
{
Q_OBJECT
Q_OBJECT
public:
KeyframeNavigator(QWidget* parent = 0, bool addLeftPad = true);
~KeyframeNavigator();
void enable_keyframes(bool);
void enable_keyframe_toggle(bool);
KeyframeNavigator(QWidget* parent = nullptr, bool addLeftPad = true);
~KeyframeNavigator();
void enable_keyframe_toggle(bool);
public slots:
void enable_keyframes(bool);
signals:
void goto_previous_key();
void toggle_key();
void goto_next_key();
void keyframe_enabled_changed(bool);
void clicked();
void goto_previous_key();
void toggle_key();
void goto_next_key();
void keyframe_enabled_changed(bool);
void clicked();
private slots:
void keyframe_ui_enabled(bool);
void keyframe_ui_enabled(bool);
private:
QHBoxLayout* key_controls;
QPushButton* left_key_nav;
QPushButton* key_addremove;
QPushButton* right_key_nav;
QPushButton* keyframe_enable;
QHBoxLayout* key_controls;
QPushButton* left_key_nav;
QPushButton* key_addremove;
QPushButton* right_key_nav;
QPushButton* keyframe_enable;
};
#endif // KEYFRAMENAVIGATOR_H
+66 -62
View File
@@ -20,29 +20,29 @@
#include "keyframeview.h"
#include "project/effect.h"
#include <QMouseEvent>
#include <QtMath>
#include <QMenu>
#include "effects/effect.h"
#include "ui/collapsiblewidget.h"
#include "panels/panels.h"
#include "panels/effectcontrols.h"
#include "project/clip.h"
#include "timeline/clip.h"
#include "panels/timeline.h"
#include "ui/timelineheader.h"
#include "project/undo.h"
#include "undo/undo.h"
#include "undo/undostack.h"
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
#include "project/sequence.h"
#include "timeline/sequence.h"
#include "panels/grapheditor.h"
#include "ui/keyframedrawing.h"
#include "ui/clickablelabel.h"
#include "ui/resizablescrollbar.h"
#include "ui/rectangleselect.h"
#include "project/keyframe.h"
#include "effects/keyframe.h"
#include "ui/graphview.h"
#include <QMouseEvent>
#include <QtMath>
#include <QMenu>
KeyframeView::KeyframeView(QWidget *parent) :
QWidget(parent),
visible_in(0),
@@ -62,6 +62,11 @@ KeyframeView::KeyframeView(QWidget *parent) :
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
}
void KeyframeView::SetEffects(const QVector<EffectUI *> &open_effects)
{
open_effects_ = open_effects;
}
void KeyframeView::show_context_menu(const QPoint& pos) {
if (selected_fields.size() > 0) {
QMenu menu(this);
@@ -101,62 +106,61 @@ void KeyframeView::paintEvent(QPaintEvent*) {
rowY.clear();
rows.clear();
if (panel_effect_controls->selected_clips.size() > 0) {
if (!open_effects_.isEmpty()) {
visible_in = LONG_MAX;
visible_out = 0;
for (int j=0;j<panel_effect_controls->selected_clips.size();j++) {
ClipPtr c = olive::ActiveSequence->clips.at(panel_effect_controls->selected_clips.at(j));
for (int i=0;i<open_effects_.size();i++) {
Clip* c = open_effects_.at(i)->GetEffect()->parent_clip;
visible_in = qMin(visible_in, c->timeline_in());
visible_out = qMax(visible_out, c->timeline_out());
}
for (int j=0;j<panel_effect_controls->selected_clips.size();j++) {
ClipPtr c = olive::ActiveSequence->clips.at(panel_effect_controls->selected_clips.at(j));
for (int i=0;i<c->effects.size();i++) {
EffectPtr e = c->effects.at(i);
if (e->container->is_expanded()) {
for (int j=0;j<e->row_count();j++) {
EffectRow* row = e->row(j);
for (int j=0;j<open_effects_.size();j++) {
ClickableLabel* label = row->label;
QWidget* contents = e->container->contents;
EffectUI* container = open_effects_.at(j);
Effect* e = container->GetEffect();
QVector<long> key_times;
int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height()/* - y_scroll*/;
for (int l=0;l<row->fieldCount();l++) {
EffectField* f = row->field(l);
for (int k=0;k<f->keyframes.size();k++) {
if (!key_times.contains(f->keyframes.at(k).time)) {
bool keyframe_selected = keyframeIsSelected(f, k);
long keyframe_frame = adjust_row_keyframe(row, f->keyframes.at(k).time, visible_in);
if (container->IsExpanded()) {
for (int j=0;j<e->row_count();j++) {
EffectRow* row = e->row(j);
// see if any other keyframes have this time
int appearances = 0;
for (int m=0;m<row->fieldCount();m++) {
EffectField* compf = row->field(m);
for (int n=0;n<compf->keyframes.size();n++) {
if (f->keyframes.at(k).time == compf->keyframes.at(n).time) {
appearances++;
}
int keyframe_y = container->GetRowY(j, this);
QVector<long> key_times;
for (int l=0;l<row->FieldCount();l++) {
EffectField* f = row->Field(l);
for (int k=0;k<f->keyframes.size();k++) {
if (!key_times.contains(f->keyframes.at(k).time)) {
bool keyframe_selected = keyframeIsSelected(f, k);
long keyframe_frame = adjust_row_keyframe(row, f->keyframes.at(k).time, visible_in);
// see if any other keyframes have this time
int appearances = 0;
for (int m=0;m<row->FieldCount();m++) {
EffectField* compf = row->Field(m);
for (int n=0;n<compf->keyframes.size();n++) {
if (f->keyframes.at(k).time == compf->keyframes.at(n).time) {
appearances++;
}
}
if (appearances != row->fieldCount()) {
QColor cc = get_curve_color(l, row->fieldCount());
draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected, cc.red(), cc.green(), cc.blue());
} else {
draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected);
}
key_times.append(f->keyframes.at(k).time);
}
if (appearances != row->FieldCount()) {
QColor cc = get_curve_color(l, row->FieldCount());
draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected, cc.red(), cc.green(), cc.blue());
} else {
draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected);
}
key_times.append(f->keyframes.at(k).time);
}
}
rows.append(row);
rowY.append(keyframe_y);
}
rows.append(row);
rowY.append(keyframe_y);
}
}
}
@@ -250,12 +254,12 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
if (mouse_y > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) {
EffectRow* row = rows.at(i);
row->focus_row();
row->FocusRow();
for (int k=0;k<row->fieldCount();k++) {
EffectField* f = row->field(k);
for (int k=0;k<row->FieldCount();k++) {
EffectField* f = row->Field(k);
for (int j=0;j<f->keyframes.size();j++) {
long eval_keyframe_time = f->keyframes.at(j).time-row->parent_effect->parent_clip->clip_in()+(row->parent_effect->parent_clip->timeline_in()-visible_in);
long eval_keyframe_time = f->keyframes.at(j).time-row->GetParentEffect()->parent_clip->clip_in()+(row->GetParentEffect()->parent_clip->timeline_in()-visible_in);
if (eval_keyframe_time >= frame_min && eval_keyframe_time <= frame_max) {
long eval_frame_diff = qAbs(eval_keyframe_time - drag_frame_start);
if (keyframe_index == -1 || eval_frame_diff < frame_diff) {
@@ -273,7 +277,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
bool already_selected = false;
keys_selected = false;
if (keyframe_index > -1) {
already_selected = keyframeIsSelected(rows.at(row_index)->field(field_index), keyframe_index);
already_selected = keyframeIsSelected(rows.at(row_index)->Field(field_index), keyframe_index);
} else {
select_rect = true;
}
@@ -283,14 +287,14 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
selected_keyframes.clear();
}
if (keyframe_index > -1) {
selected_fields.append(rows.at(row_index)->field(field_index));
selected_fields.append(rows.at(row_index)->Field(field_index));
selected_keyframes.append(keyframe_index);
// find other field with keyframes at the same time
long comp_time = rows.at(row_index)->field(field_index)->keyframes.at(keyframe_index).time;
for (int i=0;i<rows.at(row_index)->fieldCount();i++) {
long comp_time = rows.at(row_index)->Field(field_index)->keyframes.at(keyframe_index).time;
for (int i=0;i<rows.at(row_index)->FieldCount();i++) {
if (i != field_index) {
EffectField* f = rows.at(row_index)->field(i);
EffectField* f = rows.at(row_index)->Field(i);
for (int j=0;j<f->keyframes.size();j++) {
if (f->keyframes.at(j).time == comp_time) {
selected_fields.append(f);
@@ -353,8 +357,8 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
for (int i=0;i<rowY.size();i++) {
if (rowY.at(i) >= min_row && rowY.at(i) <= max_row) {
EffectRow* row = rows.at(i);
for (int k=0;k<row->fieldCount();k++) {
EffectField* field = row->field(k);
for (int k=0;k<row->FieldCount();k++) {
EffectField* field = row->Field(k);
for (int j=0;j<field->keyframes.size();j++) {
long keyframe_frame = adjust_row_keyframe(row, field->keyframes.at(j).time, visible_in);
if (!keyframeIsSelected(field, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) {
@@ -376,7 +380,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
if (panel_timeline->snapping) {
for (int i=0;i<selected_keyframes.size();i++) {
EffectField* field = selected_fields.at(i);
Clip* c = field->parent_row->parent_effect->parent_clip;
Clip* c = field->GetParentRow()->GetParentEffect()->parent_clip;
long key_time = old_key_vals.at(i) + frame_diff - c->clip_in() + c->timeline_in();
long key_eval = key_time;
if (panel_timeline->snap_to_point(olive::ActiveSequence->playhead, &key_eval)) {
+44 -38
View File
@@ -24,6 +24,8 @@
#include <QWidget>
#include <QPainter>
#include "ui/effectui.h"
class Clip;
class Effect;
class EffectRow;
@@ -31,56 +33,60 @@ class EffectField;
class TimelineHeader;
class KeyframeView : public QWidget {
Q_OBJECT
Q_OBJECT
public:
KeyframeView(QWidget* parent = 0);
KeyframeView(QWidget* parent = nullptr);
void delete_selected_keyframes();
void SetEffects(const QVector<EffectUI*>& open_effects);
TimelineHeader* header;
void delete_selected_keyframes();
long visible_in;
long visible_out;
TimelineHeader* header;
long visible_in;
long visible_out;
signals:
void wheel_event_signal(QWheelEvent*);
void wheel_event_signal(QWheelEvent*);
public slots:
void set_x_scroll(int);
void set_y_scroll(int);
void resize_move(double d);
void set_x_scroll(int);
void set_y_scroll(int);
void resize_move(double d);
private:
QVector<EffectField*> selected_fields;
QVector<int> selected_keyframes;
QVector<int> rowY;
QVector<EffectRow*> rows;
QVector<long> old_key_vals;
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
void wheelEvent(QWheelEvent* e);
bool mousedown;
bool dragging;
bool keys_selected;
bool select_rect;
bool scroll_drag;
QVector<EffectUI*> open_effects_;
bool keyframeIsSelected(EffectField *field, int keyframe);
QVector<EffectField*> selected_fields;
QVector<int> selected_keyframes;
QVector<int> rowY;
QVector<EffectRow*> rows;
QVector<long> old_key_vals;
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
void wheelEvent(QWheelEvent* e);
bool mousedown;
bool dragging;
bool keys_selected;
bool select_rect;
bool scroll_drag;
long drag_frame_start;
long last_frame_diff;
int rect_select_x;
int rect_select_y;
int rect_select_w;
int rect_select_h;
int rect_select_offset;
bool keyframeIsSelected(EffectField *field, int keyframe);
int x_scroll;
int y_scroll;
long drag_frame_start;
long last_frame_diff;
int rect_select_x;
int rect_select_y;
int rect_select_w;
int rect_select_h;
int rect_select_offset;
void update_keys();
int x_scroll;
int y_scroll;
void update_keys();
private slots:
void show_context_menu(const QPoint& pos);
void menu_set_key_type(QAction*);
void show_context_menu(const QPoint& pos);
void menu_set_key_type(QAction*);
};
#endif // KEYFRAMEVIEW_H
+67 -70
View File
@@ -20,11 +20,12 @@
#include "labelslider.h"
#include "project/undo.h"
#include "undo/undo.h"
#include "panels/viewer.h"
#include "io/config.h"
#include "io/math.h"
#include "debug.h"
#include "global/config.h"
#include "global/math.h"
#include "global/debug.h"
#include "ui/styling.h"
#include <QMouseEvent>
#include <QInputDialog>
@@ -40,28 +41,33 @@ LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) {
drag_proc = false;
min_enabled = false;
max_enabled = false;
set_color();
set_default_cursor();
SetColor();
SetDefaultCursor();
internal_value = -1;
set = false;
display_type = LABELSLIDER_NORMAL;
display_type = Normal;
set_default_value(0);
SetDefault(0);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&)));
}
void LabelSlider::set_frame_rate(double d) {
void LabelSlider::SetFrameRate(double d) {
frame_rate = d;
}
void LabelSlider::set_display_type(int type) {
display_type = type;
setText(valueToString());
void LabelSlider::SetDecimalPlaces(int places)
{
decimal_places = places;
}
void LabelSlider::set_value(double v, bool userSet) {
void LabelSlider::SetDisplayType(const DisplayType& type) {
display_type = type;
setText(ValueToString());
}
void LabelSlider::SetValue(double v) {
set = true;
if (!qFuzzyCompare(v, internal_value)) {
if (min_enabled && v < min_value) {
@@ -72,30 +78,25 @@ void LabelSlider::set_value(double v, bool userSet) {
internal_value = v;
}
setText(valueToString());
if (userSet) emit valueChanged();
setText(ValueToString());
}
}
bool LabelSlider::is_set() {
return set;
}
bool LabelSlider::is_dragging() {
bool LabelSlider::IsDragging() {
return drag_proc;
}
QString LabelSlider::valueToString() {
QString LabelSlider::ValueToString() {
double v = internal_value;
if (qIsNaN(v)) {
return "---";
} else {
switch (display_type) {
case LABELSLIDER_FRAMENUMBER:
case FrameNumber:
return frame_to_timecode(long(v), olive::CurrentConfig.timecode_view, frame_rate);
case LABELSLIDER_PERCENT:
case Percent:
return QString::number((v*100), 'f', decimal_places).append("%");
case LABELSLIDER_DECIBEL:
case Decibel:
{
QString db_str;
@@ -112,21 +113,20 @@ QString LabelSlider::valueToString() {
return db_str;
}
default:
return QString::number(v, 'f', decimal_places);
}
return QString::number(v, 'f', decimal_places);
}
}
double LabelSlider::getPreviousValue() {
return previous_value;
}
void LabelSlider::set_previous_value() {
previous_value = internal_value;
}
void LabelSlider::set_color(QString c) {
if (c.isEmpty()) c = "#ffc000";
void LabelSlider::SetColor(QString c) {
if (c.isEmpty()) {
if (olive::styling::UseDarkIcons()) {
c = "#0080ff";
} else {
c = "#ffc000";
}
}
setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}");
}
@@ -134,20 +134,20 @@ double LabelSlider::value() {
return internal_value;
}
void LabelSlider::set_default_value(double v) {
void LabelSlider::SetDefault(double v) {
default_value = v;
if (!set) {
set_value(v, false);
SetValue(v);
set = false;
}
}
void LabelSlider::set_minimum_value(double v) {
void LabelSlider::SetMinimum(double v) {
min_value = v;
min_enabled = true;
}
void LabelSlider::set_maximum_value(double v) {
void LabelSlider::SetMaximum(double v) {
max_value = v;
max_enabled = true;
}
@@ -163,7 +163,7 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) {
if (ev->modifiers() & Qt::AltModifier) {
// reset to default
reset_to_default_value();
ResetToDefault();
} else {
@@ -171,7 +171,7 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) {
if (qIsNaN(internal_value)) internal_value = 0;
// hide the cursor and store information about it for dragging
set_active_cursor();
SetActiveCursor();
drag_start = true;
drag_start_x = cursor().pos().x();
@@ -203,7 +203,7 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
// ctrl + drag drags in smaller increments
if (event->modifiers() & Qt::ControlModifier) diff *= 0.01;
if (display_type == LABELSLIDER_PERCENT) {
if (display_type == Percent) {
// we'll also need to drag in smaller increments for a percent value
diff *= 0.01;
@@ -212,7 +212,7 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
// determine what the new value will be
double new_value;
if (display_type == LABELSLIDER_DECIBEL) {
if (display_type == Decibel) {
// we move in terms of dB for decibel display
new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff);
@@ -224,7 +224,8 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
}
// set internal value
set_value(new_value, true);
SetValue(new_value);
emit valueChanged(internal_value);
// keep the cursor in the same location while dragging
cursor().setPos(drag_start_x, drag_start_y);
@@ -235,7 +236,7 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
if (drag_start) {
// unhide cursor
set_default_cursor();
SetDefaultCursor();
drag_start = false;
@@ -244,55 +245,51 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
drag_proc = false;
previous_value = drag_start_value;
emit valueChanged();
emit valueChanged(internal_value);
} else {
prompt_for_value();
ShowDialog();
}
}
}
void LabelSlider::set_default_cursor() {
void LabelSlider::SetDefaultCursor() {
setCursor(Qt::SizeHorCursor);
}
void LabelSlider::set_active_cursor() {
void LabelSlider::SetActiveCursor() {
setCursor(Qt::BlankCursor);
}
void LabelSlider::show_context_menu(const QPoint &pos)
void LabelSlider::ShowContextMenu(const QPoint &pos)
{
QMenu menu(this);
menu.addAction(tr("&Edit"), this, SLOT(prompt_for_value()));
menu.addAction(tr("&Edit"), this, SLOT(ShowDialog()));
menu.addSeparator();
menu.addAction(tr("&Reset to Default"), this, SLOT(reset_to_default_value()));
menu.addAction(tr("&Reset to Default"), this, SLOT(ResetToDefault()));
menu.exec(mapToGlobal(pos));
}
void LabelSlider::reset_to_default_value()
void LabelSlider::ResetToDefault()
{
// if the value is not already default, and there is a default to set
if (!qFuzzyCompare(internal_value, default_value)
&& !qIsNaN(default_value)) {
// cache current value
set_previous_value();
// set back to default
set_value(default_value, true);
SetValue(default_value);
emit valueChanged(internal_value);
}
}
void LabelSlider::prompt_for_value()
void LabelSlider::ShowDialog()
{
// if the user didn't actually drag, and just clicked in one place,
// we instead present a dialog prompt for the user to enter a
@@ -300,7 +297,7 @@ void LabelSlider::prompt_for_value()
double d = internal_value;
if (display_type == LABELSLIDER_FRAMENUMBER) {
if (display_type == FrameNumber) {
// ask the user to enter a timecode
QString s = QInputDialog::getText(
@@ -308,7 +305,7 @@ void LabelSlider::prompt_for_value()
tr("Set Value"),
tr("New value:"),
QLineEdit::Normal,
valueToString()
ValueToString()
);
if (s.isEmpty()) return;
@@ -322,9 +319,9 @@ void LabelSlider::prompt_for_value()
// value to show
double shown_value = internal_value;
if (display_type == LABELSLIDER_PERCENT) {
if (display_type == Percent) {
shown_value *= 100;
} else if (display_type == LABELSLIDER_DECIBEL) {
} else if (display_type == Decibel) {
shown_value = amplitude_to_db(shown_value);
}
@@ -333,7 +330,7 @@ void LabelSlider::prompt_for_value()
if (min_enabled) {
// if this field has a minimum value set, use it
shown_minimum_value = min_value;
} else if (display_type == LABELSLIDER_DECIBEL) {
} else if (display_type == Decibel) {
// minimum decibel amount is -96db
shown_minimum_value = -96;
} else {
@@ -355,16 +352,16 @@ void LabelSlider::prompt_for_value()
if (!ok) return;
// convert shown value back to internal value
if (display_type == LABELSLIDER_PERCENT) {
if (display_type == Percent) {
d *= 0.01;
} else if (display_type == LABELSLIDER_DECIBEL) {
} else if (display_type == Decibel) {
d = db_to_amplitude(d);
}
}
// if the value actually changed, trigger a change event
if (!qFuzzyCompare(d, internal_value)) {
set_previous_value();
set_value(d, true);
SetValue(d);
emit valueChanged(internal_value);
}
}
+131 -160
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -24,13 +24,6 @@
#include <QLabel>
#include <QUndoCommand>
enum LabelSliderDisplayType {
LABELSLIDER_NORMAL,
LABELSLIDER_FRAMENUMBER,
LABELSLIDER_PERCENT,
LABELSLIDER_DECIBEL
};
/**
* @brief The LabelSlider class
*
@@ -44,154 +37,132 @@ public:
LabelSlider(QWidget* parent = nullptr);
/**
* @brief Set the display frame rate
*
* If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the
* timecode will be in.
*
* @param d
*/
void set_frame_rate(double d);
* @brief Set the value
* @param v
*
* Value to set to.
*
* @param userSet
*
* **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The
* only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and
* **FALSE** will not.
*/
void SetValue(double v);
/**
* @brief Sets the way to display the value
*
* * `LABELSLIDER_NORMAL` - Shows the value as a normal number
* * `LABELSLIDER_FRAMENUMBER` - Shows the number as a timecode according to `config.timecode_view`. By default,
* will render hh:mm:ss:ff
* * `LABELSLIDER_PERCENT` - Shows the number as a percentage. 1.0 becomes "100%", 0.5 becomes 50%, etc.
* * `LABELSLIDER_DECIBLE` - Shows the number as a decibel. 1.0 becomes "0 dB", 2.0 becames roughly "6 dB", 0.5
* becomes roughly "-6 dB", etc.
*
* @param type
*
* The display type to set to. Should be a member of `enum LabelSliderDisplayType`.
*/
void set_display_type(int type);
* @brief Set the default value
*
* If a default value is set, alt+clicking the LabelSlider will return to the default value.
*
* @param v
*
* Value to set as default
*/
void SetDefault(double v);
/**
* @brief Set the value
* @param v
*
* Value to set to.
*
* @param userSet
*
* **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The
* only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and
* **FALSE** will not.
*/
void set_value(double v, bool userSet);
/**
* @brief Set the default value
*
* If a default value is set, alt+clicking the LabelSlider will return to the default value.
*
* @param v
*
* Value to set as default
*/
void set_default_value(double v);
/**
* @brief Set the minimum value
*
* If a minimum value is set, the value will never go below it. If the user manually sets a value lower than
* the minimum, it will automatically snap to the minimum.
*
* @param v
*
* Value to set as minimum
*/
void set_minimum_value(double v);
/**
* @brief Set the maximum value
*
* If a maximum value is set, the value will never go above it. If the user manually sets a value higher than
* the maximum, it will automatically snap to the maximum.
*
* @param v
*
* Value to set as maximum
*/
void set_maximum_value(double v);
/**
* @brief Returns the internal value as a double
* @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will
* return as 400%, and a timecode will return as a frame number.
*/
* @brief Returns the internal value as a double
* @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will
* return as 400%, and a timecode will return as a frame number.
*/
double value();
/**
* @brief Returns whether a value has been set or not
*
* If a value has been entered by any means (i.e. if set_value() was called), this will be **TRUE**. If set_value()
* has not been called and is_set() is **FALSE**, calling set_default_value() will automatically set the value
* to the default value WITHOUT changing the is_set() state (i.e. it will still be **FALSE** and calling
* set_default_value() again will change the current value again unless it's been changed through some other means
* in that time).
*
* @return **TRUE** if a value has been set, **FALSE** if not.
*/
bool is_set();
enum DisplayType {
Normal,
FrameNumber,
Percent,
Decibel
};
/**
* @brief Returns whether the user is currently dragging
* @return **TRUE** if the user is dragging, **FALSE** if not.
*/
bool is_dragging();
* @brief Sets the way to display the value
*
* * `LABELSLIDER_NORMAL` - Shows the value as a normal number
* * `LABELSLIDER_FRAMENUMBER` - Shows the number as a timecode according to `config.timecode_view`. By default,
* will render hh:mm:ss:ff
* * `LABELSLIDER_PERCENT` - Shows the number as a percentage. 1.0 becomes "100%", 0.5 becomes 50%, etc.
* * `LABELSLIDER_DECIBLE` - Shows the number as a decibel. 1.0 becomes "0 dB", 2.0 becames roughly "6 dB", 0.5
* becomes roughly "-6 dB", etc.
*
* @param type
*
* The display type to set to.
*/
void SetDisplayType(const DisplayType& type);
/**
* @brief Convert the internal value to a displayed string according to `display_type`
* @return The internal value as a string
*/
QString valueToString();
* @brief Returns whether the user is currently dragging
* @return **TRUE** if the user is dragging, **FALSE** if not.
*/
bool IsDragging();
/**
* @brief Returns whatever value was set before the last set_value()
*
* For various reasons (largely undo capabilities) it is helpful to retrieve whatever the value was before the
* current one. If the user dragged the current value, this will return the value just before the user started
* dragging.
*
* @return The previous value
*/
double getPreviousValue();
* @brief Set the display color
* @param c
*
* Color to set to
*/
void SetColor(QString c = nullptr);
/**
* @brief Updates previous value
*
* Called internally to store the current value as the previous value in anticipation of an upcoming value change.
* Can also be called externally (mainly for dragged EffectGizmos) in anticipation of an external change.
*/
void set_previous_value();
* @brief Set the display frame rate
*
* If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the
* timecode will be in.
*
* @param d
*/
void SetFrameRate(double d);
/**
* @brief Set the display color
* @param c
*
* Color to set to
*/
void set_color(QString c = nullptr);
* @brief Set how many decimal places to show for a floating-point number
*
* Defaults to 1
*/
void SetDecimalPlaces(int places);
public slots:
/**
* @brief Set the minimum value
*
* If a minimum value is set, the value will never go below it. If the user manually sets a value lower than
* the minimum, it will automatically snap to the minimum.
*
* @param v
*
* Value to set as minimum
*/
void SetMinimum(double v);
/**
* @brief Set how many decimal places to show for a floating-point number
*
* Defaults to 1
*/
int decimal_places;
* @brief Set the maximum value
*
* If a maximum value is set, the value will never go above it. If the user manually sets a value higher than
* the maximum, it will automatically snap to the maximum.
*
* @param v
*
* Value to set as maximum
*/
void SetMaximum(double v);
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
private:
/**
* @brief Convert the internal value to a displayed string according to `display_type`
* @return The internal value as a string
*/
QString ValueToString();
double default_value;
double internal_value;
double drag_start_value;
double previous_value;
int decimal_places;
bool min_enabled;
double min_value;
@@ -205,19 +176,19 @@ private:
bool set;
int display_type;
DisplayType display_type;
double frame_rate;
/**
* @brief Internal function to set the standard cursor (usually SizeHorCursor)
*/
void set_default_cursor();
* @brief Internal function to set the standard cursor (usually SizeHorCursor)
*/
void SetDefaultCursor();
/**
* @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible)
*/
void set_active_cursor();
* @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible)
*/
void SetActiveCursor();
private slots:
/**
* @brief Context menu slot to be connected to QWidget::customContextMenuRequested(const QPoint&)
@@ -226,12 +197,12 @@ private slots:
*
* Current cursor position
*/
void show_context_menu(const QPoint& pos);
void ShowContextMenu(const QPoint& pos);
/**
* @brief Slot to reset current value to the default value
*/
void reset_to_default_value();
void ResetToDefault();
/**
* @brief Show prompt asking for value
@@ -240,20 +211,20 @@ private slots:
* Will show an input dialog asking for a new value to be entered manually. Asks for units in the selected
* display type and converts them back to the internal value type.
*/
void prompt_for_value();
void ShowDialog();
signals:
/**
* @brief valueChanged signal
*
* Emitted if the value changed at it was instigated by the user.
*/
void valueChanged();
* @brief valueChanged signal
*
* Emitted if the value changed at it was instigated by the user.
*/
void valueChanged(double d);
/**
* @brief clicked signal
*
* Emitted if the user clicks on the LabelSlider in any way
*/
* @brief clicked signal
*
* Emitted if the user clicks on the LabelSlider in any way
*/
void clicked();
};
+1255
View File
File diff suppressed because it is too large Load Diff
+366
View File
@@ -0,0 +1,366 @@
/***
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 MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class Project;
class EffectControls;
class Viewer;
class Timeline;
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent);
virtual ~MainWindow() override;
/**
* @brief Update window title
*
* Updates the window title to reflect the current project filename. Call if the project filename changes.
*
* NOTE: It's recommended to use update_project_filename() from Olive::Global to update the filename completely
* instead of calling this function directly (update_project_filename() calls this function in the process).
*/
void updateTitle();
/**
* @brief Load shortcut file.
*
* Loads a shortcut configuration from file and sets Olive to use them.
*
* @param fn
*
* URL of the shortcut file to be loaded
*
*/
void load_shortcuts(const QString &fn);
/**
* @brief Save shortcut file.
*
* Saves the current shortcut configuration to file. Only saves shortcuts that have been changed from default.
*
* @param fn
*
* URL to save the shortcut file to.
*/
void save_shortcuts(const QString &fn);
/**
* @brief Load a CSS/QSS style from file to customize Olive's interface.
*
* @param fn
*
* URL to load the CSS file from.
*
* @return
*
* **TRUE** if CSS was successfully loaded.
*/
bool load_css_from_file(const QString& fn);
/**
* @brief Set application's QStyle based on values from Config
*/
void Restyle();
public slots:
/**
* @brief Toggles full screen mode.
*
* Toggles the main window between full screen and windowed modes.
*/
void toggle_full_screen();
signals:
/**
* @brief Signal emitted once when the main window has finished initializing
*
* Emitted the first time paintEvent runs. Connect this to functions that must be completed post-initialization.
*/
void finished_first_paint();
protected:
/**
* @brief Close event
*
* Confirms whether the project can be closed, and if so performs various clean-up functions before the application
* exits. It's preferable to call clean-up functions here rather than in the destructor because this will get called
* first.
*/
virtual void closeEvent(QCloseEvent *) override;
/**
* @brief Paint event
*
* Overridden to provide the finished_first_paint() signal.
*/
virtual void paintEvent(QPaintEvent *) override;
/**
* @brief Change event
*
* Overridden to handle language changes (e->type() == QEvent::LanguageChange) by calling Retranslate().
*
* See documentation for QWidget::changeEvent() for more information.
*
* @param e
* @return
*/
virtual void changeEvent(QEvent* e) override;
private slots:
/**
* @brief Maximizes the currently hovered panel.
*
* Saves the current state of the panels/dock widgets and removes all except the currently hovered panel,
* effectively maximizing the panel to the entire window.
*/
void maximize_panel();
/**
* @brief Reset panel layout to default.
*
* Resets the current panel layout to default. Doesn't save the current layout.
*/
void reset_layout();
/**
* @brief Function to prepare File menu.
*
* Primarily used to populate the Open Recent Projects menu.
*/
void fileMenu_About_To_Be_Shown();
/**
* @brief Function to prepare Edit menu.
*
* Primarily used to set the enabled state on Undo and Redo depending if there are undos/redos available.
*/
void editMenu_About_To_Be_Shown();
/**
* @brief Function to prepare Window menu.
*
* Primarily used to set the checked state of menu items corresponding to the panels that are currently visible.
*/
void windowMenu_About_To_Be_Shown();
/**
* @brief Function to prepare Playback menu.
*
* Primarily used to set the checked state on the "Loop" item.
*/
void playbackMenu_About_To_Be_Shown();
/**
* @brief Function to prepare View menu.
*
* Primarily used to set the checked state of various options in the view menu (e.g. title safe area, timecode
* units, etc.)
*/
void viewMenu_About_To_Be_Shown();
/**
* @brief Function to prepare Tools menu.
*
* Primarily used to set the checked state on various settings available from the Tools menu.
*/
void toolMenu_About_To_Be_Shown();
/**
* @brief Toggle whether a panel is visible or not.
*
* Assumes the sender() QAction has a pointer to a QDockWidget in its data variable. Casts it and toggles its
* visibility.
*/
void toggle_panel_visibility();
/**
* @brief Set panel lock
*
* @param locked
*
* If **TRUE** prevents panels from being moved around. Defaults to **FALSE**.
*/
void set_panels_locked(bool locked);
private:
/**
* @brief Internal function for setting the panel layout to a predetermined preset.
*
* Resets layout to default and optionally loads a layout from file. If loading from file, this function will
* always load from `get_config_path() + "/layout"`.
*
* @param reset
*
* **TRUE** if this function should just reset the current layout. **FALSE** if it should load from the
* aforementioned layout file.
*/
void setup_layout(bool reset);
/**
* @brief Initialize menu bar menus and items.
*
* Internal initialization function for all menus and menu items in the main window. Called once from the
* MainWindow() constructor.
*/
void setup_menus();
void Retranslate();
// file menu actions
QMenu* file_menu;
QMenu* new_menu;
QAction* open_project;
QMenu* open_recent;
QAction* open_action;
QAction* clear_open_recent_action;
QAction* save_project;
QAction* save_project_as;
QAction* import_action;
QAction* export_action;
QAction* exit_action;
// edit menu actions
QMenu* edit_menu;
QAction* undo_action;
QAction* redo_action;
QAction* select_all_action;
QAction* deselect_all_action;
QAction* ripple_to_in_point_;
QAction* ripple_to_out_point_;
QAction* edit_to_in_point_;
QAction* edit_to_out_point_;
QAction* delete_inout_point_;
QAction* ripple_delete_inout_point_;
QAction* setedit_marker_;
// view menu actions
QMenu* view_menu;
QAction* zoom_in_;
QAction* zoom_out_;
QAction* increase_track_height_;
QAction* decrease_track_height_;
QAction* track_lines;
QAction* frames_action;
QAction* drop_frame_action;
QAction* nondrop_frame_action;
QAction* milliseconds_action;
QAction* no_autoscroll;
QAction* page_autoscroll;
QAction* smooth_autoscroll;
QMenu* title_safe_area_menu;
QAction* title_safe_off;
QAction* title_safe_default;
QAction* title_safe_43;
QAction* title_safe_169;
QAction* title_safe_custom;
QAction* full_screen;
QAction* full_screen_viewer_;
QAction* show_all;
// playback menu
QMenu* playback_menu;
QAction* go_to_start_;
QAction* previous_frame_;
QAction* playpause_;
QAction* play_in_to_out_;
QAction* next_frame_;
QAction* go_to_end_;
QAction* go_to_prev_cut_;
QAction* go_to_next_cut_;
QAction* go_to_in_point_;
QAction* go_to_out_point_;
QAction* shuttle_left_;
QAction* shuttle_stop_;
QAction* shuttle_right_;
QAction* loop_action_;
// window menu
QMenu* window_menu;
QAction* window_project_action;
QAction* window_effectcontrols_action;
QAction* window_timeline_action;
QAction* window_graph_editor_action;
QAction* window_footageviewer_action;
QAction* window_sequenceviewer_action;
QAction* maximize_panel_;
QAction* lock_panels_;
QAction* reset_default_layout_;
// tools menu
QMenu* tools_menu;
QAction* pointer_tool_action;
QAction* edit_tool_action;
QAction* ripple_tool_action;
QAction* razor_tool_action;
QAction* slip_tool_action;
QAction* slide_tool_action;
QAction* hand_tool_action;
QAction* transition_tool_action;
QAction* snap_toggle;
QAction* selecting_also_seeks;
QAction* edit_tool_also_seeks;
QAction* edit_tool_selects_links;
QAction* seek_to_end_of_pastes;
QAction* scroll_wheel_zooms;
QAction* invert_timeline_scroll_axes;
QAction* rectified_waveforms;
QAction* enable_drag_files_to_timeline;
QAction* autoscale_by_default;
QAction* enable_seek_to_import;
QAction* enable_audio_scrubbing;
QAction* enable_drop_on_media_to_replace;
QAction* enable_hover_focus;
QAction* set_name_and_marker;
QAction* seek_also_selects;
QAction* preferences_action_;
QAction* clear_undo_action_;
// help menu
QMenu* help_menu;
QAction* action_search_;
QAction* debug_log_;
QAction* about_action_;
// used to store the panel state when one panel is maximized
QByteArray temp_panel_state;
// used in paintEvent() to determine the first paintEvent() performed
bool first_show;
};
namespace olive {
extern MainWindow* MainWindow;
}
#endif // MAINWINDOW_H
+4 -4
View File
@@ -40,11 +40,11 @@ MediaIconService::MediaIconService() {
void MediaIconService::SetMediaIcon(Media *media, int icon_type) {
// if this icon is already part of the throbber animation loop, remove it
if (throbber_items_.contains(media)) {
// throbber_lock_.lock();
throbber_lock_.lock();
throbber_items_.removeAll(media);
// throbber_lock_.unlock();
throbber_lock_.unlock();
// if we aren't animating anything, no need to run the timer for now
if (throbber_items_.empty()) {
@@ -90,13 +90,13 @@ void MediaIconService::AnimationUpdate() {
QIcon throbber_ico = QIcon(throbber_pixmap_.copy(kThrobberSize*throbber_animation_frame_, 0, kThrobberSize, kThrobberSize));
// throbber_lock_.lock();
throbber_lock_.lock();
for (int i=0;i<throbber_items_.size();i++) {
olive::project_model.set_icon(throbber_items_.at(i), throbber_ico);
}
// throbber_lock_.unlock();
throbber_lock_.unlock();
throbber_animation_frame_++;
}
+16 -16
View File
@@ -28,33 +28,33 @@
#include "project/media.h"
enum IconType {
ICON_TYPE_VIDEO,
ICON_TYPE_AUDIO,
ICON_TYPE_IMAGE,
ICON_TYPE_LOADING,
ICON_TYPE_ERROR
ICON_TYPE_VIDEO,
ICON_TYPE_AUDIO,
ICON_TYPE_IMAGE,
ICON_TYPE_LOADING,
ICON_TYPE_ERROR
};
class MediaIconService : public QObject {
Q_OBJECT
Q_OBJECT
public:
MediaIconService();
MediaIconService();
public slots:
void SetMediaIcon(Media* media, int icon_type);
void SetMediaIcon(Media* media, int icon_type);
signals:
void IconChanged();
void IconChanged();
private slots:
void AnimationUpdate();
void AnimationUpdate();
private:
int throbber_animation_frame_;
QVector<Media*> throbber_items_;
QTimer throbber_animator_;
QPixmap throbber_pixmap_;
QMutex throbber_lock_;
int throbber_animation_frame_;
QVector<Media*> throbber_items_;
QTimer throbber_animator_;
QPixmap throbber_pixmap_;
QMutex throbber_lock_;
};
namespace olive {
extern std::unique_ptr<MediaIconService> media_icon_service;
extern std::unique_ptr<MediaIconService> media_icon_service;
}
#endif // MEDIAICONSERVICE_H
+26 -17
View File
@@ -20,21 +20,18 @@
#include "menuhelper.h"
#include "oliveglobal.h"
#include "ui/focusfilter.h"
#include "io/config.h"
#include "panels/panels.h"
#include "mainwindow.h"
#include <QMessageBox>
#include <QInputDialog>
#include <QPushButton>
#include <QStyleFactory>
#include "global/config.h"
#include "project/clipboard.h"
#include "ui/mainwindow.h"
#include "global/global.h"
#include "panels/panels.h"
#include "ui/focusfilter.h"
MenuHelper olive::MenuHelper;
void MenuHelper::InitializeSharedMenus()
@@ -125,15 +122,21 @@ void MenuHelper::make_clip_functions_menu(QMenu *parent) {
parent->addAction(nest_);
}
void MenuHelper::make_edit_functions_menu(QMenu *parent) {
parent->addAction(cut_);
parent->addAction(copy_);
void MenuHelper::make_edit_functions_menu(QMenu *parent, bool objects_are_selected) {
if (objects_are_selected) {
parent->addAction(cut_);
parent->addAction(copy_);
}
parent->addAction(paste_);
parent->addAction(paste_insert_);
parent->addAction(duplicate_);
parent->addAction(delete_);
parent->addAction(ripple_delete_);
parent->addAction(split_);
if (objects_are_selected) {
parent->addAction(duplicate_);
parent->addAction(delete_);
parent->addAction(ripple_delete_);
parent->addAction(split_);
}
}
void MenuHelper::set_bool_action_checked(QAction *a) {
@@ -262,6 +265,12 @@ void MenuHelper::open_recent_from_menu() {
olive::Global.get()->open_recent(index);
}
void MenuHelper::create_effect_paste_action(QMenu *menu)
{
QAction* paste_action = menu->addAction(tr("&Paste"), panel_timeline, SLOT(paste(bool)));
paste_action->setEnabled(clipboard.size() > 0 && clipboard_type == CLIPBOARD_TYPE_EFFECT);
}
QMenu* MenuHelper::create_submenu(QMenuBar* parent,
const QObject *receiver,
const char *member) {
+15 -1
View File
@@ -75,8 +75,13 @@ public:
* @param parent
*
* The menu to add items to.
*
* @param objects_are_selected
*
* Some extra functions may be hidden in the event no clip is actually selected. Set this to **FALSE** to hide those
* functions.
*/
void make_edit_functions_menu(QMenu* parent);
void make_edit_functions_menu(QMenu* parent, bool objects_are_selected = true);
/**
* @brief Sets the checked state of a menu item based on a Boolean variable.
@@ -186,6 +191,15 @@ public slots:
*/
void open_recent_from_menu();
/**
* @brief Create a "Paste" action on the specified menu that's enabled only if the clipboard contains effects
*
* @param menu
*
* Menu to add action to
*/
void create_effect_paste_action(QMenu *menu);
private:
QAction* new_project_;
QAction* new_sequence_;
+1 -1
View File
@@ -24,7 +24,7 @@
#include <QStyle>
#include <QStyleOptionSlider>
#include "debug.h"
#include "global/debug.h"
#define RESIZE_HANDLE_SIZE 10
+1 -1
View File
@@ -23,7 +23,7 @@
#include <QWheelEvent>
#include <QDebug>
#include "io/config.h"
#include "global/config.h"
#include "panels/panels.h"
#include "panels/timeline.h"
+37 -37
View File
@@ -25,65 +25,65 @@
#include "panels/project.h"
#include "project/media.h"
#include "project/sourcescommon.h"
#include "debug.h"
#include "global/debug.h"
SourceIconView::SourceIconView(QWidget *parent) : QListView(parent) {
setSelectionMode(QAbstractItemView::ExtendedSelection);
setResizeMode(QListView::Adjust);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
setSelectionMode(QAbstractItemView::ExtendedSelection);
setResizeMode(QListView::Adjust);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
}
void SourceIconView::show_context_menu() {
project_parent->sources_common->show_context_menu(this, selectedIndexes());
project_parent->sources_common->show_context_menu(this, selectedIndexes());
}
void SourceIconView::item_click(const QModelIndex& index) {
if (selectedIndexes().size() == 1 && index.column() == 0) {
project_parent->sources_common->item_click(project_parent->item_to_media(index), index);
}
if (selectedIndexes().size() == 1 && index.column() == 0) {
project_parent->sources_common->item_click(project_parent->item_to_media(index), index);
}
}
void SourceIconView::mousePressEvent(QMouseEvent* event) {
project_parent->sources_common->mousePressEvent(event);
if (!indexAt(event->pos()).isValid()) selectionModel()->clear();
QListView::mousePressEvent(event);
project_parent->sources_common->mousePressEvent(event);
if (!indexAt(event->pos()).isValid()) selectionModel()->clear();
QListView::mousePressEvent(event);
}
void SourceIconView::dragEnterEvent(QDragEnterEvent *event) {
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QListView::dragEnterEvent(event);
}
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QListView::dragEnterEvent(event);
}
}
void SourceIconView::dragMoveEvent(QDragMoveEvent *event) {
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QListView::dragMoveEvent(event);
}
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QListView::dragMoveEvent(event);
}
}
void SourceIconView::dropEvent(QDropEvent* event) {
QModelIndex drop_item = indexAt(event->pos());
if (!drop_item.isValid()) drop_item = rootIndex();
project_parent->sources_common->dropEvent(this, event, drop_item, selectedIndexes());
QModelIndex drop_item = indexAt(event->pos());
if (!drop_item.isValid()) drop_item = rootIndex();
project_parent->sources_common->dropEvent(this, event, drop_item, selectedIndexes());
}
void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) {
bool default_behavior = true;
if (selectedIndexes().size() == 1) {
Media* m = project_parent->item_to_media(selectedIndexes().at(0));
if (m->get_type() == MEDIA_TYPE_FOLDER) {
default_behavior = false;
setRootIndex(selectedIndexes().at(0));
emit changed_root();
}
}
if (default_behavior) {
bool default_behavior = true;
if (selectedIndexes().size() == 1) {
Media* m = project_parent->item_to_media(selectedIndexes().at(0));
if (m->get_type() == MEDIA_TYPE_FOLDER) {
default_behavior = false;
setRootIndex(selectedIndexes().at(0));
emit changed_root();
}
}
if (default_behavior) {
project_parent->sources_common->mouseDoubleClickEvent(selectedIndexes());
}
}
}
+30 -30
View File
@@ -26,13 +26,13 @@
#include "panels/viewer.h"
#include "panels/panels.h"
#include "rendering/renderfunctions.h"
#include "project/undo.h"
#include "project/sequence.h"
#include "undo/undo.h"
#include "timeline/sequence.h"
#include "mainwindow.h"
#include "io/config.h"
#include "global/config.h"
#include "project/media.h"
#include "project/sourcescommon.h"
#include "debug.h"
#include "global/debug.h"
#include <QDragEnterEvent>
#include <QMimeData>
@@ -46,30 +46,30 @@
#include <QProcess>
SourceTable::SourceTable(QWidget* parent) : QTreeView(parent) {
setSortingEnabled(true);
setAcceptDrops(true);
sortByColumn(0, Qt::AscendingOrder);
setContextMenuPolicy(Qt::CustomContextMenu);
setEditTriggers(QAbstractItemView::NoEditTriggers);
setDragDropMode(QAbstractItemView::DragDrop);
setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
setSortingEnabled(true);
setAcceptDrops(true);
sortByColumn(0, Qt::AscendingOrder);
setContextMenuPolicy(Qt::CustomContextMenu);
setEditTriggers(QAbstractItemView::NoEditTriggers);
setDragDropMode(QAbstractItemView::DragDrop);
setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
}
void SourceTable::show_context_menu() {
project_parent->sources_common->show_context_menu(this, selectionModel()->selectedRows());
project_parent->sources_common->show_context_menu(this, selectionModel()->selectedRows());
}
void SourceTable::item_click(const QModelIndex& index) {
if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) {
project_parent->sources_common->item_click(project_parent->item_to_media(index), index);
}
if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) {
project_parent->sources_common->item_click(project_parent->item_to_media(index), index);
}
}
void SourceTable::mousePressEvent(QMouseEvent* event) {
project_parent->sources_common->mousePressEvent(event);
QTreeView::mousePressEvent(event);
project_parent->sources_common->mousePressEvent(event);
QTreeView::mousePressEvent(event);
}
void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) {
@@ -77,21 +77,21 @@ void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) {
}
void SourceTable::dragEnterEvent(QDragEnterEvent *event) {
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QTreeView::dragEnterEvent(event);
}
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QTreeView::dragEnterEvent(event);
}
}
void SourceTable::dragMoveEvent(QDragMoveEvent *event) {
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QTreeView::dragMoveEvent(event);
}
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else {
QTreeView::dragMoveEvent(event);
}
}
void SourceTable::dropEvent(QDropEvent* event) {
project_parent->sources_common->dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows());
project_parent->sources_common->dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows());
}
+10 -10
View File
@@ -30,19 +30,19 @@ class Media;
class SourceTable : public QTreeView
{
Q_OBJECT
Q_OBJECT
public:
SourceTable(QWidget* parent = 0);
Project* project_parent;
SourceTable(QWidget* parent = 0);
Project* project_parent;
protected:
void mousePressEvent(QMouseEvent*);
void mouseDoubleClickEvent(QMouseEvent *);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
void mousePressEvent(QMouseEvent*);
void mouseDoubleClickEvent(QMouseEvent *);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private slots:
void item_click(const QModelIndex& index);
void show_context_menu();
void item_click(const QModelIndex& index);
void show_context_menu();
};
#endif // SOURCETABLE_H
+24
View File
@@ -0,0 +1,24 @@
#include "styling.h"
#include "global/config.h"
bool olive::styling::UseDarkIcons()
{
return olive::CurrentConfig.style == kOliveDefaultLight || olive::CurrentConfig.style == kNativeDarkIcons;
}
QColor olive::styling::GetIconColor()
{
if (UseDarkIcons()) {
return Qt::black;
} else {
return Qt::white;
}
}
bool olive::styling::UseNativeUI()
{
return olive::CurrentConfig.style == kNativeLightIcons || olive::CurrentConfig.style == kNativeDarkIcons;
}
+67
View File
@@ -0,0 +1,67 @@
#ifndef STYLING_H
#define STYLING_H
#include <QColor>
namespace olive {
namespace styling {
/**
* @brief Officially supported styles to use in Olive
*/
enum Style {
/**
Qt Fusion-based cross-platform UI. The default styling of Olive. Can also be heavily customized with a CSS
file.
*/
kOliveDefaultDark,
/**
Qt Fusion-based cross-platform UI. The default styling of Olive. Can also be heavily customized with a CSS
file. This will use the
*/
kOliveDefaultLight,
/**
Use current OS's native styling (or at least Qt's default). Most UIs use a light theming, so this will
automatically implement dark icons/UI elements.
*/
kNativeDarkIcons,
/**
Use current OS's native styling (or at least Qt's default). Most UIs use a light theming, but in case one
doesn't, this option will provide light icons for use with a dark theme.
*/
kNativeLightIcons
};
/**
* @brief Return whether to use dark icons or light icons
* @return
*
* **TRUE** if icons should be dark.
*/
bool UseDarkIcons();
/**
* @brief Return whether to use native UI or Fusion
* @return
*
* **TRUE** if UI should use native styling
*/
bool UseNativeUI();
/**
* @brief Return the current icon color based on Config::use_dark_icons.
*
* Also used by some other UI elements like the lines and text on the TimelineHeader
*
* @return
*
* Either white or black depending on Config::use_dark_icons
*/
QColor GetIconColor();
}
}
#endif // STYLING_H
+34 -31
View File
@@ -21,42 +21,45 @@
#include "texteditex.h"
#include <QDebug>
#include <QMenu>
TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) {
setUndoRedoEnabled(false);
connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals()));
connect(this, SIGNAL(updateSelf()), this, SLOT(updateText()));
#include "dialogs/texteditdialog.h"
#include "mainwindow.h"
TextEditEx::TextEditEx(QWidget *parent, bool enable_rich_text) :
QTextEdit(parent),
enable_rich_text_(enable_rich_text)
{
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu()));
connect(this, SIGNAL(textChanged()), this, SLOT(queue_text_modified()));
}
const QString& TextEditEx::getPlainTextEx() {
return text;
void TextEditEx::text_edit_menu() {
QMenu menu;
menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit()));
menu.exec(QCursor::pos());
}
void TextEditEx::setPlainTextEx(const QString &t) {
previousText = text;
text = t;
emit updateSelf();
void TextEditEx::open_text_edit() {
const QString& current_text = (enable_rich_text_) ? toHtml() : toPlainText();
TextEditDialog ted(olive::MainWindow, current_text, enable_rich_text_);
ted.exec();
QString result = ted.get_string();
if (!result.isEmpty()) {
if (enable_rich_text_) {
setHtml(result);
} else {
setPlainText(result);
}
}
}
const QString &TextEditEx::getPreviousValue() {
return previousText;
}
void TextEditEx::updateInternals() {
previousText = text;
text = toPlainText();
}
void TextEditEx::updateText() {
blockSignals(true);
int pos = textCursor().position();
setPlainText(text);
QTextCursor newCursor(document());
newCursor.setPosition(pos);
setTextCursor(newCursor);
blockSignals(false);
void TextEditEx::queue_text_modified()
{
emit textModified(enable_rich_text_ ? toHtml() : toPlainText());
}
+7 -10
View File
@@ -24,20 +24,17 @@
#include <QTextEdit>
class TextEditEx : public QTextEdit {
Q_OBJECT
Q_OBJECT
public:
TextEditEx(QWidget* parent = 0);
void setPlainTextEx(const QString &text);
const QString& getPreviousValue();
const QString& getPlainTextEx();
TextEditEx(QWidget* parent = nullptr, bool enable_rich_text = true);
signals:
void updateSelf();
void textModified(const QString& s);
private slots:
void updateInternals();
void updateText();
void text_edit_menu();
void open_text_edit();
void queue_text_modified();
private:
QString previousText;
QString text;
bool enable_rich_text_;
};
#endif // TEXTEDITEX_H
+332 -329
View File
@@ -20,17 +20,6 @@
#include "timelineheader.h"
#include "mainwindow.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "project/sequence.h"
#include "project/undo.h"
#include "project/media.h"
#include "panels/viewer.h"
#include "io/config.h"
#include "ui/menuhelper.h"
#include "debug.h"
#include <QPainter>
#include <QMouseEvent>
#include <QScrollBar>
@@ -38,6 +27,19 @@
#include <QMenu>
#include <QAction>
#include "mainwindow.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "timeline/sequence.h"
#include "undo/undo.h"
#include "project/media.h"
#include "panels/viewer.h"
#include "global/config.h"
#include "global/global.h"
#include "ui/menuhelper.h"
#include "global/debug.h"
#include "undo/undostack.h"
#define CLICK_RANGE 5
#define PLAYHEAD_SIZE 6
#define LINE_MIN_PADDING 50
@@ -47,428 +49,429 @@
#define TEXT_PADDING_FROM_LINE 4
bool center_scroll_to_playhead(QScrollBar* bar, double zoom, long playhead) {
// returns true is the scroll was changed, false if not
int target_scroll = qMin(bar->maximum(), qMax(0, getScreenPointFromFrame(zoom, playhead)-(bar->width()>>1)));
if (target_scroll == bar->value()) {
return false;
}
bar->setValue(target_scroll);
return true;
// returns true is the scroll was changed, false if not
int target_scroll = qMin(bar->maximum(), qMax(0, getScreenPointFromFrame(zoom, playhead)-(bar->width()>>1)));
if (target_scroll == bar->value()) {
return false;
}
bar->setValue(target_scroll);
return true;
}
TimelineHeader::TimelineHeader(QWidget *parent) :
QWidget(parent),
snapping(true),
dragging(false),
resizing_workarea(false),
zoom(1),
in_visible(0),
fm(font()),
dragging_markers(false),
scroll(0)
QWidget(parent),
snapping(true),
dragging(false),
resizing_workarea(false),
zoom(1),
in_visible(0),
fm(font()),
dragging_markers(false),
scroll(0)
{
height_actual = fm.height();
setCursor(Qt::ArrowCursor);
setMouseTracking(true);
setFocusPolicy(Qt::ClickFocus);
show_text(true);
height_actual = fm.height();
setCursor(Qt::ArrowCursor);
setMouseTracking(true);
setFocusPolicy(Qt::ClickFocus);
show_text(true);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(show_context_menu(const QPoint &)));
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(show_context_menu(const QPoint &)));
}
void TimelineHeader::set_scroll(int s) {
scroll = s;
update();
scroll = s;
update();
}
long TimelineHeader::getHeaderFrameFromScreenPoint(int x) {
return getFrameFromScreenPoint(zoom, x + scroll) + in_visible;
return getFrameFromScreenPoint(zoom, x + scroll) + in_visible;
}
int TimelineHeader::getHeaderScreenPointFromFrame(long frame) {
return getScreenPointFromFrame(zoom, frame - in_visible) - scroll;
return getScreenPointFromFrame(zoom, frame - in_visible) - scroll;
}
void TimelineHeader::set_playhead(int mouse_x) {
long frame = getHeaderFrameFromScreenPoint(mouse_x);
if (snapping) panel_timeline->snap_to_timeline(&frame, false, true, true);
if (frame != viewer->seq->playhead) {
viewer->seek(frame);
}
long frame = getHeaderFrameFromScreenPoint(mouse_x);
if (snapping) panel_timeline->snap_to_timeline(&frame, false, true, true);
if (frame != viewer->seq->playhead) {
viewer->seek(frame);
}
}
int TimelineHeader::get_marker_offset() {
return (text_enabled) ? height()/2 : 0;
return (text_enabled) ? height()/2 : 0;
}
void TimelineHeader::set_visible_in(long i) {
in_visible = i;
update();
in_visible = i;
update();
}
void TimelineHeader::set_in_point(long new_in) {
long new_out = viewer->seq->workarea_out;
if (new_out == new_in) {
new_in--;
} else if (new_out < new_in) {
new_out = viewer->seq->getEndFrame();
}
long new_out = viewer->seq->workarea_out;
if (new_out == new_in) {
new_in--;
} else if (new_out < new_in) {
new_out = viewer->seq->getEndFrame();
}
olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq, true, new_in, new_out));
update_parents();
olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out));
update_parents();
}
void TimelineHeader::set_out_point(long new_out) {
long new_in = viewer->seq->workarea_in;
if (new_out == new_in) {
new_out++;
} else if (new_in > new_out || new_in < 0) {
new_in = 0;
}
long new_in = viewer->seq->workarea_in;
if (new_out == new_in) {
new_out++;
} else if (new_in > new_out || new_in < 0) {
new_in = 0;
}
olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq, true, new_in, new_out));
update_parents();
olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out));
update_parents();
}
void TimelineHeader::set_scrollbar_max(QScrollBar* bar, long sequence_end_frame, int offset) {
bar->setMaximum(qMax(0, getScreenPointFromFrame(zoom, sequence_end_frame) - offset));
bar->setMaximum(qMax(0, getScreenPointFromFrame(zoom, sequence_end_frame) - offset));
}
void TimelineHeader::show_text(bool enable) {
text_enabled = enable;
if (enable) {
setFixedHeight(height_actual*2);
} else {
setFixedHeight(height_actual);
}
update();
text_enabled = enable;
if (enable) {
setFixedHeight(height_actual*2);
} else {
setFixedHeight(height_actual);
}
update();
}
void TimelineHeader::mousePressEvent(QMouseEvent* event) {
if (viewer->seq != nullptr && event->buttons() & Qt::LeftButton) {
if (resizing_workarea) {
sequence_end = viewer->seq->getEndFrame();
} else {
/*int
QPoint start(in_x, height()+2);
QPainterPath path;
path.moveTo(start + QPoint(1,0));
path.lineTo(in_x-PLAYHEAD_SIZE, yoff);
path.lineTo(in_x+PLAYHEAD_SIZE+1, yoff);*/
if (viewer->seq != nullptr && event->buttons() & Qt::LeftButton) {
if (resizing_workarea) {
sequence_end = viewer->seq->getEndFrame();
} else {
/*int
QPoint start(in_x, height()+2);
QPainterPath path;
path.moveTo(start + QPoint(1,0));
path.lineTo(in_x-PLAYHEAD_SIZE, yoff);
path.lineTo(in_x+PLAYHEAD_SIZE+1, yoff);*/
bool shift = (event->modifiers() & Qt::ShiftModifier);
bool clicked_on_marker = false;
int playhead_x = getHeaderScreenPointFromFrame(viewer->seq->playhead);
bool shift = (event->modifiers() & Qt::ShiftModifier);
bool clicked_on_marker = false;
int playhead_x = getHeaderScreenPointFromFrame(viewer->seq->playhead);
if (event->pos().y() > get_marker_offset()
&& (event->pos().x() < playhead_x-PLAYHEAD_SIZE
|| event->pos().x() > playhead_x+PLAYHEAD_SIZE)) {
for (int i=0;i<viewer->marker_ref->size();i++) {
int marker_pos = getHeaderScreenPointFromFrame(viewer->marker_ref->at(i).frame);
if (event->pos().x() > marker_pos - MARKER_SIZE && event->pos().x() < marker_pos + MARKER_SIZE) {
bool found = false;
for (int j=0;j<selected_markers.size();j++) {
if (selected_markers.at(j) == i) {
if (shift) {
selected_markers.removeAt(j);
}
found = true;
break;
}
}
if (!found) {
if (!shift) {
selected_markers.clear();
}
selected_markers.append(i);
}
clicked_on_marker = true;
update();
break;
}
}
}
if (event->pos().y() > get_marker_offset()
&& (event->pos().x() < playhead_x-PLAYHEAD_SIZE
|| event->pos().x() > playhead_x+PLAYHEAD_SIZE)) {
for (int i=0;i<viewer->marker_ref->size();i++) {
int marker_pos = getHeaderScreenPointFromFrame(viewer->marker_ref->at(i).frame);
if (event->pos().x() > marker_pos - MARKER_SIZE && event->pos().x() < marker_pos + MARKER_SIZE) {
bool found = false;
for (int j=0;j<selected_markers.size();j++) {
if (selected_markers.at(j) == i) {
if (shift) {
selected_markers.removeAt(j);
}
found = true;
break;
}
}
if (!found) {
if (!shift) {
selected_markers.clear();
}
selected_markers.append(i);
}
clicked_on_marker = true;
update();
break;
}
}
}
if (clicked_on_marker) {
selected_marker_original_times.resize(selected_markers.size());
for (int i=0;i<selected_markers.size();i++) {
selected_marker_original_times[i] = viewer->marker_ref->at(selected_markers.at(i)).frame;
}
drag_start = event->pos().x();
dragging_markers = true;
} else {
if (selected_markers.size() > 0 && !shift) {
selected_markers.clear();
update();
}
set_playhead(event->pos().x());
}
}
dragging = true;
}
if (clicked_on_marker) {
selected_marker_original_times.resize(selected_markers.size());
for (int i=0;i<selected_markers.size();i++) {
selected_marker_original_times[i] = viewer->marker_ref->at(selected_markers.at(i)).frame;
}
drag_start = event->pos().x();
dragging_markers = true;
} else {
if (selected_markers.size() > 0 && !shift) {
selected_markers.clear();
update();
}
set_playhead(event->pos().x());
}
}
dragging = true;
}
}
void TimelineHeader::mouseMoveEvent(QMouseEvent* event) {
if (viewer->seq != nullptr) {
if (dragging) {
if (resizing_workarea) {
long frame = getHeaderFrameFromScreenPoint(event->pos().x());
if (snapping) panel_timeline->snap_to_timeline(&frame, true, true, false);
if (viewer->seq != nullptr) {
if (dragging) {
if (resizing_workarea) {
long frame = getHeaderFrameFromScreenPoint(event->pos().x());
if (snapping) panel_timeline->snap_to_timeline(&frame, true, true, false);
if (resizing_workarea_in) {
temp_workarea_in = qMax(qMin(temp_workarea_out-1, frame), 0L);
} else {
temp_workarea_out = qMin(qMax(temp_workarea_in+1, frame), sequence_end);
}
if (resizing_workarea_in) {
temp_workarea_in = qMax(qMin(temp_workarea_out-1, frame), 0L);
} else {
temp_workarea_out = qMin(qMax(temp_workarea_in+1, frame), sequence_end);
}
update_parents();
} else if (dragging_markers) {
long frame_movement = getHeaderFrameFromScreenPoint(event->pos().x()) - getHeaderFrameFromScreenPoint(drag_start);
update_parents();
} else if (dragging_markers) {
long frame_movement = getHeaderFrameFromScreenPoint(event->pos().x()) - getHeaderFrameFromScreenPoint(drag_start);
// snap markers
for (int i=0;i<selected_markers.size();i++) {
long fm = selected_marker_original_times.at(i) + frame_movement;
if (snapping && panel_timeline->snap_to_timeline(&fm, true, false, true)) {
frame_movement = fm - selected_marker_original_times.at(i);
break;
}
}
// snap markers
for (int i=0;i<selected_markers.size();i++) {
long fm = selected_marker_original_times.at(i) + frame_movement;
if (snapping && panel_timeline->snap_to_timeline(&fm, true, false, true)) {
frame_movement = fm - selected_marker_original_times.at(i);
break;
}
}
// validate markers (ensure none go below 0)
long validator;
for (int i=0;i<selected_markers.size();i++) {
validator = selected_marker_original_times.at(i) + frame_movement;
if (validator < 0) {
frame_movement -= validator;
}
}
// validate markers (ensure none go below 0)
long validator;
for (int i=0;i<selected_markers.size();i++) {
validator = selected_marker_original_times.at(i) + frame_movement;
if (validator < 0) {
frame_movement -= validator;
}
}
// move markers
for (int i=0;i<selected_markers.size();i++) {
viewer->marker_ref[0][selected_markers.at(i)].frame = selected_marker_original_times.at(i) + frame_movement;
}
// move markers
for (int i=0;i<selected_markers.size();i++) {
viewer->marker_ref[0][selected_markers.at(i)].frame = selected_marker_original_times.at(i) + frame_movement;
}
update_parents();
} else {
set_playhead(event->pos().x());
}
} else {
resizing_workarea = false;
unsetCursor();
if (viewer->seq != nullptr && viewer->seq->using_workarea) {
long min_frame = getHeaderFrameFromScreenPoint(event->pos().x() - CLICK_RANGE) - 1;
long max_frame = getHeaderFrameFromScreenPoint(event->pos().x() + CLICK_RANGE) + 1;
if (viewer->seq->workarea_in > min_frame && viewer->seq->workarea_in < max_frame) {
resizing_workarea = true;
resizing_workarea_in = true;
} else if (viewer->seq->workarea_out > min_frame && viewer->seq->workarea_out < max_frame) {
resizing_workarea = true;
resizing_workarea_in = false;
}
if (resizing_workarea) {
temp_workarea_in = viewer->seq->workarea_in;
temp_workarea_out = viewer->seq->workarea_out;
setCursor(Qt::SizeHorCursor);
}
}
}
}
update_parents();
} else {
set_playhead(event->pos().x());
}
} else {
resizing_workarea = false;
unsetCursor();
if (viewer->seq != nullptr && viewer->seq->using_workarea) {
long min_frame = getHeaderFrameFromScreenPoint(event->pos().x() - CLICK_RANGE) - 1;
long max_frame = getHeaderFrameFromScreenPoint(event->pos().x() + CLICK_RANGE) + 1;
if (viewer->seq->workarea_in > min_frame && viewer->seq->workarea_in < max_frame) {
resizing_workarea = true;
resizing_workarea_in = true;
} else if (viewer->seq->workarea_out > min_frame && viewer->seq->workarea_out < max_frame) {
resizing_workarea = true;
resizing_workarea_in = false;
}
if (resizing_workarea) {
temp_workarea_in = viewer->seq->workarea_in;
temp_workarea_out = viewer->seq->workarea_out;
setCursor(Qt::SizeHorCursor);
}
}
}
}
}
void TimelineHeader::mouseReleaseEvent(QMouseEvent*) {
if (viewer->seq != nullptr) {
dragging = false;
if (resizing_workarea) {
olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq, true, temp_workarea_in, temp_workarea_out));
} else if (dragging_markers && selected_markers.size() > 0) {
bool moved = false;
ComboAction* ca = new ComboAction();
for (int i=0;i<selected_markers.size();i++) {
Marker* m = &viewer->marker_ref[0][selected_markers.at(i)];
if (selected_marker_original_times.at(i) != m->frame) {
ca->append(new MoveMarkerAction(m, selected_marker_original_times.at(i), m->frame));
moved = true;
}
}
if (moved) {
olive::UndoStack.push(ca);
} else {
delete ca;
}
}
if (viewer->seq != nullptr) {
dragging = false;
if (resizing_workarea) {
olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, temp_workarea_in, temp_workarea_out));
} else if (dragging_markers && selected_markers.size() > 0) {
bool moved = false;
ComboAction* ca = new ComboAction();
for (int i=0;i<selected_markers.size();i++) {
Marker* m = &viewer->marker_ref[0][selected_markers.at(i)];
if (selected_marker_original_times.at(i) != m->frame) {
ca->append(new MoveMarkerAction(m, selected_marker_original_times.at(i), m->frame));
moved = true;
}
}
if (moved) {
olive::UndoStack.push(ca);
} else {
delete ca;
}
}
resizing_workarea = false;
dragging = false;
dragging_markers = false;
panel_timeline->snapped = false;
update_parents();
}
resizing_workarea = false;
dragging = false;
dragging_markers = false;
panel_timeline->snapped = false;
update_parents();
}
}
void TimelineHeader::focusOutEvent(QFocusEvent*) {
selected_markers.clear();
update();
selected_markers.clear();
update();
}
void TimelineHeader::update_parents() {
viewer->update_parents();
viewer->update_parents();
}
void TimelineHeader::update_zoom(double z) {
zoom = z;
update();
zoom = z;
update();
}
double TimelineHeader::get_zoom() {
return zoom;
return zoom;
}
void TimelineHeader::delete_markers() {
if (selected_markers.size() > 0) {
DeleteMarkerAction* dma = new DeleteMarkerAction(viewer->marker_ref);
for (int i=0;i<selected_markers.size();i++) {
dma->markers.append(selected_markers.at(i));
}
olive::UndoStack.push(dma);
update_parents();
}
if (selected_markers.size() > 0) {
DeleteMarkerAction* dma = new DeleteMarkerAction(viewer->marker_ref);
for (int i=0;i<selected_markers.size();i++) {
dma->markers.append(selected_markers.at(i));
}
olive::UndoStack.push(dma);
update_parents();
}
}
void TimelineHeader::paintEvent(QPaintEvent*) {
if (viewer->seq != nullptr && zoom > 0) {
QPainter p(this);
int yoff = get_marker_offset();
if (viewer->seq != nullptr && zoom > 0) {
QPainter p(this);
int yoff = get_marker_offset();
double interval = viewer->seq->frame_rate;
int textWidth = 0;
int lastTextBoundary = INT_MIN;
double interval = viewer->seq->frame_rate;
int textWidth = 0;
int lastTextBoundary = INT_MIN;
int lastLineX = INT_MIN;
int lastLineX = INT_MIN;
int sublineCount = 1;
int sublineTest = qRound(interval*zoom);
int sublineInterval = 1;
while (sublineTest > SUBLINE_MIN_PADDING
&& sublineInterval >= 1) {
sublineCount *= 2;
sublineInterval = (interval/sublineCount);
sublineTest = qRound(sublineInterval*zoom);
}
sublineCount = qMin(sublineCount, qRound(interval));
int sublineCount = 1;
int sublineTest = qRound(interval*zoom);
int sublineInterval = 1;
while (sublineTest > SUBLINE_MIN_PADDING
&& sublineInterval >= 1) {
sublineCount *= 2;
sublineInterval = (interval/sublineCount);
sublineTest = qRound(sublineInterval*zoom);
}
sublineCount = qMin(sublineCount, qRound(interval));
int text_x, fullTextWidth;
QString timecode;
int text_x, fullTextWidth;
QString timecode;
// find where to start drawing lines (lineX algorithm reversed if lineX = 0)
int i = qFloor(double(scroll)/zoom/interval);
// find where to start drawing lines (lineX algorithm reversed if lineX = 0)
int i = qFloor(double(scroll)/zoom/interval);
while (true) {
long frame = qRound(interval*i);
int lineX = qRound(frame*zoom) - scroll;
while (true) {
long frame = qRound(interval*i);
int lineX = qRound(frame*zoom) - scroll;
if (lineX > width()) break;
if (lineX > width()) break;
// draw text
bool draw_text = false;
if (text_enabled && lineX-textWidth > lastTextBoundary) {
timecode = frame_to_timecode(frame + in_visible, olive::CurrentConfig.timecode_view, viewer->seq->frame_rate);
fullTextWidth = fm.width(timecode);
textWidth = fullTextWidth>>1;
// draw text
bool draw_text = false;
if (text_enabled && lineX-textWidth > lastTextBoundary) {
timecode = frame_to_timecode(frame + in_visible, olive::CurrentConfig.timecode_view, viewer->seq->frame_rate);
fullTextWidth = fm.width(timecode);
textWidth = fullTextWidth>>1;
text_x = lineX;
text_x = lineX;
// centers the text to that point on the timeline, LEFT aligns it if not
if (olive::CurrentConfig.center_timeline_timecodes) {
text_x -= textWidth;
} else {
text_x += TEXT_PADDING_FROM_LINE;
}
// centers the text to that point on the timeline, LEFT aligns it if not
if (olive::CurrentConfig.center_timeline_timecodes) {
text_x -= textWidth;
} else {
text_x += TEXT_PADDING_FROM_LINE;
}
lastTextBoundary = lineX+textWidth;
if (lastTextBoundary >= 0) {
draw_text = true;
}
}
lastTextBoundary = lineX+textWidth;
if (lastTextBoundary >= 0) {
draw_text = true;
}
}
if (lineX > lastLineX+LINE_MIN_PADDING) {
if (draw_text) {
p.setPen(Qt::white);
p.drawText(QRect(text_x, 0, fullTextWidth, yoff), timecode);
}
if (lineX > lastLineX+LINE_MIN_PADDING) {
if (draw_text) {
p.setPen(olive::styling::GetIconColor());
p.drawText(QRect(text_x, 0, fullTextWidth, yoff), timecode);
}
// draw line markers
p.setPen(Qt::gray);
p.drawLine(lineX, (!olive::CurrentConfig.center_timeline_timecodes && draw_text) ? 0 : yoff, lineX, height());
// draw line markers
p.setPen(Qt::gray);
p.drawLine(lineX, (!olive::CurrentConfig.center_timeline_timecodes && draw_text) ? 0 : yoff, lineX, height());
// draw sub-line markers
for (int j=1;j<sublineCount;j++) {
int sublineX = lineX+(qRound(j*interval/sublineCount)*zoom);
p.drawLine(sublineX, yoff, sublineX, yoff+(height()/4));
}
// draw sub-line markers
for (int j=1;j<sublineCount;j++) {
int sublineX = lineX+(qRound(j*interval/sublineCount)*zoom);
p.drawLine(sublineX, yoff, sublineX, yoff+(height()/4));
}
lastLineX = lineX;
}
lastLineX = lineX;
}
i++;
}
i++;
}
// draw in/out selection
int in_x;
if (viewer->seq->using_workarea) {
in_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_in : viewer->seq->workarea_in));
int out_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_out : viewer->seq->workarea_out));
p.fillRect(QRect(in_x, 0, out_x-in_x, height()), QColor(0, 192, 255, 128));
p.setPen(Qt::white);
p.drawLine(in_x, 0, in_x, height());
p.drawLine(out_x, 0, out_x, height());
}
// draw in/out selection
int in_x;
if (viewer->seq->using_workarea) {
in_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_in : viewer->seq->workarea_in));
int out_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_out : viewer->seq->workarea_out));
p.fillRect(QRect(in_x, 0, out_x-in_x, height()), QColor(0, 192, 255, 128));
p.setPen(olive::styling::GetIconColor());
p.drawLine(in_x, 0, in_x, height());
p.drawLine(out_x, 0, out_x, height());
}
// draw markers
for (int i=0;i<viewer->marker_ref->size();i++) {
const Marker& m = viewer->marker_ref->at(i);
// draw markers
for (int i=0;i<viewer->marker_ref->size();i++) {
const Marker& m = viewer->marker_ref->at(i);
int marker_x = getHeaderScreenPointFromFrame(m.frame);
int marker_x = getHeaderScreenPointFromFrame(m.frame);
bool selected = false;
for (int j=0;j<selected_markers.size();j++) {
if (selected_markers.at(j) == i) {
selected = true;
break;
}
}
bool selected = false;
for (int j=0;j<selected_markers.size();j++) {
if (selected_markers.at(j) == i) {
selected = true;
break;
}
}
draw_marker(p, marker_x, yoff, height()-1, selected);
}
draw_marker(p, marker_x, yoff, height()-1, selected);
}
// draw playhead triangle
p.setRenderHint(QPainter::Antialiasing);
in_x = getHeaderScreenPointFromFrame(viewer->seq->playhead);
QPoint start(in_x, height()+2);
QPainterPath path;
path.moveTo(start + QPoint(1,0));
path.lineTo(in_x-PLAYHEAD_SIZE, yoff);
path.lineTo(in_x+PLAYHEAD_SIZE+1, yoff);
path.lineTo(start);
p.fillPath(path, Qt::red);
}
// draw playhead triangle
p.setRenderHint(QPainter::Antialiasing);
in_x = getHeaderScreenPointFromFrame(viewer->seq->playhead);
QPoint start(in_x, height()+2);
QPainterPath path;
path.moveTo(start + QPoint(1,0));
path.lineTo(in_x-PLAYHEAD_SIZE, yoff);
path.lineTo(in_x+PLAYHEAD_SIZE+1, yoff);
path.lineTo(start);
p.fillPath(path, Qt::red);
}
}
void TimelineHeader::show_context_menu(const QPoint &pos) {
QMenu menu(this);
QMenu menu(this);
olive::MenuHelper.make_inout_menu(&menu);
// Add items for setting the in/out points of a QMenu
olive::MenuHelper.make_inout_menu(&menu);
menu.addSeparator();
menu.addSeparator();
QAction* center_timecodes = menu.addAction(tr("Center Timecodes"), olive::MainWindow, SLOT(toggle_bool_action()));
center_timecodes->setCheckable(true);
center_timecodes->setChecked(olive::CurrentConfig.center_timeline_timecodes);
center_timecodes->setData(reinterpret_cast<quintptr>(&olive::CurrentConfig.center_timeline_timecodes));
QAction* center_timecodes = menu.addAction(tr("Center Timecodes"), &olive::MenuHelper, SLOT(toggle_bool_action()));
center_timecodes->setCheckable(true);
center_timecodes->setChecked(olive::CurrentConfig.center_timeline_timecodes);
center_timecodes->setData(reinterpret_cast<quintptr>(&olive::CurrentConfig.center_timeline_timecodes));
menu.exec(mapToGlobal(pos));
menu.exec(mapToGlobal(pos));
}
void TimelineHeader::resized_scroll_listener(double d) {
update_zoom(zoom * d);
update_zoom(zoom * d);
}
+53 -58
View File
@@ -20,32 +20,6 @@
#include "timelinewidget.h"
#include "oliveglobal.h"
#include "panels/panels.h"
#include "project/projectelements.h"
#include "rendering/audio.h"
#include "io/config.h"
#include "ui/sourcetable.h"
#include "ui/sourceiconview.h"
#include "project/undo.h"
#include "ui/viewerwidget.h"
#include "ui/resizablescrollbar.h"
#include "dialogs/newsequencedialog.h"
#include "mainwindow.h"
#include "ui/rectangleselect.h"
#include "rendering/renderfunctions.h"
#include "ui/cursors.h"
#include "ui/menuhelper.h"
#include "ui/focusfilter.h"
#include "dialogs/clippropertiesdialog.h"
#include "debug.h"
#include "project/effect.h"
#include "effects/internal/solideffect.h"
#include "effects/internal/texteffect.h"
#include <QPainter>
#include <QColor>
#include <QMouseEvent>
@@ -61,6 +35,30 @@
#include <QInputDialog>
#include <QStatusBar>
#include "global/global.h"
#include "panels/panels.h"
#include "project/projectelements.h"
#include "rendering/audio.h"
#include "global/config.h"
#include "ui/sourcetable.h"
#include "ui/sourceiconview.h"
#include "undo/undo.h"
#include "undo/undostack.h"
#include "ui/viewerwidget.h"
#include "ui/resizablescrollbar.h"
#include "dialogs/newsequencedialog.h"
#include "mainwindow.h"
#include "ui/rectangleselect.h"
#include "rendering/renderfunctions.h"
#include "ui/cursors.h"
#include "ui/menuhelper.h"
#include "ui/focusfilter.h"
#include "dialogs/clippropertiesdialog.h"
#include "global/debug.h"
#include "effects/effect.h"
#include "effects/internal/solideffect.h"
#include "effects/internal/texteffect.h"
#define MAX_TEXT_WIDTH 20
#define TRANSITION_BETWEEN_RANGE 40
@@ -90,8 +88,6 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
QMenu menu(this);
// TODO replace with Olive::MenuHelper::make_edit_functions_menu() without losing functionality
QAction* undoAction = menu.addAction(tr("&Undo"));
QAction* redoAction = menu.addAction(tr("&Redo"));
connect(undoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(undo()));
@@ -103,13 +99,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
// collect all the selected clips
QVector<Clip*> selected_clips = olive::ActiveSequence->SelectedClips();
if (!selected_clips.isEmpty()) {
// clips are selected
menu.addAction(tr("C&ut"), &olive::FocusFilter, SLOT(cut()));
menu.addAction(tr("Cop&y"), &olive::FocusFilter, SLOT(copy()));
}
menu.addAction(tr("&Paste"), olive::Global.get(), SLOT(paste()));
olive::MenuHelper.make_edit_functions_menu(&menu, !selected_clips.isEmpty());
if (selected_clips.isEmpty()) {
// no clips are selected
@@ -119,7 +109,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
panel_timeline->cursor_track = getTrackFromScreenPoint(pos.y());
if (panel_timeline->can_ripple_empty_space(panel_timeline->cursor_frame, panel_timeline->cursor_track)) {
QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete"));
QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete Empty Space"));
connect(ripple_delete_action, SIGNAL(triggered(bool)), panel_timeline, SLOT(ripple_delete_empty_space()));
}
@@ -128,7 +118,9 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
}
if (!selected_clips.isEmpty()) {
menu.addSeparator();
menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog()));
QAction* autoscaleAction = menu.addAction(tr("Auto-s&cale"), this, SLOT(toggle_autoscale()));
@@ -259,8 +251,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
}
if (event->source() == panel_footage_viewer->viewer_widget) {
SequencePtr proposed_seq = panel_footage_viewer->seq;
if (proposed_seq != olive::ActiveSequence) { // don't allow nesting the same sequence
if (panel_footage_viewer->seq != olive::ActiveSequence) { // don't allow nesting the same sequence
media_list.append(panel_footage_viewer->media);
import_init = true;
}
@@ -278,9 +269,10 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
panel_project->process_file_list(file_list);
for (int i=0;i<panel_project->last_imported_media.size();i++) {
Footage* f = panel_project->last_imported_media.at(i)->to_footage();
// waits for media to have a duration
// TODO would be much nicer if this was multithreaded
FootagePtr f = panel_project->last_imported_media.at(i)->to_footage();
f->ready_lock.lock();
f->ready_lock.unlock();
@@ -302,14 +294,14 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
event->acceptProposedAction();
long entry_point;
SequencePtr seq = olive::ActiveSequence;
Sequence* seq = olive::ActiveSequence.get();
if (seq == nullptr) {
// if no sequence, we're going to create a new one using the clips as a reference
entry_point = 0;
self_created_sequence = create_sequence_from_media(media_list);
seq = self_created_sequence;
seq = self_created_sequence.get();
} else {
entry_point = panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x());
panel_timeline->drag_frame_start = entry_point + getFrameFromScreenPoint(panel_timeline->zoom, 50);
@@ -486,13 +478,13 @@ void insert_clips(ComboAction* ca) {
long ripple_length = (latest_new_point - earliest_new_point);
ripple_clips(ca, olive::ActiveSequence, earliest_new_point, ripple_length, ignore_clips);
ripple_clips(ca, olive::ActiveSequence.get(), earliest_new_point, ripple_length, ignore_clips);
if (ripple_old_point) {
// works for moving later clips earlier but not earlier to later
long second_ripple_length = (earliest_old_point - latest_old_point);
ripple_clips(ca, olive::ActiveSequence, latest_old_point, second_ripple_length, ignore_clips);
ripple_clips(ca, olive::ActiveSequence.get(), latest_old_point, second_ripple_length, ignore_clips);
if (earliest_old_point < earliest_new_point) {
for (int i=0;i<panel_timeline->ghosts.size();i++) {
@@ -515,11 +507,11 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
ComboAction* ca = new ComboAction();
SequencePtr s = olive::ActiveSequence;
Sequence* s = olive::ActiveSequence.get();
// if we're dropping into nothing, create a new sequences based on the clip being dragged
if (s == nullptr) {
s = self_created_sequence;
s = self_created_sequence.get();
panel_project->create_sequence_internal(ca, self_created_sequence, true, nullptr);
self_created_sequence = nullptr;
} else if (event->keyboardModifiers() & Qt::ControlModifier) {
@@ -664,7 +656,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
if (hovered_clip >= 0) {
Clip* clip = olive::ActiveSequence->clips.at(hovered_clip).get();
if (olive::ActiveSequence->IsClipSelected(clip, true)) {
if (clip->IsSelected()) {
if (shift) {
@@ -767,7 +759,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
Clip* link = olive::ActiveSequence->clips.at(clip->linked.at(i)).get();
// check if the clip is already selected
if (!olive::ActiveSequence->IsClipSelected(link, true)) {
if (!link->IsSelected()) {
Selection ss;
ss.in = link->timeline_in();
ss.out = link->timeline_out();
@@ -998,7 +990,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
panel_sequence_viewer->cue_recording(qMin(g.in, g.out), qMax(g.in, g.out), g.track);
panel_timeline->creating = false;
} else if (g.in != g.out) {
ClipPtr c = std::make_shared<Clip>(olive::ActiveSequence);
ClipPtr c = std::make_shared<Clip>(olive::ActiveSequence.get());
c->set_media(nullptr, 0);
c->set_timeline_in(qMin(g.in, g.out));
c->set_timeline_out(qMax(g.in, g.out));
@@ -1020,7 +1012,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
QVector<ClipPtr> add;
add.append(c);
ca->append(new AddClipCommand(olive::ActiveSequence, add));
ca->append(new AddClipCommand(olive::ActiveSequence.get(), add));
if (c->track() < 0 && olive::CurrentConfig.add_default_effects_to_clips) {
// default video effects (before custom effects)
@@ -1040,7 +1032,11 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
{
c->set_name(tr("Bars"));
EffectPtr e = Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT));
e->row(0)->field(0)->set_combo_index(1);
// Auto-select bars
SolidEffect* solid_effect = static_cast<SolidEffect*>(e.get());
solid_effect->SetType(SolidEffect::SOLID_TYPE_BARS);
c->effects.append(e);
}
break;
@@ -1137,7 +1133,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
if (panel_timeline->trim_type == TRIM_OUT) ripple_length = -ripple_length;
// finally, ripple everything
ripple_clips(ca, olive::ActiveSequence, ripple_point, ripple_length, ignore_clips);
ripple_clips(ca, olive::ActiveSequence.get(), ripple_point, ripple_length, ignore_clips);
}
if (panel_timeline->tool == TIMELINE_TOOL_POINTER
@@ -1153,7 +1149,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) {
// create copy of clip
ClipPtr c(olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence));
ClipPtr c = olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence.get());
c->set_timeline_in(g.in);
c->set_timeline_out(g.out);
@@ -1180,7 +1176,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
panel_timeline->relink_clips_using_ids(old_clips, new_clips);
// add them
ca->append(new AddClipCommand(olive::ActiveSequence, new_clips));
ca->append(new AddClipCommand(olive::ActiveSequence.get(), new_clips));
}
@@ -2004,7 +2000,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
panel_timeline->cursor_track = getTrackFromScreenPoint(event->pos().y());
// if holding the mouse button down, let's scroll to that location
if (event->buttons() != 0) {
if (event->buttons() != 0 && panel_timeline->tool != TIMELINE_TOOL_HAND) {
panel_timeline->scroll_to_frame(panel_timeline->cursor_frame);
}
@@ -2069,7 +2065,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
Clip* c = olive::ActiveSequence->clips.at(j).get();
if (c != nullptr && olive::ActiveSequence->IsClipSelected(c, false)) {
if (c != nullptr && c->IsSelected(false)) {
// loop through linked clips
for (int k=0;k<c->linked.size();k++) {
@@ -2199,7 +2195,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
// if a transition isn't selected, check if the whole clip is
if (!add) {
add = olive::ActiveSequence->IsClipSelected(c, true);
add = c->IsSelected();
}
if (add) {
@@ -2338,7 +2334,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
}
// store selections
selection_command = new SetSelectionsCommand(olive::ActiveSequence);
selection_command = new SetSelectionsCommand(olive::ActiveSequence.get());
selection_command->old_data = olive::ActiveSequence->selections;
// ready to start moving clips
@@ -2949,7 +2945,6 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
bool draw_checkerboard = false;
QRect checkerboard_rect(clip_rect);
FootagePtr m = clip->media()->to_footage();
FootageStream* ms = clip->media_stream();
if (ms == nullptr) {
draw_checkerboard = true;
+3 -3
View File
@@ -28,11 +28,11 @@
#include <QApplication>
#include <QDesktopWidget>
#include "project/sequence.h"
#include "project/clip.h"
#include "timeline/sequence.h"
#include "timeline/clip.h"
#include "project/footage.h"
#include "project/media.h"
#include "project/undo.h"
#include "undo/undo.h"
#include "timelinetools.h"
class Timeline;
+1 -1
View File
@@ -14,7 +14,7 @@ UpdateNotification::UpdateNotification()
void UpdateNotification::check()
{
#if defined(_WIN32) || defined(__APPLE__)
#if defined(GITHASH) && defined(UPDATEMSG)
QNetworkAccessManager* manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(finished_slot(QNetworkReply *)));
+50 -50
View File
@@ -28,67 +28,67 @@
#include "viewerwidget.h"
#include "panels/viewer.h"
#include "project/sequence.h"
#include "debug.h"
#include "timeline/sequence.h"
#include "global/debug.h"
// enforces aspect ratio
ViewerContainer::ViewerContainer(QWidget *parent) :
QWidget(parent),
fit(true),
child(nullptr)
QWidget(parent),
fit(true),
child(nullptr)
{
horizontal_scrollbar = new QScrollBar(Qt::Horizontal, this);
vertical_scrollbar = new QScrollBar(Qt::Vertical, this);
horizontal_scrollbar = new QScrollBar(Qt::Horizontal, this);
vertical_scrollbar = new QScrollBar(Qt::Vertical, this);
horizontal_scrollbar->setVisible(false);
vertical_scrollbar->setVisible(false);
horizontal_scrollbar->setVisible(false);
vertical_scrollbar->setVisible(false);
horizontal_scrollbar->setSingleStep(20);
vertical_scrollbar->setSingleStep(20);
horizontal_scrollbar->setSingleStep(20);
vertical_scrollbar->setSingleStep(20);
child = new ViewerWidget(this);
child->container = this;
child = new ViewerWidget(this);
child->container = this;
connect(horizontal_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed()));
connect(vertical_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed()));
connect(horizontal_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed()));
connect(vertical_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed()));
}
ViewerContainer::~ViewerContainer() {}
void ViewerContainer::dragScrollPress(const QPoint &p) {
drag_start_x = p.x();
drag_start_y = p.y();
drag_start_x = p.x();
drag_start_y = p.y();
horiz_start = horizontal_scrollbar->value();
vert_start = vertical_scrollbar->value();
horiz_start = horizontal_scrollbar->value();
vert_start = vertical_scrollbar->value();
}
void ViewerContainer::dragScrollMove(const QPoint &p) {
int this_x = p.x();
int this_y = p.y();
int this_x = p.x();
int this_y = p.y();
horizontal_scrollbar->setValue(horiz_start + (drag_start_x-this_x));
vertical_scrollbar->setValue(vert_start + (drag_start_y-this_y));
horizontal_scrollbar->setValue(horiz_start + (drag_start_x-this_x));
vertical_scrollbar->setValue(vert_start + (drag_start_y-this_y));
}
void ViewerContainer::parseWheelEvent(QWheelEvent *event) {
if (event->modifiers() & Qt::AltModifier) {
QApplication::sendEvent(horizontal_scrollbar, event);
} else {
QApplication::sendEvent(vertical_scrollbar, event);
}
if (event->modifiers() & Qt::AltModifier) {
QApplication::sendEvent(horizontal_scrollbar, event);
} else {
QApplication::sendEvent(vertical_scrollbar, event);
}
}
void ViewerContainer::adjust() {
if (viewer->seq != nullptr) {
if (child->waveform) {
child->move(0, 0);
child->resize(size());
} else {
horizontal_scrollbar->setVisible(false);
vertical_scrollbar->setVisible(false);
if (viewer->seq != nullptr) {
if (child->waveform) {
child->move(0, 0);
child->resize(size());
} else {
horizontal_scrollbar->setVisible(false);
vertical_scrollbar->setVisible(false);
int zoomed_width = qRound(double(viewer->seq->width)*zoom);
int zoomed_width = qRound(double(viewer->seq->width)*zoom);
int zoomed_height = qRound(double(viewer->seq->height)*zoom);
if (fit || zoomed_width > width() || zoomed_height > height()) {
@@ -147,28 +147,28 @@ void ViewerContainer::adjust() {
child->move(zoomed_x, zoomed_y);
child->resize(zoomed_width, zoomed_height);
}
}
}
}
}
}
void ViewerContainer::adjust_scrollbars() {
horizontal_scrollbar->move(0, height()-horizontal_scrollbar->height());
horizontal_scrollbar->setFixedWidth(qMax(0, width()-vertical_scrollbar->width()));
horizontal_scrollbar->setPageStep(width());
horizontal_scrollbar->move(0, height()-horizontal_scrollbar->height());
horizontal_scrollbar->setFixedWidth(qMax(0, width()-vertical_scrollbar->width()));
horizontal_scrollbar->setPageStep(width());
vertical_scrollbar->move(width() - vertical_scrollbar->width(), 0);
vertical_scrollbar->setFixedHeight(qMax(0, height()-horizontal_scrollbar->height()));
vertical_scrollbar->setPageStep(height());
vertical_scrollbar->move(width() - vertical_scrollbar->width(), 0);
vertical_scrollbar->setFixedHeight(qMax(0, height()-horizontal_scrollbar->height()));
vertical_scrollbar->setPageStep(height());
}
void ViewerContainer::resizeEvent(QResizeEvent *event) {
event->accept();
adjust();
event->accept();
adjust();
}
void ViewerContainer::scroll_changed() {
child->set_scroll(
double(horizontal_scrollbar->value())/double(horizontal_scrollbar->maximum()),
double(vertical_scrollbar->value())/double(vertical_scrollbar->maximum())
);
child->set_scroll(
double(horizontal_scrollbar->value())/double(horizontal_scrollbar->maximum()),
double(vertical_scrollbar->value())/double(vertical_scrollbar->maximum())
);
}
+10 -17
View File
@@ -46,11 +46,11 @@ extern "C" {
#include "project/projectelements.h"
#include "rendering/renderfunctions.h"
#include "rendering/audio.h"
#include "io/config.h"
#include "debug.h"
#include "io/math.h"
#include "global/config.h"
#include "global/debug.h"
#include "global/math.h"
#include "ui/collapsiblewidget.h"
#include "project/undo.h"
#include "undo/undo.h"
#include "project/media.h"
#include "ui/viewercontainer.h"
#include "rendering/cacher.h"
@@ -91,7 +91,7 @@ ViewerWidget::~ViewerWidget() {
}
void ViewerWidget::delete_function() {
close_active_clips(viewer->seq);
close_active_clips(viewer->seq.get());
}
void ViewerWidget::set_waveform_scroll(int s) {
@@ -168,7 +168,7 @@ void ViewerWidget::save_frame() {
fn += selected_ext;
}
renderer->start_render(context(), viewer->seq, fn);
renderer->start_render(context(), viewer->seq.get(), fn);
}
}
@@ -228,11 +228,11 @@ void ViewerWidget::frame_update() {
update();
} else {
doneCurrent();
renderer->start_render(context(), viewer->seq);
renderer->start_render(context(), viewer->seq.get());
}
// render the audio
compose_audio(viewer, viewer->seq, viewer->get_playback_speed(), viewer->WaitingForPlayWake());
compose_audio(viewer, viewer->seq.get(), viewer->get_playback_speed(), viewer->WaitingForPlayWake());
}
}
@@ -253,7 +253,7 @@ void ViewerWidget::seek_from_click(int x) {
void ViewerWidget::context_destroy() {
makeCurrent();
if (viewer->seq != nullptr) {
close_active_clips(viewer->seq);
close_active_clips(viewer->seq.get());
}
renderer->delete_ctx();
doneCurrent();
@@ -310,8 +310,6 @@ void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) {
drag_start_x = event->pos().x();
drag_start_y = event->pos().y();
gizmos->field_changed();
}
}
@@ -328,10 +326,6 @@ void ViewerWidget::mousePressEvent(QMouseEvent* event) {
gizmo_y_mvmt = 0;
selected_gizmo = get_gizmo_from_mouse(event->pos().x(), event->pos().y());
if (selected_gizmo != nullptr) {
selected_gizmo->set_previous_value();
}
}
dragging = true;
}
@@ -574,7 +568,6 @@ void ViewerWidget::paintGL() {
glBegin(GL_QUADS);
// double ar_diff = (double(viewer->seq->width)/double(viewer->seq->height)/(double(width())/double(height())));
double zoom_factor = container->zoom/(double(width())/double(viewer->seq->width));
double zoom_size = (zoom_factor*2.0) - 2.0;
double zoom_left = -zoom_size*x_scroll - 1.0;
@@ -619,7 +612,7 @@ void ViewerWidget::paintGL() {
if (renderer->did_texture_fail() && !viewer->playing) {
doneCurrent();
renderer->start_render(context(), viewer->seq);
renderer->start_render(context(), viewer->seq.get());
}
}
}
+2 -2
View File
@@ -30,9 +30,9 @@
#include <QWaitCondition>
#include <QOpenGLFunctions>
#include "project/clip.h"
#include "timeline/clip.h"
#include "project/footage.h"
#include "project/effect.h"
#include "effects/effect.h"
#include "ui/viewerwindow.h"
#include "ui/viewercontainer.h"
#include "rendering/renderthread.h"