# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 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