diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index b76179c2c..721b6ae23 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -39,40 +39,40 @@ log = logging.getLogger(__name__) html_expands = [] html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \ - u'start html':u'', \ - u'end tag':u'{/r}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/r}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \ - u'start html':u'', \ - u'end tag':u'{/b}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/b}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \ - u'start html':u'', \ - u'end tag':u'{/bl}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/bl}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \ - u'start html':u'', \ - u'end tag':u'{/y}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/y}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \ - u'start html':u'', \ - u'end tag':u'{/g}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/g}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \ - u'start html':u'', \ - u'end tag':u'{/pk}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/pk}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \ - u'start html':u'', \ - u'end tag':u'{/o}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/o}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \ - u'start html':u'', \ - u'end tag':u'{/pp}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/pp}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'White', u'start tag':u'{w}', \ - u'start html':u'', \ - u'end tag':u'{/w}', u'end html':u'', \ + u'start html':u'', \ + u'end tag':u'{/w}', u'end html':u'', \ u'protected':False}) html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \ u'start html':u'', \ diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 332d23844..d03b7f7cc 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -24,6 +24,8 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +from PyQt4 import QtWebKit + from openlp.core.lib import image_to_byte HTMLSRC = u""" @@ -39,7 +41,7 @@ HTMLSRC = u""" body { background-color: black; } -.dim { +.size { position: absolute; left: 0px; top: 0px; @@ -51,6 +53,9 @@ body { background-color: black; display: none; } +#image { + z-index:1; +} #video { z-index:2; } @@ -136,8 +141,12 @@ body { } document.getElementById('black').style.display = black; document.getElementById('lyricsmain').style.visibility = lyrics; - document.getElementById('lyricsoutline').style.visibility = lyrics; - document.getElementById('lyricsshadow').style.visibility = lyrics; + outline = document.getElementById('lyricsoutline') + if(outline!=null) + outline.style.visibility = lyrics; + shadow = document.getElementById('lyricsshadow') + if(shadow!=null) + shadow.style.visibility = lyrics; document.getElementById('footer').style.visibility = lyrics; var vid = document.getElementById('video'); if(vid.src != ''){ @@ -156,7 +165,7 @@ body { return 0; } if(position == ''){ - position = window.getComputedStyle(text, '').verticalAlign; + position = getComputedStyle(text, '').verticalAlign; } switch(position) { @@ -181,111 +190,62 @@ body { } function show_text(newtext){ - var text1 = document.getElementById('lyricsmain'); - var texto1 = document.getElementById('lyricsoutline'); - var texts1 = document.getElementById('lyricsshadow'); - if(!transition){ - text1.innerHTML = newtext; - texto1.innerHTML = newtext; - texts1.innerHTML = newtext; - return; - } - var text2 = document.getElementById('lyricsmain2'); - var texto2 = document.getElementById('lyricsoutline2'); - var texts2 = document.getElementById('lyricsshadow2'); - if((text2.style.opacity == '')||(parseFloat(text2.style.opacity) < 0.5)) - { - text2.innerHTML = text1.innerHTML; - text2.style.opacity = text1.style.opacity; - texto2.innerHTML = text1.innerHTML; - texto2.style.opacity = text1.style.opacity; - texts2.innerHTML = text1.innerHTML; - texts2.style.opacity = text1.style.opacity; - } - text1.style.opacity = 0; - text1.innerHTML = newtext; - texto1.style.opacity = 0; - texto1.innerHTML = newtext; - texts1.style.opacity = 0; - texts1.innerHTML = newtext; - // For performance reasons, we'll not animate the shadow for now - texts2.style.opacity = 0; if(timer != null) clearTimeout(timer); - timer = setTimeout('text_fade()', 50); + text_fade('lyricsmain', newtext); + text_fade('lyricsoutline', newtext); + text_fade('lyricsshadow', newtext); + if(text_opacity()==1) return; + timer = setTimeout(function(){ + show_text(newtext); + }, 100); } - function text_fade(){ - var text1 = document.getElementById('lyricsmain'); - var texto1 = document.getElementById('lyricsoutline'); - var texts1 = document.getElementById('lyricsshadow'); - var text2 = document.getElementById('lyricsmain2'); - var texto2 = document.getElementById('lyricsoutline2'); - var texts2 = document.getElementById('lyricsshadow2'); - if(parseFloat(text1.style.opacity) < 1){ - text1.style.opacity = parseFloat(text1.style.opacity) + 0.1; - texto1.style.opacity = parseFloat(texto1.style.opacity) + 0.1; - // Don't animate shadow (performance) - //texts1.style.opacity = parseFloat(texts1.style.opacity) + 0.1; + function text_fade(id, newtext){ + /* + Using -webkit-transition: opacity 1s linear; would have been preferred + but it isn't currently quick enough when animating multiple layers of + large areas of large text. Therefore do it manually as best we can. + Hopefully in the future we can revisit and do more interesting + transitions using -webkit-transition and -webkit-transform. + However we need to ensure interrupted transitions (quickly change 2 + slides) still looks pretty and is zippy. + */ + var text = document.getElementById(id); + if(text==null) return; + if(!transition){ + text.innerHTML = newtext; + return; } - if(parseFloat(text2.style.opacity) > 0){ - text2.style.opacity = parseFloat(text2.style.opacity) - 0.1; - texto2.style.opacity = parseFloat(texto2.style.opacity) - 0.1; - // Don't animate shadow (performance) - //texts2.style.opacity = parseFloat(texts2.style.opacity) - 0.1; - } - if((parseFloat(text1.style.opacity) < 1) || - (parseFloat(text2.style.opacity) > 0)){ - t = setTimeout('text_fade()', 50); + if(newtext==text.innerHTML){ + text.style.opacity = parseFloat(text.style.opacity) + 0.3; + if(text.style.opacity>0.7) + text.style.opacity = 1; } else { - text1.style.opacity = 1; - texto1.style.opacity = 1; - texts1.style.opacity = 1; - text2.style.opacity = 0; - texto2.style.opacity = 0; - texts2.style.opacity = 0; + text.style.opacity = parseFloat(text.style.opacity) - 0.3; + if(text.style.opacity<=0.1){ + text.innerHTML = newtext; + } } } + function text_opacity(){ + var text = document.getElementById('lyricsmain'); + return getComputedStyle(text, '').opacity; + } + function show_text_complete(){ - return (document.getElementById('lyricsmain').style.opacity == 1); + return (text_opacity()==1); } - - - -
- - -
- - -
- - -
- - -
- - -
- + + +%s - -
- +
+ """ @@ -300,7 +260,13 @@ def build_html(item, screen, alert, islive): Current display information `alert` Alert display display information + `islive` + Item is going live, rather than preview/theme building """ + try: + webkitvers = float(QtWebKit.qWebKitVersion()) + except AttributeError: + webkitvers = 0 width = screen[u'size'].width() height = screen[u'size'].height() theme = item.themedata @@ -309,83 +275,144 @@ def build_html(item, screen, alert, islive): else: image = u'' html = HTMLSRC % (width, height, - build_alert(alert, width), - build_footer(item), - build_lyrics(item), + build_alert_css(alert, width), + build_footer_css(item), + build_lyrics_css(item, webkitvers), u'true' if theme and theme.display_slideTransition and islive \ else u'false', - image) + image, + build_lyrics_html(item, webkitvers)) return html -def build_lyrics(item): +def build_lyrics_css(item, webkitvers): """ - Build the video display div + Build the video display css `item` Service Item containing theme and location information + + `webkitvers` + The version of qtwebkit we're using + """ 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 } +.lyricstable { + z-index:4; + position: absolute; + display: table; + %s +} +.lyricscell { + display:table-cell; + word-wrap: break-word; + %s +} +.lyricsmain { +%s +} +.lyricsoutline { +%s +} +.lyricsshadow { +%s +} """ theme = item.themedata - lyricscommon = u'' lyricstable = u'' - outlinetable = u'' - shadowtable = u'' lyrics = u'' - outline = u'display: none;' - shadow = u'display: none;' + lyricsmain = u'' + outline = u'' + shadow = u'' if theme: - lyricscommon = u'width: %spx; height: %spx; word-wrap: break-word; ' \ - u'font-family: %s; font-size: %spt; color: %s; line-height: %d%%;' \ - % (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)) lyricstable = u'left: %spx; top: %spx;' % \ (item.main.x(), item.main.y()) - outlinetable = u'left: %spx; top: %spx;' % \ - (item.main.x(), item.main.y()) - shadowtable = u'left: %spx; top: %spx;' % \ - (item.main.x() + float(theme.display_shadow_size), - item.main.y() + float(theme.display_shadow_size)) - align = u'' if theme.display_horizontalAlign == 2: - align = u'text-align:center;' + align = u'center' elif theme.display_horizontalAlign == 1: - align = u'text-align:right;' + align = u'right' else: - align = u'text-align:left;' + align = u'left' if theme.display_verticalAlign == 2: - valign = u'vertical-align:bottom;' + valign = u'bottom' elif theme.display_verticalAlign == 1: - valign = u'vertical-align:middle;' + valign = u'middle' else: - valign = u'vertical-align:top;' - lyrics = u'%s %s' % (align, valign) + valign = u'top' + lyrics = u'width: %spx; height: %spx; text-align: %s; ' \ + 'vertical-align: %s; font-family: %s; font-size: %spt; ' \ + 'color: %s; line-height: %d%%;' % \ + (item.main.width(), item.main.height(), align, valign, + theme.font_main_name, theme.font_main_proportion, + theme.font_main_color, 100 + int(theme.font_main_line_adjustment)) + # For performance reasons we want to show as few DIV's as possible, + # especially when animating/transitions. + # However some bugs in older versions of qtwebkit mean we need to + # perform workarounds and add extra divs. Only do these when needed. + # + # Before 533.3 the webkit-text-fill colour wasn't displayed, only the + # stroke (outline) color. So put stroke layer underneath the main text. + # + # Before 534.4 the webkit-text-stroke was sometimes out of alignment + # with the fill, or normal text. letter-spacing=1 is workaround + # https://bugs.webkit.org/show_bug.cgi?id=44403 + # + # Before 534.4 the text-shadow didn't get displayed when + # webkit-text-stroke was used. So use an offset text layer underneath. + # https://bugs.webkit.org/show_bug.cgi?id=19728 if theme.display_outline: - lyricscommon += u' letter-spacing: 1px;' - outline = u'-webkit-text-stroke: %sem %s; ' % \ + if webkitvers < 534.3: + lyrics += u' letter-spacing: 1px;' + outline = u' -webkit-text-stroke: %sem %s; ' \ + '-webkit-text-fill-color: %s; ' % \ (float(theme.display_outline_size) / 16, - theme.display_outline_color) - if theme.display_shadow: + theme.display_outline_color, theme.font_main_color) + if webkitvers >= 533.3: + lyricsmain += outline + if theme.display_shadow and webkitvers < 534.3: shadow = u'-webkit-text-stroke: %sem %s; ' \ - u'-webkit-text-fill-color: %s; ' % \ + u'-webkit-text-fill-color: %s; ' \ + u' padding-left: %spx; padding-top: %spx' % \ (float(theme.display_outline_size) / 16, - theme.display_shadow_color, theme.display_shadow_color) - else: - if theme.display_shadow: - shadow = u'color: %s;' % (theme.display_shadow_color) - lyrics_html = style % (lyricscommon, lyricstable, outlinetable, - shadowtable, lyrics, outline, shadow) - return lyrics_html + theme.display_shadow_color, theme.display_shadow_color, + theme.display_shadow_size, theme.display_shadow_size) + if theme.display_shadow and \ + (not theme.display_outline or webkitvers >= 534.3): + lyricsmain += u' text-shadow: %s %spx %spx;' % \ + (theme.display_shadow_color, theme.display_shadow_size, + theme.display_shadow_size) + lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow) + return lyrics_css + +def build_lyrics_html(item, webkitvers): + """ + Build the HTML required to show the lyrics -def build_footer(item): + `item` + Service Item containing theme and location information + + `webkitvers` + The version of qtwebkit we're using + """ + # Bugs in some versions of QtWebKit mean we sometimes need additional + # divs for outline and shadow, since the CSS doesn't work. + # To support vertical alignment middle and bottom, nested div's using + # display:table/display:table-cell are required for each lyric block. + lyrics = u'' + theme = item.themedata + if webkitvers < 534.4 and theme and theme.display_outline: + lyrics += u'
' \ + u'
' + if webkitvers < 533.3: + lyrics += u'
' \ + u'
' + lyrics += u'
' \ + u'
' + return lyrics + +def build_footer_css(item): """ Build the display of the item footer @@ -416,7 +443,7 @@ def build_footer(item): theme.font_footer_proportion, theme.font_footer_color, align) return lyrics_html -def build_alert(alertTab, width): +def build_alert_css(alertTab, width): """ Build the display of the footer @@ -424,7 +451,7 @@ def build_alert(alertTab, width): Details from the Alert tab for fonts etc """ style = """ - width: %s; + width: %spx; vertical-align: %s; font-family: %s; font-size: %spt; diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 908e91d01..868399f83 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -115,8 +115,11 @@ class MainDisplay(DisplayWidget): self.screen = self.screens.current self.setVisible(False) self.setGeometry(self.screen[u'size']) - self.webView = QtWebKit.QWebView(self) - self.webView.setGeometry(0, 0, self.screen[u'size'].width(), \ + self.scene = QtGui.QGraphicsScene() + self.setScene(self.scene) + self.webView = QtWebKit.QGraphicsWebView() + self.scene.addItem(self.webView) + self.webView.resize(self.screen[u'size'].width(), \ self.screen[u'size'].height()) self.page = self.webView.page() self.frame = self.page.mainFrame()