openlp/openlp/core/lib/htmlbuilder.py

404 lines
12 KiB
Python
Raw Normal View History

2010-07-11 10:58:36 +00:00
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
2010-07-25 09:03:01 +00:00
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
2010-07-11 10:58:36 +00:00
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from openlp.core.lib import image_to_byte
HTMLSRC = u"""
<html>
<head>
<title>OpenLP Display</title>
<style>
*{
margin: 0;
2010-08-09 21:21:04 +00:00
padding: 0;
border: 0;
2010-07-11 10:58:36 +00:00
}
2010-08-07 06:18:05 +00:00
body {
background-color: black;
}
2010-08-09 21:21:04 +00:00
.dim {
position: absolute;
left: 0px;
2010-08-09 21:21:04 +00:00
top: 0px;
width: %spx;
height: %spx;
2010-08-09 21:21:04 +00:00
}
#black {
2010-08-09 21:21:04 +00:00
z-index:8;
background-color: black;
2010-08-09 21:21:04 +00:00
display: none;
}
#video {
z-index:2;
2010-08-09 21:21:04 +00:00
}
#alert {
position: absolute;
left: 0px;
2010-08-09 21:21:04 +00:00
top: 0px;
z-index:10;
%s
2010-08-09 21:21:04 +00:00
}
#footer {
position: absolute;
z-index:5;
%s
2010-08-09 21:21:04 +00:00
}
/* lyric css */
2010-07-11 10:58:36 +00:00
%s
2010-07-11 10:58:36 +00:00
</style>
<script language="javascript">
2010-08-09 21:21:04 +00:00
var timer = null;
var transition = %s;
2010-08-01 08:28:31 +00:00
2010-08-09 21:21:04 +00:00
function show_video(state, path, volume, loop){
2010-08-07 06:18:05 +00:00
var vid = document.getElementById('video');
2010-08-09 21:21:04 +00:00
if(path != null)
2010-08-07 06:18:05 +00:00
vid.src = path;
2010-08-09 21:21:04 +00:00
if(loop != null){
2010-08-07 06:18:05 +00:00
if(loop)
vid.loop = 'loop';
else
vid.loop = '';
}
2010-08-09 21:21:04 +00:00
if(volume != null){
vid.volume = volume;
}
2010-08-07 06:18:05 +00:00
switch(state){
case 'play':
vid.play();
vid.style.display = 'block';
break;
case 'pause':
vid.pause();
vid.style.display = 'block';
break;
case 'stop':
vid.pause();
vid.style.display = 'none';
break;
case 'close':
vid.pause();
vid.style.display = 'none';
2010-08-09 21:21:04 +00:00
vid.src = '';
2010-08-07 06:18:05 +00:00
break;
}
}
2010-08-09 21:21:04 +00:00
function show_image(src){
2010-08-07 06:18:05 +00:00
var img = document.getElementById('image');
img.src = src;
2010-08-09 21:21:04 +00:00
if(src == '')
2010-08-07 06:18:05 +00:00
img.style.display = 'none';
else
img.style.display = 'block';
}
2010-08-09 21:21:04 +00:00
function show_blank(state){
2010-08-05 05:37:26 +00:00
var black = 'none';
var lyrics = '';
2010-08-07 06:18:05 +00:00
var pause = false;
2010-08-05 05:37:26 +00:00
switch(state){
case 'theme':
2010-08-07 06:18:05 +00:00
lyrics = 'hidden';
pause = true;
2010-08-05 05:37:26 +00:00
break;
case 'black':
2010-08-07 06:18:05 +00:00
black = 'block';
pause = true;
break;
case 'desktop':
pause = true;
2010-08-05 19:01:24 +00:00
break;
2010-08-05 05:37:26 +00:00
}
document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('lyricsoutline').style.visibility = lyrics;
document.getElementById('lyricsshadow').style.visibility = lyrics;
2010-08-07 06:18:05 +00:00
document.getElementById('footer').style.visibility = lyrics;
var vid = document.getElementById('video');
if(vid.src != ''){
if(pause)
vid.pause();
else
vid.play();
}
2010-08-05 05:37:26 +00:00
}
2010-08-09 21:21:04 +00:00
function show_alert(alerttext, position){
2010-08-07 06:18:05 +00:00
var text = document.getElementById('alert');
text.innerHTML = alerttext;
2010-08-09 21:21:04 +00:00
if(alerttext == '') {
2010-08-07 06:18:05 +00:00
text.style.visibility = 'hidden';
return 0;
}
2010-08-09 21:21:04 +00:00
if(position == ''){
position = getComputedStyle(text, '').verticalAlign;
2010-08-07 06:18:05 +00:00
}
2010-08-09 21:21:04 +00:00
switch(position)
2010-08-07 06:18:05 +00:00
{
2010-08-09 21:21:04 +00:00
case 'top':
text.style.top = '0px';
break;
case 'middle':
text.style.top = ((window.innerHeight - text.clientHeight) / 2)
2010-08-09 21:21:04 +00:00
+ 'px';
break;
case 'bottom':
text.style.top = (window.innerHeight - text.clientHeight)
2010-08-09 21:21:04 +00:00
+ 'px';
break;
2010-08-07 06:18:05 +00:00
}
text.style.visibility = 'visible';
return text.clientHeight;
}
2010-08-21 10:07:59 +00:00
function show_footer(footertext){
2010-08-23 22:24:42 +00:00
document.getElementById('footer').innerHTML = footertext;
2010-08-09 21:21:04 +00:00
}
2010-08-09 21:21:04 +00:00
function show_text(newtext){
if(timer != null)
clearTimeout(timer);
text_fade('lyricsmain', newtext);
text_fade('lyricsoutline', newtext);
text_fade('lyricsshadow', newtext);
if(text_opacity()==1) return;
timer = setTimeout(function(){
show_text(newtext);
}, 100);
2010-08-30 18:55:59 +00:00
}
function text_fade(id, newtext){
var text = document.getElementById(id);
if(!transition){
2010-09-01 21:36:02 +00:00
text.innerHTML = newtext;
return;
}
if(text.style.opacity=='') text.style.opacity = 1;
if(newtext==text.innerHTML){
text.style.opacity = parseFloat(text.style.opacity) + 0.3;
2010-08-09 21:21:04 +00:00
} else {
text.style.opacity -= 0.3;
2010-09-01 21:36:02 +00:00
if(text.style.opacity<=0.1){
text.innerHTML = newtext;
2010-09-01 21:36:02 +00:00
}
2010-07-30 05:08:49 +00:00
}
}
2010-08-30 20:57:59 +00:00
function text_opacity(){
var text = document.getElementById('lyricsmain');
2010-09-01 21:36:02 +00:00
return getComputedStyle(text, '').opacity;
}
2010-08-09 21:21:04 +00:00
function show_text_complete(){
return (text_opacity()==1);
2010-07-11 10:58:36 +00:00
}
</script>
</head>
<body>
2010-08-09 21:21:04 +00:00
<!--
2010-09-01 21:36:02 +00:00
Would prefer to use a single div and make use of -webkit-text-fill-color
2010-08-09 21:21:04 +00:00
-webkit-text-stroke and text-shadow styles, but they have problems working/
co-operating in qwebkit. https://bugs.webkit.org/show_bug.cgi?id=43187
2010-09-01 21:36:02 +00:00
Therefore one for text, one for outline and one for shadow.
Note, the webkit fill problem is fixed in 433.3 and the shadow problem looks
as though it'll be fixed in QtWebkit 2.1 (434.3)
There is an alignment problem with fills in 433.3 however requiring a hack
by setting letter spacing. This is also fixed in v434.3
2010-08-09 21:21:04 +00:00
-->
2010-09-01 21:36:02 +00:00
<div class="lyricstable lyricscommon">
<div id="lyricsmain" class="lyrics"></div>
</div>
<div class="lyricsoutlinetable lyricscommon">
<div id="lyricsoutline" class="lyricsoutline lyrics"></div>
</div>
<div class="lyricsshadowtable lyricscommon">
<div id="lyricsshadow" class="lyricsshadow lyrics"></div>
</div>
2010-08-07 06:18:05 +00:00
<div id="alert" style="visibility:hidden;"></div>
2010-07-19 18:03:00 +00:00
<div id="footer" class="footer"></div>
2010-08-09 21:21:04 +00:00
<video class="dim" id="video"></video>
<div class="dim" id="black"></div>
<img class="dim" id="image" src="%s" />
2010-07-11 10:58:36 +00:00
</body>
</html>
"""
2010-07-27 19:13:56 +00:00
def build_html(item, screen, alert, islive):
2010-07-25 08:58:08 +00:00
"""
Build the full web paged structure for display
`item`
Service Item to be displayed
`screen`
Current display information
`alert`
Alert display display information
"""
2010-07-11 10:58:36 +00:00
width = screen[u'size'].width()
height = screen[u'size'].height()
2010-07-30 05:08:49 +00:00
theme = item.themedata
2010-08-09 21:21:04 +00:00
if item.bg_frame:
image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame)
2010-08-07 06:18:05 +00:00
else:
2010-08-09 21:21:04 +00:00
image = u''
html = HTMLSRC % (width, height,
build_alert(alert, width),
build_footer(item),
build_lyrics(item),
u'true' if theme and theme.display_slideTransition and islive \
else u'false',
2010-08-09 21:21:04 +00:00
image)
return html
2010-07-11 10:58:36 +00:00
def build_lyrics(item):
2010-07-25 08:58:08 +00:00
"""
Build the video display div
`item`
Service Item containing theme and location information
"""
2010-07-28 16:53:54 +00:00
style = """
.lyricscommon { position: absolute; %s }
.lyricstable { z-index:4; %s }
.lyricsoutlinetable { z-index:3; %s }
.lyricsshadowtable { z-index:2; %s }
.lyrics { %s }
.lyricsoutline { %s }
.lyricsshadow { %s }
2010-07-30 05:08:49 +00:00
"""
2010-07-17 08:59:15 +00:00
theme = item.themedata
2010-07-30 05:08:49 +00:00
lyricscommon = u''
lyricstable = u''
outlinetable = u''
shadowtable = u''
2010-07-28 16:53:54 +00:00
lyrics = u''
2010-07-30 05:08:49 +00:00
outline = u'display: none;'
shadow = u'display: none;'
2010-07-12 16:49:38 +00:00
if theme:
2010-09-01 21:36:02 +00:00
lyricscommon = u'display: table; width: %spx; height: %spx; word-wrap: break-word; ' \
2010-08-29 14:20:21 +00:00
u'font-family: %s; font-size: %spt; color: %s; line-height: %d%%;' \
2010-08-28 23:52:10 +00:00
% (item.main.width(), item.main.height(), theme.font_main_name,
theme.font_main_proportion, theme.font_main_color,
100 + int(theme.font_main_line_adjustment))
2010-07-30 05:08:49 +00:00
lyricstable = u'left: %spx; top: %spx;' % \
(item.main.x(), item.main.y())
outlinetable = u'left: %spx; top: %spx;' % \
2010-08-25 17:08:24 +00:00
(item.main.x(), item.main.y())
2010-07-30 05:08:49 +00:00
shadowtable = u'left: %spx; top: %spx;' % \
(item.main.x() + float(theme.display_shadow_size),
item.main.y() + float(theme.display_shadow_size))
2010-07-18 18:01:35 +00:00
align = u''
if theme.display_horizontalAlign == 2:
2010-07-28 16:53:54 +00:00
align = u'text-align:center;'
2010-07-18 18:01:35 +00:00
elif theme.display_horizontalAlign == 1:
2010-07-28 16:53:54 +00:00
align = u'text-align:right;'
else:
align = u'text-align:left;'
2010-07-18 18:01:35 +00:00
if theme.display_verticalAlign == 2:
2010-07-27 19:13:56 +00:00
valign = u'vertical-align:bottom;'
2010-07-18 18:01:35 +00:00
elif theme.display_verticalAlign == 1:
2010-07-27 19:13:56 +00:00
valign = u'vertical-align:middle;'
2010-07-18 18:01:35 +00:00
else:
2010-07-27 19:13:56 +00:00
valign = u'vertical-align:top;'
2010-09-01 21:36:02 +00:00
lyrics = u'display:table-cell; %s %s' % (align, valign)
2010-07-28 16:53:54 +00:00
if theme.display_outline:
lyricscommon += u' letter-spacing: 1px;'
2010-07-30 05:08:49 +00:00
outline = u'-webkit-text-stroke: %sem %s; ' % \
2010-07-28 16:53:54 +00:00
(float(theme.display_outline_size) / 16,
theme.display_outline_color)
2010-07-30 05:08:49 +00:00
if theme.display_shadow:
shadow = u'-webkit-text-stroke: %sem %s; ' \
2010-08-28 23:52:10 +00:00
u'-webkit-text-fill-color: %s; ' % \
2010-07-30 05:08:49 +00:00
(float(theme.display_outline_size) / 16,
theme.display_shadow_color, theme.display_shadow_color)
2010-07-30 05:08:49 +00:00
else:
if theme.display_shadow:
shadow = u'color: %s;' % (theme.display_shadow_color)
lyrics_html = style % (lyricscommon, lyricstable, outlinetable,
shadowtable, lyrics, outline, shadow)
2010-07-19 18:03:00 +00:00
return lyrics_html
2010-07-24 16:55:06 +00:00
def build_footer(item):
2010-08-03 04:56:21 +00:00
"""
Build the display of the item footer
`item`
Service Item to be processed.
"""
2010-08-09 21:21:04 +00:00
style = """
2010-08-30 20:57:59 +00:00
left: %spx;
top: %spx;
width: %spx;
height: %spx;
font-family: %s;
font-size: %spt;
color: %s;
text-align: %s;
2010-07-19 18:03:00 +00:00
"""
theme = item.themedata
2010-08-09 21:21:04 +00:00
if not theme:
return u''
if theme.display_horizontalAlign == 2:
align = u'center'
elif theme.display_horizontalAlign == 1:
align = u'right'
else:
align = u'left'
2010-08-25 17:08:24 +00:00
lyrics_html = style % (item.footer.x(), item.footer.y(),
item.footer.width(), item.footer.height(), theme.font_footer_name,
2010-08-09 21:21:04 +00:00
theme.font_footer_proportion, theme.font_footer_color, align)
2010-07-12 16:49:38 +00:00
return lyrics_html
2010-07-11 10:58:36 +00:00
2010-08-09 21:21:04 +00:00
def build_alert(alertTab, width):
2010-08-03 04:56:21 +00:00
"""
Build the display of the footer
2010-07-19 18:03:00 +00:00
2010-08-03 04:56:21 +00:00
`alertTab`
Details from the Alert tab for fonts etc
"""
2010-08-01 08:28:31 +00:00
style = """
2010-08-30 20:57:59 +00:00
width: %s;
vertical-align: %s;
font-family: %s;
font-size: %spt;
color: %s;
background-color: %s;
2010-08-07 06:18:05 +00:00
"""
2010-08-09 21:21:04 +00:00
if not alertTab:
return u''
align = u''
if alertTab.location == 2:
align = u'bottom'
elif alertTab.location == 1:
align = u'middle'
else:
align = u'top'
alert = style % (width, align, alertTab.font_face, alertTab.font_size,
2010-08-09 21:21:04 +00:00
alertTab.font_color, alertTab.bg_color)
return alert