1 #include "richtexteffect.h"
2
3 #include <QTextDocument>
4 #include <QtMath>
5
6 #include "timeline/clip.h"
7 #include "ui/blur.h"
8
9 enum AutoscrollDirection {
10 SCROLL_OFF,
11 SCROLL_UP,
12 SCROLL_DOWN,
13 SCROLL_LEFT,
14 SCROLL_RIGHT,
15 };
16
RichTextEffect(Clip * c,const EffectMeta * em)17 RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) :
18 Effect(c, em)
19 {
20 SetFlags(Effect::SuperimposeFlag);
21
22 EffectRow* text_row = new EffectRow(this, tr("Text"));
23 text_val = new StringField(text_row, "text");
24 text_val->SetColumnSpan(2);
25
26 EffectRow* padding_row = new EffectRow(this, tr("Padding"));
27 padding_field = new DoubleField(padding_row, "padding");
28 padding_field->SetColumnSpan(2);
29
30 EffectRow* position_row = new EffectRow(this, tr("Position"));
31 position_x = new DoubleField(position_row, "posx");
32 position_y = new DoubleField(position_row, "posy");
33
34 EffectRow* vertical_align_row = new EffectRow(this, tr("Vertical Align:"));
35 vertical_align = new ComboField(vertical_align_row, "valign");
36 vertical_align->AddItem(tr("Top"), Qt::AlignTop);
37 vertical_align->AddItem(tr("Center"), Qt::AlignCenter);
38 vertical_align->AddItem(tr("Bottom"), Qt::AlignBottom);
39 vertical_align->SetValueAt(0, Qt::AlignCenter);
40 vertical_align->SetColumnSpan(2);
41
42 EffectRow* autoscroll_row = new EffectRow(this, tr("Auto-Scroll"));
43 autoscroll = new ComboField(autoscroll_row, "autoscroll");
44 autoscroll->AddItem(tr("Off"), SCROLL_OFF);
45 autoscroll->AddItem(tr("Up"), SCROLL_UP);
46 autoscroll->AddItem(tr("Down"), SCROLL_DOWN);
47 autoscroll->AddItem(tr("Left"), SCROLL_LEFT);
48 autoscroll->AddItem(tr("Right"), SCROLL_RIGHT);
49 autoscroll->SetColumnSpan(2);
50
51 EffectRow* shadow_row = new EffectRow(this, tr("Shadow"));
52 shadow_bool = new BoolField(shadow_row, "shadow");
53 shadow_bool->SetColumnSpan(2);
54
55 EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color"));
56 shadow_color = new ColorField(shadow_color_row, "shadowcolor");
57 shadow_color->SetColumnSpan(2);
58
59 EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle"));
60 shadow_angle = new DoubleField(shadow_angle_row, "shadowangle");
61 shadow_angle->SetColumnSpan(2);
62
63 EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance"));
64 shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance");
65 shadow_distance->SetColumnSpan(2);
66 shadow_distance->SetMinimum(0);
67
68 EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness"));
69 shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness");
70 shadow_softness->SetColumnSpan(2);
71 shadow_softness->SetMinimum(0);
72
73 EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity"));
74 shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity");
75 shadow_opacity->SetColumnSpan(2);
76 shadow_opacity->SetMinimum(0);
77 shadow_opacity->SetMaximum(100);
78
79 // Create default text
80 text_val->SetValueAt(0, "<html>"
81 "<body style=\"color: #ffffff; font-size: 36pt;\">"
82 "<center>Sample Text</center>"
83 "</body>"
84 "</html>");
85 }
86
redraw(double timecode)87 void RichTextEffect::redraw(double timecode)
88 {
89 QPainter p(&img);
90 p.setRenderHint(QPainter::Antialiasing);
91 int width = img.width();
92 int height = img.height();
93
94 int padding = qRound(padding_field->GetDoubleAt(timecode));
95
96 width -= 2 * padding;
97 height -= 2 * padding;
98
99 QTextDocument td;
100 td.setHtml(text_val->GetStringAt(timecode));
101 td.setTextWidth(width);
102
103 int translate_x = qRound(position_x->GetDoubleAt(timecode) + padding);
104 int translate_y = qRound(position_y->GetDoubleAt(timecode) + padding);
105
106 int doc_height = qRound(td.size().height());
107
108 AutoscrollDirection auto_scroll_dir = static_cast<AutoscrollDirection>(autoscroll->GetValueAt(timecode).toInt());
109
110 double scroll_progress = 0;
111
112 if (auto_scroll_dir != SCROLL_OFF) {
113 double clip_length_secs = double(parent_clip->length()) / parent_clip->media_frame_rate();
114 scroll_progress = (timecode - double(parent_clip->clip_in()) / parent_clip->media_frame_rate()) / clip_length_secs;
115 }
116
117 if (auto_scroll_dir == SCROLL_OFF || auto_scroll_dir == SCROLL_LEFT || auto_scroll_dir == SCROLL_RIGHT) {
118
119 // If we're not auto-scrolling the vertical direction, respect the vertical alignment
120 if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) {
121 translate_y += height / 2 - doc_height / 2;
122 } else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) {
123 translate_y += height - doc_height;
124 }
125
126 // Check if we are autoscrolling
127 if (auto_scroll_dir != SCROLL_OFF) {
128
129 if (auto_scroll_dir == SCROLL_LEFT) {
130 scroll_progress = 1.0 - scroll_progress;
131 }
132
133 int doc_width = qRound(td.size().width());
134 translate_x += qRound(-doc_width + (img.width() + doc_width) * scroll_progress);
135 }
136
137 } else if (auto_scroll_dir == SCROLL_UP || auto_scroll_dir == SCROLL_DOWN) {
138
139 // Auto-scroll bottom to top or top to bottom
140
141 if (auto_scroll_dir == SCROLL_UP) {
142 scroll_progress = 1.0 - scroll_progress;
143 }
144
145 translate_y += qRound(-doc_height + (img.height() + doc_height)*scroll_progress);
146
147 }
148
149 QRect clip_rect = img.rect();
150 clip_rect.translate(-translate_x, -translate_y);
151 p.translate(translate_x, translate_y);
152
153 img.fill(Qt::transparent);
154
155 // draw software shadow
156 if (shadow_bool->GetBoolAt(timecode)) {
157
158 // calculate offset using distance and angle
159 double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0;
160 double distance = qFloor(shadow_distance->GetDoubleAt(timecode));
161 int shadow_x_offset = qRound(qCos(angle) * distance);
162 int shadow_y_offset = qRound(qSin(angle) * distance);
163
164 p.translate(shadow_x_offset, shadow_y_offset);
165 clip_rect.translate(-shadow_x_offset, -shadow_y_offset);
166
167 td.drawContents(&p, clip_rect);
168
169 int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode));
170 if (blurSoftness > 0) {
171 olive::ui::blur(img, img.rect(), blurSoftness, true);
172 }
173
174 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
175
176 p.fillRect(clip_rect, shadow_color->GetColorAt(timecode));
177
178 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
179
180 p.translate(-shadow_x_offset, -shadow_y_offset);
181 clip_rect.translate(shadow_x_offset, shadow_y_offset);
182 }
183
184 td.drawContents(&p, clip_rect);
185
186 p.end();
187 }
188
AlwaysUpdate()189 bool RichTextEffect::AlwaysUpdate()
190 {
191 return autoscroll->GetValueAt(autoscroll->Now()).toInt() != SCROLL_OFF;
192 }
193