# -*- coding: utf-8 -*- # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 ############################################################################### # OpenLP - Open Source Lyrics Projection # # --------------------------------------------------------------------------- # # Copyright (c) 2008-2015 OpenLP Developers # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # # Software Foundation; version 2 of the License. # # # # This program is distributed in the hope that it will be useful, but WITHOUT # # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # more details. # # # # You should have received a copy of the GNU General Public License along # # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ This module is responsible for generating the HTML for :class:`~openlp.core.ui.maindisplay`. The ``build_html`` function is the function which has to be called from outside. The generated and returned HTML will look similar to this:: OpenLP Display
""" import logging from PyQt5 import QtWebKit from openlp.core.common import Settings from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType log = logging.getLogger(__name__) HTMLSRC = """ OpenLP Display %s
""" def build_html(item, screen, is_live, background, image=None, plugins=None): """ Build the full web paged structure for display :param item: Service Item to be displayed :param screen: Current display information :param is_live: Item is going live, rather than preview/theme building :param background: Theme background image - bytes :param image: Image media item - bytes :param plugins: The List of available plugins """ width = screen['size'].width() height = screen['size'].height() theme_data = item.theme_data # Image generated and poked in if background: bgimage_src = 'src="data:image/png;base64,%s"' % background elif item.bg_image_bytes: bgimage_src = 'src="data:image/png;base64,%s"' % item.bg_image_bytes else: bgimage_src = 'style="display:none;"' if image: image_src = 'src="data:image/png;base64,%s"' % image else: image_src = 'style="display:none;"' css_additions = '' js_additions = '' html_additions = '' if plugins: for plugin in plugins: css_additions += plugin.get_display_css() js_additions += plugin.get_display_javascript() html_additions += plugin.get_display_html() html = HTMLSRC % ( build_background_css(item, width), css_additions, build_footer_css(item, height), build_lyrics_css(item), 'true' if theme_data and theme_data.display_slide_transition and is_live else 'false', js_additions, bgimage_src, image_src, html_additions ) return html def webkit_version(): """ Return the Webkit version in use. Note method added relatively recently, so return 0 if prior to this """ try: webkit_ver = float(QtWebKit.qWebKitVersion()) log.debug('Webkit version = %s' % webkit_ver) except AttributeError: webkit_ver = 0 return webkit_ver def build_background_css(item, width): """ Build the background css :param item: Service Item containing theme and location information :param width: """ width = int(width) // 2 theme = item.theme_data background = 'background-color: black' if theme: if theme.background_type == BackgroundType.to_string(BackgroundType.Transparent): background = '' elif theme.background_type == BackgroundType.to_string(BackgroundType.Solid): background = 'background-color: %s' % theme.background_color else: if theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal): background = 'background: -webkit-gradient(linear, left top, left bottom, from(%s), to(%s)) fixed' \ % (theme.background_start_color, theme.background_end_color) elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop): background = 'background: -webkit-gradient(linear, left top, right bottom, from(%s), to(%s)) fixed' \ % (theme.background_start_color, theme.background_end_color) elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftBottom): background = 'background: -webkit-gradient(linear, left bottom, right top, from(%s), to(%s)) fixed' \ % (theme.background_start_color, theme.background_end_color) elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical): background = 'background: -webkit-gradient(linear, left top, right top, from(%s), to(%s)) fixed' % \ (theme.background_start_color, theme.background_end_color) else: background = 'background: -webkit-gradient(radial, %s 50%%, 100, %s 50%%, %s, from(%s), to(%s)) fixed'\ % (width, width, width, theme.background_start_color, theme.background_end_color) return background def build_lyrics_css(item): """ Build the lyrics display css :param item: Service Item containing theme and location information """ style = """ .lyricstable { z-index: 5; position: absolute; display: table; %s } .lyricscell { display: table-cell; word-wrap: break-word; -webkit-transition: opacity 0.4s ease; %s } .lyricsmain { %s } """ theme_data = item.theme_data lyricstable = '' lyrics = '' lyricsmain = '' if theme_data and item.main: lyricstable = 'left: %spx; top: %spx;' % (item.main.x(), item.main.y()) lyrics = build_lyrics_format_css(theme_data, item.main.width(), item.main.height()) lyricsmain += build_lyrics_outline_css(theme_data) if theme_data.font_main_shadow: lyricsmain += ' text-shadow: %s %spx %spx;' % \ (theme_data.font_main_shadow_color, theme_data.font_main_shadow_size, theme_data.font_main_shadow_size) lyrics_css = style % (lyricstable, lyrics, lyricsmain) return lyrics_css def build_lyrics_outline_css(theme_data): """ Build the css which controls the theme outline. Also used by renderer for splitting verses :param theme_data: Object containing theme information """ if theme_data.font_main_outline: size = float(theme_data.font_main_outline_size) / 16 fill_color = theme_data.font_main_color outline_color = theme_data.font_main_outline_color return ' -webkit-text-stroke: %sem %s; -webkit-text-fill-color: %s; ' % (size, outline_color, fill_color) return '' def build_lyrics_format_css(theme_data, width, height): """ Build the css which controls the theme format. Also used by renderer for splitting verses :param theme_data: Object containing theme information :param width: Width of the lyrics block :param height: Height of the lyrics block """ align = HorizontalType.Names[theme_data.display_horizontal_align] valign = VerticalType.Names[theme_data.display_vertical_align] if theme_data.font_main_outline: left_margin = int(theme_data.font_main_outline_size) * 2 else: left_margin = 0 justify = 'white-space:pre-wrap;' # fix tag incompatibilities if theme_data.display_horizontal_align == HorizontalType.Justify: justify = '' if theme_data.display_vertical_align == VerticalType.Bottom: padding_bottom = '0.5em' else: padding_bottom = '0' lyrics = '%s word-wrap: break-word; ' \ 'text-align: %s; vertical-align: %s; font-family: %s; ' \ 'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \ 'padding: 0; padding-bottom: %s; padding-left: %spx; width: %spx; height: %spx; ' % \ (justify, align, valign, theme_data.font_main_name, theme_data.font_main_size, theme_data.font_main_color, 100 + int(theme_data.font_main_line_adjustment), padding_bottom, left_margin, width, height) if theme_data.font_main_italics: lyrics += 'font-style:italic; ' if theme_data.font_main_bold: lyrics += 'font-weight:bold; ' return lyrics def build_footer_css(item, height): """ Build the display of the item footer :param item: Service Item to be processed. :param height: """ style = """ left: %spx; bottom: %spx; width: %spx; font-family: %s; font-size: %spt; color: %s; text-align: left; white-space: %s; """ theme = item.theme_data if not theme or not item.footer: return '' bottom = height - int(item.footer.y()) - int(item.footer.height()) whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap' lyrics_html = style % (item.footer.x(), bottom, item.footer.width(), theme.font_footer_name, theme.font_footer_size, theme.font_footer_color, whitespace) return lyrics_html