openlp/openlp/core/lib/htmlbuilder.py

402 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){
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;
if(text.style.opacity<=0.1)
text.innerHTML = newtext;
2010-07-30 05:08:49 +00:00
}
}
2010-08-30 20:57:59 +00:00
function text_opacity(){
var text = document.getElementById('lyricsmain');
return window.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
<!--
Using tables, rather than div's to make use of the vertical-align style that
doesn't work on div's. This avoids the need to do positioning manually which
could get messy when changing verses esp. with transitions
Would prefer to use a single table and make use of -webkit-text-fill-color
-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
Therefore one table for text, one for outline and one for shadow.
-->
2010-07-30 05:08:49 +00:00
<table class="lyricstable lyricscommon">
<tr><td id="lyricsmain" class="lyrics"></td></tr>
2010-07-30 05:08:49 +00:00
</table>
<table class="lyricsoutlinetable lyricscommon">
<tr><td id="lyricsoutline" class="lyricsoutline lyrics"></td></tr>
2010-07-30 05:08:49 +00:00
</table>
<table class="lyricsshadowtable lyricscommon">
<tr><td id="lyricsshadow" class="lyricsshadow lyrics"></td></tr>
2010-07-28 16:53:54 +00:00
</table>
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-08-23 22:24:42 +00:00
lyricscommon = u'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-07-30 05:08:49 +00:00
lyrics = u'%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