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);
30 void eSubtitleWidget::setPage(const eDVBTeletextSubtitlePage &p)
32 eDVBTeletextSubtitlePage newpage = p;
36 invalidate(m_visible_region); // invalidate old visible regions
37 m_visible_region.rects.clear();
39 unsigned int elements = newpage.m_elements.size();
42 int fontsize = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_fontsize", 34) * getDesktop(0)->size().width()/1280;
43 int startY = size().height() - (size().height() / 3 * 1) / 2 - ((fontsize + paddingY) * elements) / 2;
44 int width = size().width() - startX * 2;
45 int height = size().height() - startY;
46 int size_per_element = fontsize + paddingY;
47 bool original_position = ePythonConfigQuery::getConfigBoolValue("config.subtitles.subtitle_original_position");
48 bool rewrap = ePythonConfigQuery::getConfigBoolValue("config.subtitles.subtitle_rewrap");
50 bool original_colors = false;
51 switch (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_fontcolor", 0))
54 case 0: /* use original teletext colors */
55 color = newpage.m_elements[0].m_color;
56 original_colors = true;
59 color = gRGB(255, 255, 255);
61 case FONTCOLOR_YELLOW:
62 color = gRGB(255, 255, 0);
65 color = gRGB(0, 255, 0);
68 color = gRGB(0, 255, 255);
71 color = gRGB(0, 0, 255);
73 case FONTCOLOR_MAGNETA:
74 color = gRGB(255, 0, 255);
77 color = gRGB(255, 0, 0);
80 color = gRGB(0, 0, 0);
83 color.a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_opacity");
85 int line = newpage.m_elements[0].m_source_line;
86 int currentelement = 0;
87 m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", line));
88 for (int i=0; i<elements; ++i)
90 if (!m_page.m_elements[currentelement].m_text.empty())
91 m_page.m_elements[currentelement].m_text += " ";
92 if (original_colors && color != newpage.m_elements[i].m_color)
94 color = newpage.m_elements[i].m_color;
95 m_page.m_elements[currentelement].m_text += (std::string)color;
97 if (line != newpage.m_elements[i].m_source_line)
99 line = newpage.m_elements[i].m_source_line;
102 m_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(color, "", line));
106 m_page.m_elements[currentelement].m_text += newpage.m_elements[i].m_text;
108 for (int i=0; i<m_page.m_elements.size(); i++)
110 eRect &area = m_page.m_elements[i].m_area;
111 area.setLeft(startX);
112 if (!original_position)
114 int lowerborder = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_position", 50);
115 area.setTop(size().height() - size_per_element * (m_page.m_elements.size() - i) - lowerborder * getDesktop(0)->size().height()/720);
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 eTextPara *para = new eTextPara(area);
322 para->setFont(subtitleStyles[Subtitle_TTX].font);
323 para->renderString(element.m_text.c_str(), RS_WRAP);
325 eRect bgbox = para->getBoundBox();
326 int bgboxWidth = bgbox.width();
327 int bgboxHeight = bgbox.height();
328 if (alignmentValue == "left")
329 bgbox.setLeft(area.left() - paddingY - borderwidth);
330 else if (alignmentValue == "right")
331 bgbox.setLeft(area.left() + area.width() - bgboxWidth - paddingY - borderwidth);
333 bgbox.setLeft(area.left() + area.width() / 2 - bgboxWidth / 2 - paddingY - borderwidth);
334 bgbox.setTop(area.top());
335 bgbox.setWidth(bgboxWidth + paddingY * 2 + borderwidth * 2);
336 bgbox.setHeight(area.height());
338 switch (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgcolor", 0))
365 case BGCOLOR_MAGNETA:
382 bg_a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity", 0);
384 painter.setForegroundColor(gRGB(bg_r, bg_g, bg_b, bg_a));
388 int offset = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_edgestyle_level", 3);
396 case FONTSTYLE_RAISED:
399 ePoint shadow_offset = ePoint(-offset, -offset);
400 shadow.moveBy(shadow_offset);
401 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].shadow_color);
402 painter.renderText(shadow, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
405 case FONTSTYLE_DEPRESSED:
408 ePoint shadow_offset = ePoint(offset, offset);
409 shadow.moveBy(shadow_offset);
410 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].shadow_color);
411 painter.renderText(shadow, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
414 case FONTSTYLE_UNIFORM:
418 if (fontcolor.r == 0 && fontcolor.g == 0 && fontcolor.b == 0)
420 gRGB tmp_border_white = gRGB(255,255,255);
421 bordercolor = tmp_border_white;
423 else if (bg_r == 0 && bg_g == 0 && bg_b == 0)
432 if ( !subtitleStyles[Subtitle_TTX].have_foreground_color )
433 painter.setForegroundColor(element.m_color);
435 painter.setForegroundColor(subtitleStyles[Subtitle_TTX].foreground_color);
436 painter.renderText(area, element.m_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag, bordercolor, borderwidth);
439 else if (m_pango_page_ok)
441 int elements = m_pango_page.m_elements.size();
444 for (int i=0; i<elements; ++i)
446 face = Subtitle_Regular;
447 ePangoSubtitlePageElement &element = m_pango_page.m_elements[i];
448 std::string text = element.m_pango_line;
449 text = replace_all(text, "'", "'");
450 text = replace_all(text, """, "\"");
451 text = replace_all(text, "&", "&");
452 text = replace_all(text, "<", "<");
453 text = replace_all(text, ">", ">");
455 std::string shadow_text = text;
456 if (edgestyle == FONTSTYLE_RAISED || edgestyle == FONTSTYLE_DEPRESSED)
458 shadow_text = replace_all(shadow_text, "</u>", "");
459 shadow_text = replace_all(shadow_text, "</i>", "");
460 shadow_text = replace_all(shadow_text, "</b>", "");
461 shadow_text = replace_all(shadow_text, "<u>", "");
462 shadow_text = replace_all(shadow_text, "<i>", "");
463 shadow_text = replace_all(shadow_text, "<b>", "");
466 if (ePythonConfigQuery::getConfigBoolValue("config.subtitles.pango_subtitle_fontswitch"))
468 if (text.find("<i>") != std::string::npos || text.find("</i>") != std::string::npos)
469 face = Subtitle_Italic;
470 else if (text.find("<b>") != std::string::npos || text.find("</b>") != std::string::npos)
471 face = Subtitle_Bold;
473 int subtitleColors = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_fontcolor", 1);
476 text = replace_all(text, "<i>", gRGB(255,255,0));
477 text = replace_all(text, "<b>", gRGB(0,255,255));
478 text = replace_all(text, "<u>", (std::string) gRGB(0,255,0));
479 text = replace_all(text, "</i>", (std::string) gRGB(255,255,255));
480 text = replace_all(text, "</b>", (std::string) gRGB(255,255,255));
481 text = replace_all(text, "</u>", (std::string) gRGB(255,255,255));
485 text = replace_all(text, "</u>", "");
486 text = replace_all(text, "</i>", "");
487 text = replace_all(text, "</b>", "");
488 text = replace_all(text, "<u>", "");
489 text = replace_all(text, "<i>", "");
490 text = replace_all(text, "<b>", "");
493 gRGB fontcolor = (!subtitleStyles[face].have_foreground_color) ? element.m_color : subtitleStyles[face].foreground_color;
494 switch (subtitleColors)
497 case 0: /* use original colors */
498 original_colors = true;
500 case FONTCOLOR_WHITE:
501 fontcolor = gRGB(255, 255, 255);
503 case FONTCOLOR_YELLOW:
504 fontcolor = gRGB(255, 255, 0);
506 case FONTCOLOR_GREEN:
507 fontcolor = gRGB(0, 255, 0);
510 fontcolor = gRGB(0, 255, 255);
513 fontcolor = gRGB(0, 0, 255);
515 case FONTCOLOR_MAGNETA:
516 fontcolor = gRGB(255, 0, 255);
519 fontcolor = gRGB(255, 0, 0);
521 case FONTCOLOR_BLACK:
522 fontcolor = gRGB(0, 0, 0);
525 fontcolor.a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_opacity");
526 if (!original_colors)
527 text = (std::string)fontcolor + text;
529 subtitleStyles[face].font->pointSize = fontsize;
530 painter.setFont(subtitleStyles[face].font);
531 eRect &area = element.m_area;
532 int bg_r, bg_g, bg_b, bg_a;
533 if (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity") < 0xFF)
535 unsigned int padding = 10;
536 eTextPara *para = new eTextPara(area);
537 para->setFont(subtitleStyles[face].font);
538 para->renderString(text.c_str(), RS_WRAP);
540 eRect bgbox = para->getBoundBox();
541 int bgboxWidth = bgbox.width();
542 int bgboxHeight = bgbox.height();
543 if (alignmentValue == "left")
544 bgbox.setLeft(area.left() - padding - borderwidth);
545 else if (alignmentValue == "right")
546 bgbox.setLeft(area.left() + area.width() - bgboxWidth - padding - borderwidth);
548 bgbox.setLeft(area.left() + area.width() / 2 - bgboxWidth / 2 - padding - borderwidth);
549 bgbox.setTop(area.top() + area.height() / 2 - bgboxHeight / 2 - padding * 2 - borderwidth);
550 bgbox.setWidth(bgboxWidth + padding * 2 + borderwidth * 2);
551 bgbox.setHeight(bgboxHeight + padding * 3 + borderwidth * 2);
553 switch (ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgcolor", 0))
580 case BGCOLOR_MAGNETA:
597 bg_a = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bgopacity", 0);
599 painter.setForegroundColor(gRGB(bg_r, bg_g, bg_b, bg_a));
603 int offset = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_edgestyle_level", 3);
611 case FONTSTYLE_RAISED:
614 ePoint shadow_offset = ePoint(-offset, -offset);
615 shadow.moveBy(shadow_offset);
616 painter.setForegroundColor(subtitleStyles[face].shadow_color);
617 painter.renderText(shadow, shadow_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
620 case FONTSTYLE_DEPRESSED:
623 ePoint shadow_offset = ePoint(offset, offset);
624 shadow.moveBy(shadow_offset);
625 painter.setForegroundColor(subtitleStyles[face].shadow_color);
626 painter.renderText(shadow, shadow_text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag);
629 case FONTSTYLE_UNIFORM:
633 if (fontcolor.r == 0 && fontcolor.g == 0 && fontcolor.b == 0)
635 gRGB tmp_border_white = gRGB(255,255,255);
636 bordercolor = tmp_border_white;
638 else if (bg_r == 0 && bg_g == 0 && bg_b == 0)
647 if ( !subtitleStyles[face].have_foreground_color && element.m_have_color )
648 painter.setForegroundColor(element.m_color);
650 painter.setForegroundColor(subtitleStyles[face].foreground_color);
651 painter.renderText(area, text, gPainter::RT_WRAP|gPainter::RT_VALIGN_CENTER|rt_halignment_flag, bordercolor, borderwidth);
654 else if (m_dvb_page_ok)
656 for (std::list<eDVBSubtitleRegion>::iterator it(m_dvb_page.m_regions.begin()); it != m_dvb_page.m_regions.end(); ++it)
658 eRect r = eRect(it->m_position, it->m_pixmap->size());
659 r.scale(size().width(), m_dvb_page.m_display_size.width(), size().height(), m_dvb_page.m_display_size.height());
660 painter.blitScale(it->m_pixmap, r);
666 return eWidget::event(event, data, data2);
670 void eSubtitleWidget::setFontStyle(subfont_t face, gFont *font, int haveColor, const gRGB &col, const gRGB &shadowCol, const ePoint &shadowOffset)
672 subtitleStyles[face].font = font;
673 subtitleStyles[face].have_foreground_color = haveColor;
674 subtitleStyles[face].foreground_color = col;
675 subtitleStyles[face].shadow_color = shadowCol;
676 subtitleStyles[face].shadow_offset = shadowOffset;