1 #include <lib/gui/esubtitle.h>
2 #include <lib/gui/ewidgetdesktop.h>
3 #include <lib/gdi/grc.h>
4 #include <lib/gdi/font.h>
5 #include <lib/base/estring.h>
6 #include <lib/base/nconfig.h>
9 ok, here's much room for improvements.
11 first, the placing of the individual elements is sub-optimal.
12 then maybe a colored background would be an option.
16 eSubtitleWidget::eSubtitleStyle eSubtitleWidget::subtitleStyles[Subtitle_MAX];
18 eSubtitleWidget::eSubtitleWidget(eWidget *parent)
19 : eWidget(parent), m_hide_subtitles_timer(eTimer::create(eApp))
21 setBackgroundColor(gRGB(0,0,0,255));
25 CONNECT(m_hide_subtitles_timer->timeout, eSubtitleWidget::clearPage);
29 void eSubtitleWidget::setPage(const eDVBTeletextSubtitlePage &p)
31 eDVBTeletextSubtitlePage newpage = p;
35 invalidate(m_visible_region); // invalidate old visible regions
36 m_visible_region.rects.clear();
38 unsigned int elements = newpage.m_elements.size();
41 int startY = elements > 1
43 : size().height() / 3 * 2;
44 int width = size().width() - startX * 2;
45 int height = size().height() - startY;
46 int size_per_element = height / (elements ? elements : 1);
47 bool original_position = ePythonConfigQuery::getConfigBoolValue("config.subtitles.subtitle_original_position");
49 bool original_colors = false;
50 switch (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_fontcolor", 0))
53 case 0: /* use original teletext colors */
54 color = newpage.m_elements[0].m_color;
55 original_colors = true;
58 color = gRGB(255, 255, 255);
60 case FONTCOLOR_YELLOW:
61 color = gRGB(255, 255, 0);
64 color = gRGB(0, 255, 0);
67 color = gRGB(0, 255, 255);
70 color = gRGB(0, 0, 255);
72 case FONTCOLOR_MAGNETA:
73 color = gRGB(255, 0, 255);
76 color = gRGB(255, 0, 0);
79 color = gRGB(0, 0, 0);
82 color.a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_opacity");
84 int line = newpage.m_elements[0].m_source_line;
85 int currentelement = 0;
86 m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", line));
87 for (int i=0; i<elements; ++i)
89 if (!m_page.m_elements[currentelement].m_text.empty())
90 m_page.m_elements[currentelement].m_text += " ";
91 if (original_colors && color != newpage.m_elements[i].m_color)
93 color = newpage.m_elements[i].m_color;
94 m_page.m_elements[currentelement].m_text += (std::string)color;
96 if (line != newpage.m_elements[i].m_source_line)
98 line = newpage.m_elements[i].m_source_line;
99 m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", line));
102 m_page.m_elements[currentelement].m_text += newpage.m_elements[i].m_text;
104 for (int i=0; i<m_page.m_elements.size(); i++)
106 eRect &area = m_page.m_elements[i].m_area;
107 area.setLeft(startX);
108 if (!original_position)
110 int lowerborder = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_position", 50);
111 if (lowerborder == 0)
112 lowerborder -= 100 * getDesktop(0)->size().height()/720;
113 else if (lowerborder == 50)
114 lowerborder -= 50 * getDesktop(0)->size().height()/720;
115 area.setTop(size_per_element * i + startY - lowerborder);
118 area.setTop(size_per_element * i + startY);
119 area.setWidth(width);
120 area.setHeight(size_per_element);
121 m_visible_region.rects.push_back(area);
124 m_hide_subtitles_timer->start(7500, true);
125 invalidate(m_visible_region); // invalidate new regions
128 void eSubtitleWidget::setPage(const eDVBSubtitlePage &p)
132 invalidate(m_visible_region); // invalidate old visible regions
133 m_visible_region.rects.clear();
135 bool original_position = ePythonConfigQuery::getConfigBoolValue("config.subtitles.subtitle_original_position");
136 for (std::list<eDVBSubtitleRegion>::iterator it(m_dvb_page.m_regions.begin()); it != m_dvb_page.m_regions.end(); ++it)
138 if (!original_position)
140 int lines = m_dvb_page.m_regions.size();
141 int lowerborder = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_position", -1);
142 if (lowerborder >= 0)
144 it->m_position = ePoint(it->m_position.x(), p.m_display_size.height() - (lines - line) * it->m_pixmap->size().height() - lowerborder);
148 eDebug("add %d %d %d %d", it->m_position.x(), it->m_position.y(), it->m_pixmap->size().width(), it->m_pixmap->size().height());
149 eDebug("disp width %d, disp height %d", p.m_display_size.width(), p.m_display_size.height());
150 eRect r = eRect(it->m_position, it->m_pixmap->size());
151 r.scale(size().width(), p.m_display_size.width(), size().height(), p.m_display_size.height());
152 m_visible_region.rects.push_back(r);
155 m_hide_subtitles_timer->start(7500, true);
156 invalidate(m_visible_region); // invalidate new regions
159 void eSubtitleWidget::setPage(const ePangoSubtitlePage &p)
163 invalidate(m_visible_region); // invalidate old visible regions
164 m_visible_region.rects.clear();
166 bool rewrap_enabled = ePythonConfigQuery::getConfigBoolValue("config.subtitles.subtitle_rewrap");
167 bool colourise_dialogs_enabled = ePythonConfigQuery::getConfigBoolValue("config.subtitles.colourise_dialogs");
168 bool original_position = ePythonConfigQuery::getConfigBoolValue("config.subtitles.subtitle_original_position");
170 int elements = m_pango_page.m_elements.size();
172 if(rewrap_enabled | colourise_dialogs_enabled)
174 size_t ix, colourise_dialogs_current = 0;
175 std::vector<std::string> colourise_dialogs_colours;
176 std::string replacement;
177 std::string alignmentValue;
178 ePythonConfigQuery::getConfigValue("config.subtitles.subtitle_alignment", alignmentValue);
179 bool alignment_center = (alignmentValue == "center");
181 if(colourise_dialogs_enabled)
183 colourise_dialogs_colours.push_back((std::string)gRGB(0xff, 0xff, 0x00)); // yellow
184 colourise_dialogs_colours.push_back((std::string)gRGB(0x00, 0xff, 0xff)); // cyan
185 colourise_dialogs_colours.push_back((std::string)gRGB(0xff, 0x00, 0xff)); // magenta
186 colourise_dialogs_colours.push_back((std::string)gRGB(0x00, 0xff, 0x00)); // green
187 colourise_dialogs_colours.push_back((std::string)gRGB(0xff, 0xaa, 0xaa)); // light red
188 colourise_dialogs_colours.push_back((std::string)gRGB(0xaa, 0xaa, 0xff)); // light blue
191 for (int i=0; i<elements; ++i)
193 std::string& line = m_pango_page.m_elements[i].m_pango_line;
195 for (ix = 0; ix < line.length(); ix++)
197 if(rewrap_enabled && !line.compare(ix, 1, "\n"))
198 line.replace(ix, 1, " ");
200 if(colourise_dialogs_enabled && !line.compare(ix, 2, "- "))
202 /* workaround for rendering fault when colouring is enabled, rewrap is off and alignment is center */
203 replacement = std::string((!rewrap_enabled && alignment_center) ? " " : "") + colourise_dialogs_colours.at(colourise_dialogs_current);
205 line.replace(ix, 2, replacement);
206 colourise_dialogs_current++;
208 if(colourise_dialogs_current >= colourise_dialogs_colours.size())
209 colourise_dialogs_current = 0;
217 int startY = elements > 1
218 ? size().height() / 2
219 : size().height() / 3 * 2;
220 int width = size().width() - startX * 2;
221 int height = size().height() - startY;
222 int size_per_element = height / (elements ? elements : 1);
223 for (int i=0; i<elements; ++i)
225 eRect &area = m_pango_page.m_elements[i].m_area;
226 area.setLeft(startX);
227 if (!original_position)
229 int lowerborder = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_position", 50);
230 if (lowerborder == 0)
231 lowerborder -= 100 * getDesktop(0)->size().height()/720;
232 else if (lowerborder == 50)
233 lowerborder -= 50 * getDesktop(0)->size().height()/720;
234 area.setTop(size_per_element * i + startY - lowerborder);
237 area.setTop(size_per_element * i + startY);
238 area.setWidth(width);
239 area.setHeight(size_per_element);
240 m_visible_region.rects.push_back(area);
243 int timeout_ms = m_pango_page.m_timeout;
244 m_hide_subtitles_timer->start(timeout_ms, true);
245 invalidate(m_visible_region); // invalidate new regions
248 void eSubtitleWidget::clearPage()
250 eDebug("subtitle timeout... hide");
254 invalidate(m_visible_region);
255 m_visible_region.rects.clear();
258 void eSubtitleWidget::setPixmap(ePtr<gPixmap> &pixmap, gRegion changed, eRect pixmap_dest)
261 m_pixmap_dest = pixmap_dest; /* this is in a virtual 720x576 cage */
263 /* 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 */
264 changed.scale(m_pixmap_dest.width(), 720, m_pixmap_dest.height(), 576);
265 changed.moveBy(ePoint(m_pixmap_dest.x(), m_pixmap_dest.y()));
267 if (pixmap->size().width() && pixmap->size().height())
268 changed.scale(size().width(), pixmap->size().width(), size().height(), pixmap->size().height());
273 int eSubtitleWidget::event(int event, void *data, void *data2)
279 ePtr<eWindowStyle> style;
280 gPainter &painter = *(gPainter*)data2;
283 eWidget::event(event, data, data2);
285 std::string alignmentValue;
286 int rt_halignment_flag;
287 ePythonConfigQuery::getConfigValue("config.subtitles.subtitle_alignment", alignmentValue);
288 if (alignmentValue == "right")
289 rt_halignment_flag = gPainter::RT_HALIGN_RIGHT;
290 else if (alignmentValue == "left")
291 rt_halignment_flag = gPainter::RT_HALIGN_LEFT;
293 rt_halignment_flag = gPainter::RT_HALIGN_CENTER;
295 int fontsize = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_fontsize", 34) * getDesktop(0)->size().width()/1280;
296 int edgestyle = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_edgestyle");
297 int borderwidth = (edgestyle == FONTSTYLE_UNIFORM) ? ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_edgestyle_level") : 0;
298 gRGB bordercolor = gRGB();
299 bool original_colors = false;
303 eRect r = m_pixmap_dest;
304 r.scale(size().width(), 720, size().height(), 576);
305 painter.blitScale(m_pixmap, r);
306 } else if (m_page_ok)
308 int elements = m_page.m_elements.size();
310 subtitleStyles[Subtitle_TTX].font->pointSize = fontsize;
312 painter.setFont(subtitleStyles[Subtitle_TTX].font);
313 for (int i=0; i<elements; ++i)
315 eDVBTeletextSubtitlePageElement &element = m_page.m_elements[i];
316 eRect &area = element.m_area;
317 gRGB fontcolor = (!subtitleStyles[Subtitle_TTX].have_foreground_color) ? element.m_color : subtitleStyles[Subtitle_TTX].foreground_color;
318 int bg_r, bg_g, bg_b, bg_a;
319 if (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity") < 0xFF)
321 unsigned int padding = 10;
322 eTextPara *para = new eTextPara(area);
323 para->setFont(subtitleStyles[Subtitle_TTX].font);
324 para->renderString(element.m_text.c_str(), RS_WRAP);
326 eRect bgbox = para->getBoundBox();
327 int bgboxWidth = bgbox.width();
328 int bgboxHeight = bgbox.height();
329 if (alignmentValue == "left")
330 bgbox.setLeft(area.left() - padding - borderwidth);
331 else if (alignmentValue == "right")
332 bgbox.setLeft(area.left() + area.width() - bgboxWidth - padding - borderwidth);
334 bgbox.setLeft(area.left() + area.width() / 2 - bgboxWidth / 2 - padding - borderwidth);
335 bgbox.setTop(area.top() + area.height() / 2 - bgboxHeight / 2 - padding * 2 - borderwidth);
336 bgbox.setWidth(bgboxWidth + padding * 2 + borderwidth * 2);
337 bgbox.setHeight(bgboxHeight + padding * 3 + borderwidth * 2);
339 switch (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgcolor", 0))
366 case BGCOLOR_MAGNETA:
383 bg_a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity", 0);
385 painter.setForegroundColor(gRGB(bg_r, bg_g, bg_b, bg_a));
389 int offset = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_edgestyle_level", 3);
397 case FONTSTYLE_RAISED:
400 ePoint shadow_offset = ePoint(-offset, -offset);
401 shadow.moveBy(shadow_offset);
402 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].shadow_color);
403 painter.renderText(shadow, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
406 case FONTSTYLE_DEPRESSED:
409 ePoint shadow_offset = ePoint(offset, offset);
410 shadow.moveBy(shadow_offset);
411 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].shadow_color);
412 painter.renderText(shadow, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
415 case FONTSTYLE_UNIFORM:
419 if (fontcolor.r == 0 && fontcolor.g == 0 && fontcolor.b == 0)
421 gRGB tmp_border_white = gRGB(255,255,255);
422 bordercolor = tmp_border_white;
424 else if (bg_r == 0 && bg_g == 0 && bg_b == 0)
433 if ( !subtitleStyles[Subtitle_TTX].have_foreground_color )
434 painter.setForegroundColor(element.m_color);
436 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].foreground_color);
437 painter.renderText(area, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag, bordercolor, borderwidth);
440 else if (m_pango_page_ok)
442 int elements = m_pango_page.m_elements.size();
445 for (int i=0; i<elements; ++i)
447 face = Subtitle_Regular;
448 ePangoSubtitlePageElement &element = m_pango_page.m_elements[i];
449 std::string text = element.m_pango_line;
450 text = replace_all(text, "'", "'");
451 text = replace_all(text, """, "\"");
452 text = replace_all(text, "&", "&");
453 text = replace_all(text, "<", "<");
454 text = replace_all(text, ">", ">");
456 std::string shadow_text = text;
457 if (edgestyle == FONTSTYLE_RAISED || edgestyle == FONTSTYLE_DEPRESSED)
459 shadow_text = replace_all(shadow_text, "</u>", "");
460 shadow_text = replace_all(shadow_text, "</i>", "");
461 shadow_text = replace_all(shadow_text, "</b>", "");
462 shadow_text = replace_all(shadow_text, "<u>", "");
463 shadow_text = replace_all(shadow_text, "<i>", "");
464 shadow_text = replace_all(shadow_text, "<b>", "");
467 if (ePythonConfigQuery::getConfigBoolValue("config.subtitles.pango_subtitle_fontswitch"))
469 if (text.find("<i>") != std::string::npos || text.find("</i>") != std::string::npos)
470 face = Subtitle_Italic;
471 else if (text.find("<b>") != std::string::npos || text.find("</b>") != std::string::npos)
472 face = Subtitle_Bold;
474 int subtitleColors = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_fontcolor", 1);
477 text = replace_all(text, "<i>", gRGB(255,255,0));
478 text = replace_all(text, "<b>", gRGB(0,255,255));
479 text = replace_all(text, "<u>", (std::string) gRGB(0,255,0));
480 text = replace_all(text, "</i>", (std::string) gRGB(255,255,255));
481 text = replace_all(text, "</b>", (std::string) gRGB(255,255,255));
482 text = replace_all(text, "</u>", (std::string) gRGB(255,255,255));
486 text = replace_all(text, "</u>", "");
487 text = replace_all(text, "</i>", "");
488 text = replace_all(text, "</b>", "");
489 text = replace_all(text, "<u>", "");
490 text = replace_all(text, "<i>", "");
491 text = replace_all(text, "<b>", "");
494 gRGB fontcolor = (!subtitleStyles[face].have_foreground_color) ? element.m_color : subtitleStyles[face].foreground_color;
495 switch (subtitleColors)
498 case 0: /* use original colors */
499 original_colors = true;
501 case FONTCOLOR_WHITE:
502 fontcolor = gRGB(255, 255, 255);
504 case FONTCOLOR_YELLOW:
505 fontcolor = gRGB(255, 255, 0);
507 case FONTCOLOR_GREEN:
508 fontcolor = gRGB(0, 255, 0);
511 fontcolor = gRGB(0, 255, 255);
514 fontcolor = gRGB(0, 0, 255);
516 case FONTCOLOR_MAGNETA:
517 fontcolor = gRGB(255, 0, 255);
520 fontcolor = gRGB(255, 0, 0);
522 case FONTCOLOR_BLACK:
523 fontcolor = gRGB(0, 0, 0);
526 fontcolor.a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_opacity");
527 if (!original_colors)
528 text = (std::string)fontcolor + text;
530 subtitleStyles[face].font->pointSize = fontsize;
531 painter.setFont(subtitleStyles[face].font);
532 eRect &area = element.m_area;
533 int bg_r, bg_g, bg_b, bg_a;
534 if (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity") < 0xFF)
536 unsigned int padding = 10;
537 eTextPara *para = new eTextPara(area);
538 para->setFont(subtitleStyles[face].font);
539 para->renderString(text.c_str(), RS_WRAP);
541 eRect bgbox = para->getBoundBox();
542 int bgboxWidth = bgbox.width();
543 int bgboxHeight = bgbox.height();
544 if (alignmentValue == "left")
545 bgbox.setLeft(area.left() - padding - borderwidth);
546 else if (alignmentValue == "right")
547 bgbox.setLeft(area.left() + area.width() - bgboxWidth - padding - borderwidth);
549 bgbox.setLeft(area.left() + area.width() / 2 - bgboxWidth / 2 - padding - borderwidth);
550 bgbox.setTop(area.top() + area.height() / 2 - bgboxHeight / 2 - padding * 2 - borderwidth);
551 bgbox.setWidth(bgboxWidth + padding * 2 + borderwidth * 2);
552 bgbox.setHeight(bgboxHeight + padding * 3 + borderwidth * 2);
554 switch (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgcolor", 0))
581 case BGCOLOR_MAGNETA:
598 bg_a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity", 0);
600 painter.setForegroundColor(gRGB(bg_r, bg_g, bg_b, bg_a));
604 int offset = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_edgestyle_level", 3);
612 case FONTSTYLE_RAISED:
615 ePoint shadow_offset = ePoint(-offset, -offset);
616 shadow.moveBy(shadow_offset);
617 painter.setForegroundColor(subtitleStyles[face].shadow_color);
618 painter.renderText(shadow, shadow_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
621 case FONTSTYLE_DEPRESSED:
624 ePoint shadow_offset = ePoint(offset, offset);
625 shadow.moveBy(shadow_offset);
626 painter.setForegroundColor(subtitleStyles[face].shadow_color);
627 painter.renderText(shadow, shadow_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
630 case FONTSTYLE_UNIFORM:
634 if (fontcolor.r == 0 && fontcolor.g == 0 && fontcolor.b == 0)
636 gRGB tmp_border_white = gRGB(255,255,255);
637 bordercolor = tmp_border_white;
639 else if (bg_r == 0 && bg_g == 0 && bg_b == 0)
648 if ( !subtitleStyles[face].have_foreground_color && element.m_have_color )
649 painter.setForegroundColor(element.m_color);
651 painter.setForegroundColor(subtitleStyles[face].foreground_color);
652 painter.renderText(area, text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag, bordercolor, borderwidth);
655 else if (m_dvb_page_ok)
657 for (std::list<eDVBSubtitleRegion>::iterator it(m_dvb_page.m_regions.begin()); it != m_dvb_page.m_regions.end(); ++it)
659 eRect r = eRect(it->m_position, it->m_pixmap->size());
660 r.scale(size().width(), m_dvb_page.m_display_size.width(), size().height(), m_dvb_page.m_display_size.height());
661 painter.blitScale(it->m_pixmap, r);
667 return eWidget::event(event, data, data2);
671 void eSubtitleWidget::setFontStyle(subfont_t face, gFont *font, int haveColor, const gRGB &col, const gRGB &shadowCol, const ePoint &shadowOffset)
673 subtitleStyles[face].font = font;
674 subtitleStyles[face].have_foreground_color = haveColor;
675 subtitleStyles[face].foreground_color = col;
676 subtitleStyles[face].shadow_color = shadowCol;
677 subtitleStyles[face].shadow_offset = shadowOffset;