Small adjudgement for SRT subtitles when background is enabled.
[openblackhole/openblackhole-enigma2.git] / lib / gui / esubtitle.cpp
1 #include <lib/gui/esubtitle.h>
2 #include <lib/gdi/grc.h>
3 #include <lib/gdi/font.h>
4 #include <lib/base/estring.h>
5 #include <lib/base/nconfig.h>
6 #include <lib/gui/ewidgetdesktop.h>
7
8 std::map<eSubtitleWidget::subfont_t, eSubtitleWidget::eSubtitleStyle> eSubtitleWidget::subtitleStyles;
9
10 eSubtitleWidget::eSubtitleWidget(eWidget *parent)
11         : eWidget(parent), m_hide_subtitles_timer(eTimer::create(eApp))
12 {
13         setBackgroundColor(gRGB(0,0,0,255));
14         m_page_ok = 0;
15         m_dvb_page_ok = 0;
16         m_pango_page_ok = 0;
17         CONNECT(m_hide_subtitles_timer->timeout, eSubtitleWidget::clearPage);
18 }
19
20 #define startX 50
21 void eSubtitleWidget::setPage(const eDVBTeletextSubtitlePage &p)
22 {
23         eDVBTeletextSubtitlePage newpage = p;
24         m_page = p;
25         m_page.clear();
26         m_page_ok = 1;
27         invalidate(m_visible_region); // invalidate old visible regions
28         m_visible_region.rects.clear();
29
30         unsigned int elements = newpage.m_elements.size();
31         if (elements)
32         {
33                 int width = size().width() - startX * 2;
34                 bool original_position = eConfigManager::getConfigBoolValue("config.subtitles.ttx_subtitle_original_position");
35                 bool rewrap = eConfigManager::getConfigBoolValue("config.subtitles.subtitle_rewrap");
36                 gRGB color;
37                 bool original_colors = false;
38                 switch (eConfigManager::getConfigIntValue("config.subtitles.ttx_subtitle_colors", 1))
39                 {
40                         case 0: /* use original teletext colors */
41                                 color = newpage.m_elements[0].m_color;
42                                 original_colors = true;
43                                 break;
44                         default:
45                         case 1: /* white */
46                                 color = gRGB(255, 255, 255);
47                                 break;
48                         case 2: /* yellow */
49                                 color = gRGB(255, 255, 0);
50                                 break;
51                 }
52
53                 if (!original_position)
54                 {
55                         int height = size().height() / 3;
56
57                         int lowerborder = eConfigManager::getConfigIntValue("config.subtitles.subtitle_position", 50);
58                         int line = newpage.m_elements[0].m_source_line;
59                         /* create a new page with just one text element */
60                         m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", 0));
61                         for (unsigned int i = 0; i < elements; ++i)
62                         {
63                                 if (!m_page.m_elements[0].m_text.empty()) m_page.m_elements[0].m_text += " ";
64                                 if (original_colors && color != newpage.m_elements[i].m_color)
65                                 {
66                                         color = newpage.m_elements[i].m_color;
67                                         m_page.m_elements[0].m_text += (std::string)color;
68                                 }
69                                 if (line != newpage.m_elements[i].m_source_line)
70                                 {
71                                         line = newpage.m_elements[i].m_source_line;
72                                         if (!rewrap) m_page.m_elements[0].m_text += "\\n";
73                                 }
74                                 m_page.m_elements[0].m_text += newpage.m_elements[i].m_text;
75                         }
76                         eRect &area = m_page.m_elements[0].m_area;
77                         area.setLeft((size().width() - width) / 2);
78                         area.setTop(size().height() - height - lowerborder);
79                         area.setWidth(width);
80                         area.setHeight(height);
81                         m_visible_region |= area;
82                 }
83                 else
84                 {
85                         int size_per_element = (size().height() - 25) / 24;
86                         int line = newpage.m_elements[0].m_source_line;
87                         int currentelement = 0;
88                         m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", line));
89                         for (unsigned int i = 0; i < elements; ++i)
90                         {
91                                 if (!m_page.m_elements[currentelement].m_text.empty()) m_page.m_elements[currentelement].m_text += " ";
92                                 if (original_colors && color != newpage.m_elements[i].m_color)
93                                 {
94                                         color = newpage.m_elements[i].m_color;
95                                         m_page.m_elements[currentelement].m_text += (std::string)color;
96                                 }
97                                 if (line != newpage.m_elements[i].m_source_line)
98                                 {
99                                         line = newpage.m_elements[i].m_source_line;
100                                         m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", line));
101                                         currentelement++;
102                                 }
103                                 m_page.m_elements[currentelement].m_text += newpage.m_elements[i].m_text;
104                         }
105                         for (unsigned int i = 0; i < m_page.m_elements.size(); i++)
106                         {
107                                 eRect &area = m_page.m_elements[i].m_area;
108                                 area.setLeft(startX);
109                                 area.setTop(size_per_element * m_page.m_elements[i].m_source_line);
110                                 area.setWidth(width);
111                                 area.setHeight(size_per_element * 2); //teletext subtitles are double height only even lines are used
112                                 m_visible_region |= area;
113                         }
114                 }
115         }
116         m_hide_subtitles_timer->start(7500, true);
117         invalidate(m_visible_region); // invalidate new regions
118 }
119
120 void eSubtitleWidget::setPage(const eDVBSubtitlePage &p)
121 {
122         eDebug("[eSubtitleWidget] setPage");
123         m_dvb_page = p;
124         invalidate(m_visible_region); // invalidate old visible regions
125         m_visible_region.rects.clear();
126         int line = 0;
127         int original_position = eConfigManager::getConfigIntValue("config.subtitles.dvb_subtitles_original_position");
128         for (std::list<eDVBSubtitleRegion>::iterator it(m_dvb_page.m_regions.begin()); it != m_dvb_page.m_regions.end(); ++it)
129         {
130                 if (original_position)
131                 {
132                         int lines = m_dvb_page.m_regions.size();
133                         int lowerborder = eConfigManager::getConfigIntValue("config.subtitles.subtitle_position", -1);
134                         if (lowerborder >= 0)
135                         {
136                                 if (original_position == 1)
137                                         it->m_position=ePoint(it->m_position.x(), p.m_display_size.height() - (lines - line) * it->m_pixmap->size().height() - lowerborder);
138                                 else
139                                         it->m_position=ePoint(it->m_position.x(), it->m_position.y() + 55 - lowerborder);
140                         }
141                         line++;
142                 }
143                 eDebug("[eSubtitleWidget] add %d %d %d %d", it->m_position.x(), it->m_position.y(), it->m_pixmap->size().width(), it->m_pixmap->size().height());
144                 eDebug("[eSubtitleWidget] disp width %d, disp height %d", p.m_display_size.width(), p.m_display_size.height());
145                 eRect r = eRect(it->m_position, it->m_pixmap->size());
146                 r.scale(size().width(), p.m_display_size.width(), size().height(), p.m_display_size.height());
147                 m_visible_region |= r;
148         }
149         m_dvb_page_ok = 1;
150         m_hide_subtitles_timer->start(7500, true);
151         invalidate(m_visible_region); // invalidate new regions
152 }
153
154 void eSubtitleWidget::setPage(const ePangoSubtitlePage &p)
155 {
156         int elements, element, startY, width, height, size_per_element;
157         int lowerborder;
158         bool rewrap_enabled;
159         bool colourise_dialogs_enabled;
160
161         m_pango_page = p;
162         m_pango_page_ok = 1;
163         invalidate(m_visible_region); // invalidate old visible regions
164         m_visible_region.rects.clear();
165
166         rewrap_enabled = eConfigManager::getConfigBoolValue("config.subtitles.subtitle_rewrap");
167         colourise_dialogs_enabled = eConfigManager::getConfigBoolValue("config.subtitles.colourise_dialogs");
168         lowerborder = eConfigManager::getConfigIntValue("config.subtitles.subtitle_position", 50);
169
170         elements = m_pango_page.m_elements.size();
171
172         if(rewrap_enabled | colourise_dialogs_enabled)
173         {
174                 size_t ix, colourise_dialogs_current = 0;
175                 std::vector<std::string> colourise_dialogs_colours;
176                 std::string replacement;
177                 bool alignment_center = eConfigManager::getConfigValue("config.subtitles.subtitle_alignment") == "center";
178
179                 if(colourise_dialogs_enabled)
180                 {
181                         colourise_dialogs_colours.push_back((std::string)gRGB(0xff, 0xff, 0x00));       // yellow
182                         colourise_dialogs_colours.push_back((std::string)gRGB(0x00, 0xff, 0xff));       // cyan
183                         colourise_dialogs_colours.push_back((std::string)gRGB(0xff, 0x00, 0xff));       // magenta
184                         colourise_dialogs_colours.push_back((std::string)gRGB(0x00, 0xff, 0x00));       // green
185                         colourise_dialogs_colours.push_back((std::string)gRGB(0xff, 0xaa, 0xaa));       // light red
186                         colourise_dialogs_colours.push_back((std::string)gRGB(0xaa, 0xaa, 0xff));       // light blue
187                 }
188
189                 for (element = 0; element < elements; element++)
190                 {
191                         std::string& line = m_pango_page.m_elements[element].m_pango_line;
192
193                         for (ix = 0; ix < line.length(); ix++)
194                         {
195                                 if(rewrap_enabled && !line.compare(ix, 1, "\n"))
196                                         line.replace(ix, 1, " ");
197
198                                 if(colourise_dialogs_enabled && !line.compare(ix, 2, "- "))
199                                 {
200                                         /* workaround for rendering fault when colouring is enabled, rewrap is off and alignment is center */
201                                         replacement = std::string((!rewrap_enabled && alignment_center) ? "  " : "") + colourise_dialogs_colours.at(colourise_dialogs_current);
202
203                                         line.replace(ix, 2, replacement);
204                                         colourise_dialogs_current++;
205
206                                         if(colourise_dialogs_current >= colourise_dialogs_colours.size())
207                                                 colourise_dialogs_current = 0;
208                                 }
209                         }
210                 }
211         }
212
213         if (elements > 1)
214                 startY = size().height() / 2;
215         else
216                 startY = size().height() / 3 * 2;
217
218         width = size().width() - startX * 2;
219         height = size().height() - startY;
220
221         if (elements != 0)
222                 size_per_element = height / elements;
223         else
224                 size_per_element = height;
225
226         for (element = 0; element < elements; element++)
227         {
228                 eRect& area = m_pango_page.m_elements[element].m_area;
229                 area.setLeft(startX);
230                 area.setTop(size_per_element * element + startY - lowerborder);
231                 area.setWidth(width);
232                 area.setHeight(size_per_element);
233                 m_visible_region |= area;
234         }
235
236         m_hide_subtitles_timer->start(m_pango_page.m_timeout, true);
237         invalidate(m_visible_region); // invalidate new regions
238 }
239
240 void eSubtitleWidget::clearPage()
241 {
242         m_page_ok = 0;
243         m_dvb_page_ok = 0;
244         m_pango_page_ok = 0;
245         invalidate(m_visible_region);
246         m_visible_region.rects.clear();
247 }
248
249 void eSubtitleWidget::setPixmap(ePtr<gPixmap> &pixmap, gRegion changed, eRect pixmap_dest)
250 {
251         m_pixmap = pixmap;
252         m_pixmap_dest = pixmap_dest; /* this is in a virtual 720x576 cage */
253
254                 /* incoming "changed" regions are relative to the physical pixmap area, so they have to be scaled to the virtual pixmap area, then to the screen */
255         changed.scale(m_pixmap_dest.width(), 720, m_pixmap_dest.height(), 576);
256         changed.moveBy(ePoint(m_pixmap_dest.x(), m_pixmap_dest.y()));
257
258         if (pixmap->size().width() && pixmap->size().height())
259                 changed.scale(size().width(), pixmap->size().width(), size().height(), pixmap->size().height());
260
261         invalidate(changed);
262 }
263
264 int eSubtitleWidget::event(int event, void *data, void *data2)
265 {
266         switch (event)
267         {
268         case evtPaint:
269         {
270                 ePtr<eWindowStyle> style;
271                 gPainter &painter = *(gPainter*)data2;
272
273                 getStyle(style);
274                 eWidget::event(event, data, data2);
275
276                 std::string alignmentValue;
277
278                 int rt_halignment_flag;
279                 alignmentValue = eConfigManager::getConfigValue("config.subtitles.subtitle_alignment");
280                 if (alignmentValue == "right")
281                         rt_halignment_flag = gPainter::RT_HALIGN_RIGHT;
282                 else if (alignmentValue == "left")
283                         rt_halignment_flag = gPainter::RT_HALIGN_LEFT;
284                 else
285                         rt_halignment_flag = gPainter::RT_HALIGN_CENTER;
286
287                 int borderwidth = eConfigManager::getConfigIntValue("config.subtitles.subtitle_borderwidth", 2) * getDesktop(0)->size().width()/1280;
288                 int fontsize = eConfigManager::getConfigIntValue("config.subtitles.subtitle_fontsize", 34) * getDesktop(0)->size().width()/1280;
289                 bool show_background = eConfigManager::getConfigBoolValue("config.subtitles.show_background");
290
291                 if (m_pixmap)
292                 {
293                         eRect r = m_pixmap_dest;
294                         r.scale(size().width(), 720, size().height(), 576);
295                         painter.blitScale(m_pixmap, r);
296                 }
297                 else if (m_page_ok)
298                 {
299                         unsigned int elements = m_page.m_elements.size();
300
301                         subtitleStyles[Subtitle_TTX].font->pointSize=fontsize;
302
303                         painter.setFont(subtitleStyles[Subtitle_TTX].font);
304                         for (unsigned int i = 0; i < elements; ++i)
305                         {
306                                 eDVBTeletextSubtitlePageElement &element = m_page.m_elements[i];
307                                 if (!element.m_text.empty())
308                                 {
309                                         eRect &area = element.m_area;
310                                         if (show_background)
311                                         {
312                                                 eTextPara *para = new eTextPara(area);
313                                                 para->setFont(subtitleStyles[Subtitle_TTX].font);
314                                                 para->renderString(element.m_text.c_str());
315                                                 eRect bbox = para->getBoundBox();
316                                                 int bboxWidth = bbox.width();
317                                                 if (alignmentValue == "right")
318                                                         bbox.setLeft(area.left() + area.width() - bboxWidth - borderwidth);
319                                                 else if (alignmentValue == "left")
320                                                         bbox.setLeft(area.left() - borderwidth);
321                                                 else
322                                                         bbox.setLeft(area.left() + area.width() / 2 - bboxWidth / 2 - borderwidth);
323                                                 bbox.setWidth(bboxWidth + borderwidth * 2);
324                                                 bbox.setHeight(area.height());
325                                                 painter.setForegroundColor(gRGB(0,0,0,64));
326                                                 painter.fill(bbox);
327                                                 borderwidth = 0;
328                                         }
329                                         if (!subtitleStyles[Subtitle_TTX].have_foreground_color)
330                                                 painter.setForegroundColor(element.m_color);
331                                         else
332                                                 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].foreground_color);
333                                         painter.renderText(area, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_BOTTOM|rt_halignment_flag, subtitleStyles[Subtitle_TTX].border_color, borderwidth);
334                                 }
335                         }
336                 }
337                 else if (m_pango_page_ok)
338                 {
339                         int elements = m_pango_page.m_elements.size();
340                         subfont_t face;
341
342                         for (int i=0; i<elements; ++i)
343                         {
344                                 face = Subtitle_Regular;
345                                 ePangoSubtitlePageElement &element = m_pango_page.m_elements[i];
346                                 std::string text = element.m_pango_line;
347                                 text = replace_all(text, "&apos;", "'");
348                                 text = replace_all(text, "&quot;", "\"");
349                                 text = replace_all(text, "&amp;", "&");
350                                 text = replace_all(text, "&lt", "<");
351                                 text = replace_all(text, "&gt", ">");
352
353                                 if (eConfigManager::getConfigBoolValue("config.subtitles.pango_subtitle_fontswitch"))
354                                 {
355                                         if (text.find("<i>") != std::string::npos || text.find("</i>") != std::string::npos)
356                                                 if (text.find("<b>") != std::string::npos || text.find("</b>") != std::string::npos)
357                                                         face = Subtitle_MAX;
358                                                 else
359                                                         face = Subtitle_Italic;
360                                         else if (text.find("<b>") != std::string::npos || text.find("</b>") != std::string::npos)
361                                                 face = Subtitle_Bold;
362                                 }
363                                 int subtitleColors = eConfigManager::getConfigIntValue("config.subtitles.pango_subtitle_colors", 1);
364                                 if (!subtitleColors)
365                                         {
366                                                 text = replace_all(text, "<i>", gRGB(255,255,0));
367                                                 text = replace_all(text, "<b>", gRGB(0,255,255));
368                                                 text = replace_all(text, "<u>", (std::string) gRGB(0,255,0));
369                                                 text = replace_all(text, "</i>", (std::string) gRGB(255,255,255));
370                                                 text = replace_all(text, "</b>", (std::string) gRGB(255,255,255));
371                                                 text = replace_all(text, "</u>", (std::string) gRGB(255,255,255));
372                                         }
373                                 else
374                                 {
375                                         if (subtitleColors == 2)
376                                                 text = (std::string) gRGB(255, 255, 0) + text;
377                                         text = replace_all(text, "</u>", "");
378                                         text = replace_all(text, "</i>", "");
379                                         text = replace_all(text, "</b>", "");
380                                         text = replace_all(text, "<u>", "");
381                                         text = replace_all(text, "<i>", "");
382                                         text = replace_all(text, "<b>", "");
383                                 }
384                                 subtitleStyles[face].font->pointSize=fontsize;
385                                 painter.setFont(subtitleStyles[face].font);
386                                 eRect &area = element.m_area;
387                                 if (show_background)
388                                 {
389                                         eTextPara *para = new eTextPara(area);
390                                         para->setFont(subtitleStyles[face].font);
391                                         para->renderString(text.c_str());
392                                         eRect bbox = para->getBoundBox();
393                                         int bboxWidth = bbox.width();
394                                         if (alignmentValue == "right")
395                                                 bbox.setLeft(area.left() + area.width() - bboxWidth - borderwidth);
396                                         else if (alignmentValue == "left")
397                                                 bbox.setLeft(area.left() - borderwidth);
398                                         else
399                                                 bbox.setLeft(area.left() + area.width() / 2 - bboxWidth / 2 - borderwidth);
400                                         bbox.setWidth(bboxWidth + borderwidth * 2);
401                                         int bboxTop = area.top() + area.height() - bbox.height() - borderwidth;
402                                         int bboxHeight = bbox.height() + borderwidth * 2;
403                                         bbox.setTop(bboxTop);
404                                         bbox.setHeight(bboxHeight);
405                                         area.setTop(area.top() - borderwidth);
406                                         painter.setForegroundColor(gRGB(0,0,0,64));
407                                         painter.fill(bbox);
408                                         borderwidth = 0;
409                                 }
410                                 if ( !subtitleStyles[face].have_foreground_color && element.m_have_color )
411                                         painter.setForegroundColor(element.m_color);
412                                 else
413                                         painter.setForegroundColor(subtitleStyles[face].foreground_color);
414                                 painter.renderText(area, text, gPainter::RT_WRAP|gPainter::RT_VALIGN_BOTTOM|rt_halignment_flag, subtitleStyles[face].border_color, borderwidth);
415                         }
416                 }
417                 else if (m_dvb_page_ok)
418                 {
419                         for (std::list<eDVBSubtitleRegion>::iterator it(m_dvb_page.m_regions.begin()); it != m_dvb_page.m_regions.end(); ++it)
420                         {
421                                 eRect r = eRect(it->m_position, it->m_pixmap->size());
422                                 r.scale(size().width(), m_dvb_page.m_display_size.width(), size().height(), m_dvb_page.m_display_size.height());
423                                 painter.blitScale(it->m_pixmap, r);
424                         }
425                 }
426                 return 0;
427         }
428         default:
429                 return eWidget::event(event, data, data2);
430         }
431 }
432
433 void eSubtitleWidget::setFontStyle(subfont_t face, gFont *font, int haveColor, const gRGB &col, const gRGB &borderCol, int borderWidth)
434 {
435         subtitleStyles[face].font = font;
436         subtitleStyles[face].have_foreground_color = haveColor;
437         subtitleStyles[face].foreground_color = col;
438         subtitleStyles[face].border_color = borderCol;
439         subtitleStyles[face].border_width = borderWidth;
440 }