Jonathan Corwin has proposed merging lp:~j-corwin/openlp/render into lp:~trb143/openlp/renderer.
Requested reviews: OpenLP Core (openlp-core) Alerts over presentations and other fixes. NOTE This is a merge request for Tims branch, not trunk. -- https://code.launchpad.net/~j-corwin/openlp/render/+merge/33246 Your team OpenLP Core is requested to review the proposed merge of lp:~j-corwin/openlp/render into lp:~trb143/openlp/renderer.
=== modified file 'openlp/core/lib/htmlbuilder.py' --- openlp/core/lib/htmlbuilder.py 2010-08-07 06:18:05 +0000 +++ openlp/core/lib/htmlbuilder.py 2010-08-20 18:26:42 +0000 @@ -33,33 +33,60 @@ <style> *{ margin: 0; - padding:0 + padding: 0; + border: 0; } body { background-color: black; } -%s -%s -%s -%s -%s -%s -%s +.dim { + position: absolute; + left: 0px; + top: 0px; + width: %spx; + height: %spx; +} +#black { + z-index:8; + background-color: black; + display: none; +} +#video { + z-index:2; +} +#alert { + position: absolute; + left: 0px; + top: 0px; + z-index:10; + %s +} +#footer { + position: absolute; + z-index:5; + %s +} +/* lyric css */ +%s + </style> <script language="javascript"> - var t = null; + var timer = null; var transition = %s; - function video(state, path, volume, loop){ + function show_video(state, path, volume, loop){ var vid = document.getElementById('video'); - if(path!=null) + if(path != null) vid.src = path; - if(loop!=null){ + if(loop != null){ if(loop) vid.loop = 'loop'; else vid.loop = ''; } + if(volume != null){ + vid.volume = volume; + } switch(state){ case 'play': vid.play(); @@ -76,22 +103,20 @@ case 'close': vid.pause(); vid.style.display = 'none'; - vid.setAttribute('src', ''); + vid.src = ''; break; - if(volume!=null) - vid.volume = volume; } } - function setImage(src){ + function show_image(src){ var img = document.getElementById('image'); img.src = src; - if(src=='') + if(src == '') img.style.display = 'none'; else img.style.display = 'block'; } - function blankState(state){ + function show_blank(state){ var black = 'none'; var lyrics = ''; var pause = false; @@ -122,36 +147,39 @@ } } - function displayAlert(alerttext, shrink){ + function show_alert(alerttext, position){ var text = document.getElementById('alert'); text.innerHTML = alerttext; - if(alerttext=='') { + if(alerttext == '') { text.style.visibility = 'hidden'; return 0; } - if(shrink){ - text.style.top = '0px'; + if(position == ''){ + position = window.getComputedStyle(text, '').verticalAlign; } - else + switch(position) { - switch(window.getComputedStyle(text, '').verticalAlign) - { - case 'top': - text.style.top = '0px'; - break; - case 'middle': - text.style.top = ((window.innerHeight - text.clientHeight) / 2) + 'px'; - break; - case 'bottom': - text.style.top = (window.innerHeight - text.clientHeight) + 'px'; - break; - } + case 'top': + text.style.top = '0px'; + break; + case 'middle': + text.style.top = ((window.innerHeight - text.clientHeight) / 2) + + 'px'; + break; + case 'bottom': + text.style.top = (window.innerHeight - text.clientHeight) + + 'px'; + break; } text.style.visibility = 'visible'; return text.clientHeight; } - function startfade(newtext){ + function show_footer(text){ + document.getElementById('footer').innerHTML(text); + } + + function show_text(newtext){ var text1 = document.getElementById('lyricsmain'); var texto1 = document.getElementById('lyricsoutline'); var texts1 = document.getElementById('lyricsshadow'); @@ -164,7 +192,8 @@ 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){ + if((text2.style.opacity == '')||(parseFloat(text2.style.opacity) < 0.5)) + { text2.innerHTML = text1.innerHTML; text2.style.opacity = text1.style.opacity; texto2.innerHTML = text1.innerHTML; @@ -178,15 +207,14 @@ texto1.innerHTML = newtext; texts1.style.opacity = 0; texts1.innerHTML = newtext; - // temp: + // For performance reasons, we'll not animate the shadow for now texts2.style.opacity = 0; - // end temp - if(t!=null) - clearTimeout(t); - t = setTimeout('fade()', 50); + if(timer != null) + clearTimeout(timer); + timer = setTimeout('text_fade()', 50); } - function fade(){ + function text_fade(){ var text1 = document.getElementById('lyricsmain'); var texto1 = document.getElementById('lyricsoutline'); var texts1 = document.getElementById('lyricsshadow'); @@ -196,16 +224,19 @@ 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; } 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('fade()', 50); - else{ + if((parseFloat(text1.style.opacity) < 1) || + (parseFloat(text2.style.opacity) > 0)){ + t = setTimeout('text_fade()', 50); + } else { text1.style.opacity = 1; texto1.style.opacity = 1; texts1.style.opacity = 1; @@ -215,12 +246,22 @@ } } - function fadeFinished(){ - return (document.getElementById('lyricsmain').style.opacity==1); + function show_text_complete(){ + return (document.getElementById('lyricsmain').style.opacity == 1); } </script> </head> <body> +<!-- +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. +--> <table class="lyricstable lyricscommon"> <tr><td id="lyricsmain" class="lyrics"></td></tr> </table> @@ -239,18 +280,11 @@ <table class="lyricsshadowtable lyricscommon"> <tr><td id="lyricsshadow2" class="lyricsshadow lyrics"></td></tr> </table> -<!-- -<table class="alerttable"> - <tr><td class="alertcell"> - <div class="alert" id="alertmain"></div> - </td></tr> -</table> ---> <div id="alert" style="visibility:hidden;"></div> <div id="footer" class="footer"></div> -<video id="video"></video> -<div id="black"></div> -%s +<video class="dim" id="video"></video> +<div class="dim" id="black"></div> +<img class="dim" id="image" src="%s" /> </body> </html> """ @@ -269,80 +303,18 @@ width = screen[u'size'].width() height = screen[u'size'].height() theme = item.themedata - html = HTMLSRC % (build_video(width, height), - build_image(width, height), - build_lyrics(item), - build_footer(item), - build_alert(width, height, alert), - build_image(width, height), - build_black(width, height), - "true" if theme and - theme.display_slideTransition else "false", - build_image_src(item.bg_frame)) + if item.bg_frame: + image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame) + else: + image = u'' + html = HTMLSRC % (width, height, + build_alert(alert, width), + build_footer(item), + build_lyrics(item), + u'true' if theme and theme.display_slideTransition else u'false', + image) return html -def build_video(width, height): - """ - Build the video display div - - `width` - Screen width - `height` - Screen height - """ - video = """ - #video { position: absolute; left: 0px; top: 0px; - width: %spx; height: %spx; z-index:2; } - """ - return video % (width, height) - -def build_black(width, height): - """ - Build the black display div - - `width` - Screen width - `height` - Screen height - """ - black = """ - #black { position: absolute; left: 0px; top: 0px; - width: %spx; height: %spx; z-index:8; - background-color: black; display: none; - } - """ - return black % (width, height) - -def build_image(width, height): - """ - Build the image display div - - `width` - Screen width - `height` - Screen height - """ - image = """ - #image { position: absolute; left: 0px; top: 0px; - width: %spx; height: %spx; z-index:1; - } - """ - return image % (width, height) - -def build_image_src(image): - """ - Build display for the backgroung image - - `image` - Image to be displayed - """ - if image: - return '<img id="image" src="data:image/png;base64,%s" />' % \ - image_to_byte(image) - else: - return '<img id="image" />' - - def build_lyrics(item): """ Build the video display div @@ -358,7 +330,6 @@ .lyrics { %s } .lyricsoutline { %s } .lyricsshadow { %s } - table {border=0; margin=0; padding=0; } """ theme = item.themedata lyricscommon = u'' @@ -408,7 +379,6 @@ shadow = u'color: %s;' % (theme.display_shadow_color) lyrics_html = style % (lyricscommon, lyricstable, outlinetable, shadowtable, lyrics, outline, shadow) - print lyrics_html return lyrics_html def build_footer(item): @@ -418,64 +388,54 @@ `item` Service Item to be processed. """ - lyrics = """ - #footer {position: absolute; %s z-index:5; %s; %s } + style = """ + left: %spx; + top: %spx; + width: %spx; + height: %spx; + font-family: %s; + font-size: %spx; + color: %s; + align: %s; """ theme = item.themedata - lyrics_html = u'' - position = u'' - font = u'' - text = u'' - if theme: - position = u' left: %spx; top: %spx; width: %spx; height: %spx; ' % \ - (item.footer.x(), item.footer.y(), item.footer.width(), - item.footer.height()) - font = u' font-family %s; font-size: %spx;' % \ - (theme.font_footer_name, theme.font_footer_proportion) - align = u'' - if theme.display_horizontalAlign == 2: - align = u'align:center;' - elif theme.display_horizontalAlign == 1: - align = u'align:right;' - text = u'color:%s; %s ' % (theme.font_footer_color, align) - lyrics_html = lyrics % (position, font, text) + 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' + lyrics_html = style % (item.footer.x(), item.footer.y(), + item.footer.width(), item.footer.height(), theme.font_footer_name, + theme.font_footer_proportion, theme.font_footer_color, align) return lyrics_html -def build_alert(width, height, alertTab): +def build_alert(alertTab, width): """ Build the display of the footer - `width` - Screen Width - `height` - Screen height `alertTab` Details from the Alert tab for fonts etc """ style = """ - .alerttable { position: absolute; z-index:10; left 0px; top 0px; %s } - .alertcell { %s } - .alert { %s } - """ - style2 = """ - #alert {position: absolute; z-index:10; left 0px; top 0px; width: %spx; %s %s} + width: %s; + vertical-align: %s; + font-family %s; + font-size: %spx; + color: %s; + background-color: %s; """ - alerttable = u'' - alertcell = u'' - alert = u'' - if alertTab: - if alertTab.location == 2: - alertcell = u'vertical-align:bottom;' - elif alertTab.location == 1: - alertcell = u'vertical-align:middle;' - else: - alertcell = u'vertical-align:top;' - alerttable = u'width: %spx; height: %spx; ' % (width, height) - alert = u'font-family %s; font-size: %spx; color: %s; ' \ - u'background-color: %s' % \ - (alertTab.font_face, alertTab.font_size, alertTab.font_color, - alertTab.bg_color) - #alert_html = style % (alerttable, alertcell, alert) - alert_html = style2 % (width, alertcell, alert) - print alert_html - return alert_html + 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, + alertTab.font_color, alertTab.bg_color) + return alert === modified file 'openlp/core/ui/maindisplay.py' --- openlp/core/ui/maindisplay.py 2010-08-07 13:37:10 +0000 +++ openlp/core/ui/maindisplay.py 2010-08-20 18:26:42 +0000 @@ -113,7 +113,7 @@ self.page = self.webView.page() self.frame = self.page.mainFrame() QtCore.QObject.connect(self.webView, - QtCore.SIGNAL(u'loadFinished(bool)'), self.loaded) + QtCore.SIGNAL(u'loadFinished(bool)'), self.isLoaded) self.frame.setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff) self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal, @@ -162,11 +162,11 @@ The slide text to be displayed """ log.debug(u'text') - self.frame.evaluateJavaScript("startfade('" + - slide.replace("\\", "\\\\").replace("\'", "\\\'") + "')") + self.frame.evaluateJavaScript(u'show_text("%s")' % \ + slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) return self.preview() - def alert(self, text, shrink=False): + def alert(self, text): """ Add the alert text @@ -174,15 +174,22 @@ The slide text to be displayed """ log.debug(u'alert') - js = "displayAlert('" + \ - text.replace("\\", "\\\\").replace("\'", "\\\'") + "', %s)" % \ - ('true' if shrink else 'false') + if self.height() != self.screen[u'size'].height() \ + or not self.isVisible(): + shrink = True + else: + shrink = False + js = u'show_alert("%s", "%s")' % ( + text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'), + u'top' if shrink else u'') height = self.frame.evaluateJavaScript(js) if shrink: if text: self.resize(self.width(), int(height.toString())) + self.setVisible(True) else: self.setGeometry(self.screen[u'size']) + self.setVisible(False) def image(self, image): """ @@ -203,10 +210,10 @@ Display an image, as is. """ if image: - js = "setImage('" + \ - u'data:image/png;base64,%s' % image_to_byte(image) + "');" + js = u'show_image("data:image/png;base64,%s");' % \ + image_to_byte(image) else: - js = "setImage('');" + js = u'show_image("");' self.frame.evaluateJavaScript(js) def resetImage(self): @@ -222,35 +229,35 @@ Used after Video plugin has changed the background """ log.debug(u'resetVideo') - self.frame.evaluateJavaScript('video("close");') + self.frame.evaluateJavaScript(u'show_video("close");') def videoPlay(self): """ Responds to the request to play a loaded video """ log.debug(u'videoPlay') - self.frame.evaluateJavaScript('video("play");') + self.frame.evaluateJavaScript(u'show_video("play");') def videoPause(self): """ Responds to the request to pause a loaded video """ log.debug(u'videoPause') - self.frame.evaluateJavaScript('video("pause");') + self.frame.evaluateJavaScript(u'show_video("pause");') def videoStop(self): """ Responds to the request to stop a loaded video """ log.debug(u'videoStop') - self.frame.evaluateJavaScript('video("stop");') + self.frame.evaluateJavaScript(u'show_video("stop");') def videoVolume(self, volume): """ Changes the volume of a running video """ log.debug(u'videoVolume %d' % volume) - self.frame.evaluateJavaScript('video(null,null,%s);' % + self.frame.evaluateJavaScript(u'show_video(null, null, %s);' % str(float(volume)/float(10))) def video(self, videoPath, volume): @@ -259,13 +266,12 @@ """ log.debug(u'video') self.loaded = True - js = 'video("play","%s",%s,true);' % \ - (videoPath.replace("\\", "\\\\"), str(float(volume)/float(10))) + js = u'show_video("play", "%s", %s, true);' % \ + (videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10))) self.frame.evaluateJavaScript(js) - print js return self.preview() - def loaded(self): + def isLoaded(self): """ Called by webView event to show display is fully loaded """ @@ -280,7 +286,7 @@ # Wait for the fade to finish before geting the preview. # Important otherwise preview will have incorrect text if at all ! if self.serviceItem.themedata.display_slideTransition: - while self.frame.evaluateJavaScript("fadeFinished()").toString() == u'false': + while self.frame.evaluateJavaScript(u'show_text_complete()').toString() == u'false': Receiver.send_message(u'openlp_process_events') # Wait for the webview to update before geting the preview. # Important otherwise first preview will miss the background ! @@ -295,7 +301,7 @@ painter.end() # save preview for debugging if log.isEnabledFor(logging.DEBUG): - preview.save("temp.png", "png") + preview.save(u'temp.png', u'png') return preview def buildHtml(self, serviceItem): @@ -310,7 +316,13 @@ html = build_html(self.serviceItem, self.screen, self.parent.alertTab) self.webView.setHtml(html) if serviceItem.footer and serviceItem.foot_text: - self.frame.findFirstElement('div#footer').setInnerXml(serviceItem.foot_text) + self.footer(serviceItem.foot_text) + + def footer(self, text): + log.debug(u'footer') + js = "show_footer('" + \ + text.replace("\\", "\\\\").replace("\'", "\\\'") + "')" + self.frame.evaluateJavaScript(js) def hideDisplay(self, mode=HideMode.Screen): """ @@ -318,15 +330,13 @@ Store the images so they can be replaced when required """ log.debug(u'hideDisplay mode = %d', mode) - self.frame.evaluateJavaScript( - "document.getElementById('blank').style.visibility = 'visible'") if mode == HideMode.Screen: - self.frame.evaluateJavaScript('blankState("desktop");') + self.frame.evaluateJavaScript(u'show_blank("desktop");') self.setVisible(False) elif mode == HideMode.Blank or self.initialFrame: - self.frame.evaluateJavaScript('blankState("black");') + self.frame.evaluateJavaScript(u'show_blank("black");') else: - self.frame.evaluateJavaScript('blankState("theme");') + self.frame.evaluateJavaScript(u'show_blank("theme");') if mode != HideMode.Screen and self.isHidden(): self.setVisible(True) @@ -337,7 +347,7 @@ Make the stored images None to release memory. """ log.debug(u'showDisplay') - self.frame.evaluateJavaScript('blankState("show");') + self.frame.evaluateJavaScript('show_blank("show");') if self.isHidden(): self.setVisible(True) # Trigger actions when display is active again
_______________________________________________ Mailing list: https://launchpad.net/~openlp-core Post to : openlp-core@lists.launchpad.net Unsubscribe : https://launchpad.net/~openlp-core More help : https://help.launchpad.net/ListHelp