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