added shadow to rich text effect and removed old effect residue
This commit is contained in:
@@ -373,6 +373,9 @@ void Effect::copy_field_keyframes(EffectPtr e) {
|
||||
|
||||
// Copy keyframes between effects
|
||||
copy_field->keyframes = field->keyframes;
|
||||
|
||||
// Copy persistet data between effects
|
||||
copy_field->persistent_data_ = field->persistent_data_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "richtexteffect.h"
|
||||
|
||||
#include <QTextDocument>
|
||||
#include <QtMath>
|
||||
|
||||
#include "timeline/clip.h"
|
||||
#include "ui/blur.h"
|
||||
|
||||
enum AutoscrollDirection {
|
||||
SCROLL_OFF,
|
||||
@@ -46,6 +48,34 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) :
|
||||
autoscroll->AddItem(tr("Right"), SCROLL_RIGHT);
|
||||
autoscroll->SetColumnSpan(2);
|
||||
|
||||
EffectRow* shadow_row = new EffectRow(this, tr("Shadow"));
|
||||
shadow_bool = new BoolField(shadow_row, "shadow");
|
||||
shadow_bool->SetColumnSpan(2);
|
||||
|
||||
EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color"));
|
||||
shadow_color = new ColorField(shadow_color_row, "shadowcolor");
|
||||
shadow_color->SetColumnSpan(2);
|
||||
|
||||
EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle"));
|
||||
shadow_angle = new DoubleField(shadow_angle_row, "shadowangle");
|
||||
shadow_angle->SetColumnSpan(2);
|
||||
|
||||
EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance"));
|
||||
shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance");
|
||||
shadow_distance->SetColumnSpan(2);
|
||||
shadow_distance->SetMinimum(0);
|
||||
|
||||
EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness"));
|
||||
shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness");
|
||||
shadow_softness->SetColumnSpan(2);
|
||||
shadow_softness->SetMinimum(0);
|
||||
|
||||
EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity"));
|
||||
shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity");
|
||||
shadow_opacity->SetColumnSpan(2);
|
||||
shadow_opacity->SetMinimum(0);
|
||||
shadow_opacity->SetMaximum(100);
|
||||
|
||||
// Create default text
|
||||
text_val->SetValueAt(0, "<html>"
|
||||
"<body style=\"color: #ffffff; font-size: 36pt;\">"
|
||||
@@ -61,8 +91,6 @@ void RichTextEffect::redraw(double timecode)
|
||||
int width = img.width();
|
||||
int height = img.height();
|
||||
|
||||
img.fill(Qt::transparent);
|
||||
|
||||
int padding = qRound(padding_field->GetDoubleAt(timecode));
|
||||
|
||||
width -= 2 * padding;
|
||||
@@ -79,7 +107,7 @@ void RichTextEffect::redraw(double timecode)
|
||||
|
||||
AutoscrollDirection auto_scroll_dir = static_cast<AutoscrollDirection>(autoscroll->GetValueAt(timecode).toInt());
|
||||
|
||||
double scroll_progress;
|
||||
double scroll_progress = 0;
|
||||
|
||||
if (auto_scroll_dir != SCROLL_OFF) {
|
||||
double clip_length_secs = double(parent_clip->length()) / parent_clip->media_frame_rate();
|
||||
@@ -102,7 +130,7 @@ void RichTextEffect::redraw(double timecode)
|
||||
scroll_progress = 1.0 - scroll_progress;
|
||||
}
|
||||
|
||||
int doc_width = td.size().width();
|
||||
int doc_width = qRound(td.size().width());
|
||||
translate_x += qRound(-doc_width + (img.width() + doc_width) * scroll_progress);
|
||||
}
|
||||
|
||||
@@ -114,7 +142,7 @@ void RichTextEffect::redraw(double timecode)
|
||||
scroll_progress = 1.0 - scroll_progress;
|
||||
}
|
||||
|
||||
translate_y += qRound(-doc_height + (height + doc_height)*scroll_progress);
|
||||
translate_y += qRound(-doc_height + (img.height() + doc_height)*scroll_progress);
|
||||
|
||||
}
|
||||
|
||||
@@ -122,8 +150,43 @@ void RichTextEffect::redraw(double timecode)
|
||||
clip_rect.translate(-translate_x, -translate_y);
|
||||
p.translate(translate_x, translate_y);
|
||||
|
||||
img.fill(Qt::transparent);
|
||||
|
||||
// draw software shadow
|
||||
if (shadow_bool->GetBoolAt(timecode)) {
|
||||
|
||||
// calculate offset using distance and angle
|
||||
double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0;
|
||||
double distance = qFloor(shadow_distance->GetDoubleAt(timecode));
|
||||
int shadow_x_offset = qRound(qCos(angle) * distance);
|
||||
int shadow_y_offset = qRound(qSin(angle) * distance);
|
||||
|
||||
p.translate(shadow_x_offset, shadow_y_offset);
|
||||
clip_rect.translate(-shadow_x_offset, -shadow_y_offset);
|
||||
|
||||
td.drawContents(&p, clip_rect);
|
||||
|
||||
int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode));
|
||||
if (blurSoftness > 0) {
|
||||
olive::ui::blur(img, img.rect(), blurSoftness, true);
|
||||
}
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
|
||||
p.fillRect(img.rect(), shadow_color->GetColorAt(timecode));
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
|
||||
p.translate(-shadow_x_offset, -shadow_y_offset);
|
||||
clip_rect.translate(shadow_x_offset, shadow_y_offset);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
td.drawContents(&p, clip_rect);
|
||||
|
||||
p.end();
|
||||
}
|
||||
|
||||
bool RichTextEffect::AlwaysUpdate()
|
||||
|
||||
@@ -17,6 +17,13 @@ private:
|
||||
DoubleField* position_y;
|
||||
ComboField* vertical_align;
|
||||
ComboField* autoscroll;
|
||||
|
||||
BoolField* shadow_bool;
|
||||
DoubleField* shadow_angle;
|
||||
DoubleField* shadow_distance;
|
||||
ColorField* shadow_color;
|
||||
DoubleField* shadow_softness;
|
||||
DoubleField* shadow_opacity;
|
||||
};
|
||||
|
||||
#endif // RICHTEXTEFFECT_H
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "ui/comboboxex.h"
|
||||
#include "ui/colorbutton.h"
|
||||
#include "ui/fontcombobox.h"
|
||||
#include "ui/blur.h"
|
||||
#include "global/config.h"
|
||||
|
||||
TextEffect::TextEffect(Clip* c, const EffectMeta* em) :
|
||||
@@ -154,70 +155,6 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) :
|
||||
fragPath = "dropshadow.frag";
|
||||
}
|
||||
|
||||
void blurred2(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;
|
||||
}
|
||||
}
|
||||
|
||||
void TextEffect::redraw(double timecode) {
|
||||
QColor bkg = set_color_button->GetColorAt(timecode);
|
||||
bkg.setAlpha(0);
|
||||
@@ -340,7 +277,7 @@ void TextEffect::redraw(double timecode) {
|
||||
p.drawPath(shadow_path);
|
||||
|
||||
int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode));
|
||||
if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, true);
|
||||
if (blurSoftness > 0) olive::ui::blur(img, img.rect(), blurSoftness, true);
|
||||
}
|
||||
|
||||
// draw outline
|
||||
|
||||
@@ -173,7 +173,8 @@ SOURCES += \
|
||||
effects/transition.cpp \
|
||||
ui/styling.cpp \
|
||||
undo/undostack.cpp \
|
||||
effects/internal/richtexteffect.cpp
|
||||
effects/internal/richtexteffect.cpp \
|
||||
ui/blur.cpp
|
||||
|
||||
HEADERS += \
|
||||
ui/mainwindow.h \
|
||||
@@ -300,7 +301,8 @@ HEADERS += \
|
||||
effects/transition.h \
|
||||
ui/styling.h \
|
||||
undo/undostack.h \
|
||||
effects/internal/richtexteffect.h
|
||||
effects/internal/richtexteffect.h \
|
||||
ui/blur.h
|
||||
|
||||
FORMS +=
|
||||
|
||||
|
||||
+65
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef BLUR_H
|
||||
#define BLUR_H
|
||||
|
||||
#include <QImage>
|
||||
#include <QRect>
|
||||
|
||||
namespace olive {
|
||||
namespace ui {
|
||||
void blur(QImage& result, const QRect& rect, int radius, bool alphaOnly);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BLUR_H
|
||||
@@ -33,15 +33,10 @@ QColor ColorButton::get_color() {
|
||||
}
|
||||
|
||||
void ColorButton::set_color(QColor c) {
|
||||
previousColor = color;
|
||||
color = c;
|
||||
set_button_color();
|
||||
}
|
||||
|
||||
const QColor &ColorButton::getPreviousValue() {
|
||||
return previousColor;
|
||||
}
|
||||
|
||||
void ColorButton::set_button_color() {
|
||||
QPalette pal = palette();
|
||||
pal.setColor(QPalette::Button, color);
|
||||
|
||||
@@ -31,10 +31,8 @@ public:
|
||||
ColorButton(QWidget* parent = nullptr);
|
||||
QColor get_color();
|
||||
void set_color(QColor c);
|
||||
const QColor& getPreviousValue();
|
||||
private:
|
||||
QColor color;
|
||||
QColor previousColor;
|
||||
void set_button_color();
|
||||
signals:
|
||||
void color_changed(const QColor& c);
|
||||
|
||||
@@ -42,12 +42,7 @@ const QString &EmbeddedFileChooser::getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
const QString &EmbeddedFileChooser::getPreviousValue() {
|
||||
return old_filename;
|
||||
}
|
||||
|
||||
void EmbeddedFileChooser::setFilename(const QString &s) {
|
||||
old_filename = filename;
|
||||
filename = s;
|
||||
update_label();
|
||||
emit changed(filename);
|
||||
|
||||
@@ -31,14 +31,12 @@ public:
|
||||
EmbeddedFileChooser(QWidget* parent = 0);
|
||||
|
||||
const QString& getFilename();
|
||||
const QString& getPreviousValue();
|
||||
void setFilename(const QString& s);
|
||||
signals:
|
||||
void changed(const QString& s);
|
||||
private:
|
||||
QLabel* file_label;
|
||||
QString filename;
|
||||
QString old_filename;
|
||||
void update_label();
|
||||
private slots:
|
||||
void browse();
|
||||
|
||||
@@ -30,11 +30,6 @@ FontCombobox::FontCombobox(QWidget* parent) : QComboBox(parent) {
|
||||
connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(updateInternals()));
|
||||
}
|
||||
|
||||
const QString& FontCombobox::getPreviousValue() {
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
void FontCombobox::updateInternals() {
|
||||
previousValue = value;
|
||||
value = currentText();
|
||||
}
|
||||
|
||||
+1
-3
@@ -26,12 +26,10 @@
|
||||
class FontCombobox : public QComboBox {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FontCombobox(QWidget* parent = 0);
|
||||
const QString &getPreviousValue();
|
||||
FontCombobox(QWidget* parent = nullptr);
|
||||
private slots:
|
||||
void updateInternals();
|
||||
private:
|
||||
QString previousValue;
|
||||
QString value;
|
||||
};
|
||||
|
||||
|
||||
@@ -245,8 +245,6 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
|
||||
|
||||
drag_proc = false;
|
||||
|
||||
previous_value = drag_start_value;
|
||||
|
||||
emit valueChanged(internal_value);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -160,7 +160,6 @@ private:
|
||||
double default_value;
|
||||
double internal_value;
|
||||
double drag_start_value;
|
||||
double previous_value;
|
||||
|
||||
int decimal_places;
|
||||
|
||||
|
||||
@@ -21,48 +21,6 @@
|
||||
#include "texteditex.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
/*
|
||||
TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) {
|
||||
setUndoRedoEnabled(false);
|
||||
connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals()));
|
||||
connect(this, SIGNAL(updateSelf()), this, SLOT(updateText()));
|
||||
}
|
||||
|
||||
const QString& TextEditEx::getPlainTextEx() {
|
||||
return text;
|
||||
}
|
||||
|
||||
void TextEditEx::setPlainTextEx(const QString &t) {
|
||||
previousText = text;
|
||||
text = t;
|
||||
emit updateSelf();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
*/
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
#include "dialogs/texteditdialog.h"
|
||||
|
||||
Reference in New Issue
Block a user