openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #26634
[Merge] lp:~marmyshev/openlp/transitions into lp:openlp
Dmitriy Marmyshev has proposed merging lp:~marmyshev/openlp/transitions into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
Related bugs:
Bug #763067 in OpenLP: "Transition is not used when "blanking to ...""
https://bugs.launchpad.net/openlp/+bug/763067
Bug #1080604 in OpenLP: "Transitions works not smoothly"
https://bugs.launchpad.net/openlp/+bug/1080604
For more details, see:
https://code.launchpad.net/~marmyshev/openlp/transitions/+merge/256730
New transition system. New effects, added transitions for background, images and blanking.
no tests.
just to review all changes.
--
Your team OpenLP Core is requested to review the proposed merge of lp:~marmyshev/openlp/transitions into lp:openlp.
=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py 2015-02-21 13:08:56 +0000
+++ openlp/core/common/settings.py 2015-04-18 08:51:32 +0000
@@ -296,6 +296,7 @@
'themes/last directory export': '',
'themes/last directory import': '',
'themes/theme level': ThemeLevel.Song,
+ 'themes/background transitions': '',
'themes/wrap footer': False,
'user interface/live panel': True,
'user interface/live splitter geometry': QtCore.QByteArray(),
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2015-04-02 09:04:56 +0000
+++ openlp/core/lib/__init__.py 2015-04-18 08:51:32 +0000
@@ -323,7 +323,8 @@
from .pluginmanager import PluginManager
from .settingstab import SettingsTab
from .serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
-from .htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css
+from .htmlbuilder import build_html_display, build_lyrics_format_css, build_lyrics_outline_css, build_html_text, \
+ build_html_image, build_html_background, build_html_footer
from .toolbar import OpenLPToolbar
from .dockwidget import OpenLPDockWidget
from .imagemanager import ImageManager
@@ -332,3 +333,4 @@
from .projector.db import ProjectorDB, Projector
from .projector.pjlink1 import PJLink1
from .projector.constants import PJLINK_PORT, ERROR_MSG, ERROR_STRING
+from .transitions import TransitionType
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py 2015-01-18 13:39:21 +0000
+++ openlp/core/lib/htmlbuilder.py 2015-04-18 08:51:32 +0000
@@ -9,12 +9,12 @@
# 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 #
@@ -409,9 +409,7 @@
overflow: hidden;
-webkit-user-select: none;
}
-body {
- %s;
-}
+body {}
.size {
position: absolute;
left: 0px;
@@ -420,9 +418,7 @@
height: 100%%;
}
#black {
- z-index: 8;
background-color: black;
- display: none;
}
#bgimage {
z-index: 1;
@@ -430,125 +426,363 @@
#image {
z-index: 2;
}
-%s
+/* %css_additions% */
#footer {
- position: absolute;
z-index: 6;
- %s
}
-/* lyric css */
-%s
sup {
font-size: 0.6em;
vertical-align: top;
position: relative;
top: -0.3em;
}
+
+#screen{
+ left: 0px;
+ top: 0px;
+ height: %height%px;
+ width: %width%px;
+ overflow:hidden;
+ position:relative;
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+.background_frame{
+ z-index: 1;
+ height: %height%px;
+ width: %width%px;
+ position:absolute;
+ overflow:hidden;
+ margin:0;
+ padding:0;
+ border:0;
+}
+.frame{
+ z-index: 8;
+ height: %height%px;
+ width: %width%px;
+ position:absolute;
+ overflow:hidden;
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
</style>
<script>
- var timer = null;
- var transition = %s;
- %s
-
- function show_image(src){
- var img = document.getElementById('image');
- img.src = src;
- if(src == '')
- img.style.display = 'none';
- else
- img.style.display = 'block';
- }
-
- function show_blank(state){
- var black = 'none';
- var lyrics = '';
- switch(state){
- case 'theme':
- lyrics = 'hidden';
- break;
- case 'black':
- black = 'block';
- break;
- case 'desktop':
- break;
- }
- document.getElementById('black').style.display = black;
- document.getElementById('lyricsmain').style.visibility = lyrics;
- document.getElementById('image').style.visibility = lyrics;
- document.getElementById('footer').style.visibility = lyrics;
- }
-
- function show_footer(footertext){
- document.getElementById('footer').innerHTML = footertext;
- }
-
- function show_text(new_text){
- var match = /-webkit-text-fill-color:[^;\"]+/gi;
- if(timer != null)
- clearTimeout(timer);
- /*
- QtWebkit bug with outlines and justify causing outline alignment
- problems. (Bug 859950) Surround each word with a <span> to workaround,
- but only in this scenario.
- */
- var txt = document.getElementById('lyricsmain');
- if(window.getComputedStyle(txt).textAlign == 'justify'){
- if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
- new_text = new_text.replace(/(\s| )+(?![^<]*>)/g,
- function(match) {
- return '</span>' + match + '<span>';
- });
- new_text = '<span>' + new_text + '</span>';
- }
- }
- text_fade('lyricsmain', new_text);
- }
-
- function text_fade(id, new_text){
- /*
- Show the text.
- */
- var text = document.getElementById(id);
- if(text == null) return;
- if(!transition){
- text.innerHTML = new_text;
- return;
- }
- // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
- text.style.opacity = '0.1';
- // Fade new text in after the old text has finished fading out.
- timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
- }
-
- function _show_text(text, new_text) {
- /*
- Helper function to show the new_text delayed.
- */
- text.innerHTML = new_text;
- text.style.opacity = '1';
- // Wait until the text is completely visible. We want to save the timer id, to be able to call
- // clearTimeout(timer) when the text has changed before finishing fading.
- timer = window.setTimeout(function(){timer = null;}, 400);
+ var current_frame_id = 'frame1';
+ var next_frame_id = 'frame2';
+ var current_bg_frame_id = 'bg_frame1';
+ var next_bg_frame_id = 'bg_frame2';
+ var width = %width%;
+ var height = %height%;
+ var frame_timer = null;
+ var bg_timer = null;
+ var transition = 'None';
+ var bg_transition = 'None';
+ %js_additions%
+
+
+ function get_next_frame_id(background){
+ if(background == undefined) background = false;
+ if(background){
+ return next_bg_frame_id;
+ }else{
+ return next_frame_id;
+ }
+ }
+
+ function get_transition(background){
+ if(background == undefined) background = false;
+ if(background){
+ return bg_transition;
+ }else{
+ return transition;
+ }
+ }
+
+ function set_transition(value, background){
+ if(value == undefined) value = 'None';
+ if(background == undefined) background = false;
+ if(background){
+ bg_transition = value;
+ }else{
+ transition = value;
+ }
+ }
+
+ function show_next(background){
+ /*
+ Show next frame of content or background
+ */
+ var current_frame = document.getElementById(current_frame_id);
+ var next_frame = document.getElementById(next_frame_id);
+ var animation_effect = transition;
+ if(background == undefined) background = false;
+ if(background){
+ current_frame = document.getElementById(current_bg_frame_id);
+ next_frame = document.getElementById(next_bg_frame_id);
+ animation_effect = bg_transition;
+ }
+ if(frame_timer != null && !background)
+ clearTimeout(frame_timer);
+ if(bg_timer != null && background)
+ clearTimeout(bg_timer);
+ current_frame.style.opacity = 1;
+ next_frame.style.opacity = 0;
+ switch(animation_effect){
+ case 'FadeOutFadeIn':
+ animation_fadeoutin(background, current_frame, next_frame, 100);
+ change_frames(background);
+ break;
+ case 'FadeIn':
+ animation_fadein(background, current_frame, next_frame, 100);
+ change_frames(background);
+ break;
+ case 'CrossFade':
+ animation_crossfade(background, current_frame, next_frame, 100);
+ change_frames(background);
+ break;
+ case 'MoveLeft':
+ animation_move(background, current_frame, next_frame, 1, 'left');
+ change_frames(background);
+ break;
+ case 'MoveRight':
+ animation_move(background, current_frame, next_frame, 1, 'right');
+ change_frames(background);
+ break;
+ case 'MoveUp':
+ animation_move(background, current_frame, next_frame, 1, 'top');
+ change_frames(background);
+ break;
+ case 'MoveDown':
+ animation_move(background, current_frame, next_frame, 1, 'bottom');
+ change_frames(background);
+ break;
+ default:
+ no_animation(current_frame, next_frame);
+ change_frames(background);
+ }
+ }
+
+ function change_frames(background){
+ if(background){
+ var temp = current_bg_frame_id;
+ current_bg_frame_id = next_bg_frame_id;
+ next_bg_frame_id = temp;
+ }else{
+ var temp = current_frame_id;
+ current_frame_id = next_frame_id;
+ next_frame_id = temp;
+ }
+ }
+
+ function no_animation(current_frame, next_frame){
+ current_frame.style.opacity = 0;
+ next_frame.style.opacity = 1;
+ }
+
+ function animation_fadeoutin(background, current_frame, next_frame, delay){
+ /*
+ Animation at first fade out current frame, then fade in next frame
+ */
+ if(parseFloat(current_frame.style.opacity) > 0.2){
+ current_frame.style.opacity = parseFloat(current_frame.style.opacity) - 0.1;
+ if(background){
+ bg_timer = window.setTimeout(function(){animation_fadeoutin(background, current_frame, next_frame, delay)}, delay);;
+ }else{
+ frame_timer = window.setTimeout(function(){animation_fadeoutin(background, current_frame, next_frame, delay)}, delay);;
+ }
+ return;
+ }else if(parseFloat(next_frame.style.opacity) <= 1){
+ next_frame.style.opacity = parseFloat(next_frame.style.opacity) + 0.1;
+ if(background){
+ bg_timer = window.setTimeout(function(){animation_fadeoutin(background, current_frame, next_frame, delay)}, delay);;
+ }else{
+ frame_timer = window.setTimeout(function(){animation_fadeoutin(background, current_frame, next_frame, delay)}, delay);;
+ }
+ return;
+ }
+ current_frame.style.opacity = 0;
+ if(background){
+ bg_timer = null;
+ }else{
+ frame_timer = null;
+ }
+ }
+
+ function animation_fadein(background, current_frame, next_frame, delay){
+ /*
+ Animation fade in next frame, and then hide current
+ */
+ if(parseFloat(next_frame.style.opacity) <= 1){
+ next_frame.style.opacity = parseFloat(next_frame.style.opacity) + 0.1;
+ if(background){
+ bg_timer = window.setTimeout(function(){animation_fadein(background, current_frame, next_frame, delay)}, delay);;
+ }else{
+ frame_timer = window.setTimeout(function(){animation_fadein(background, current_frame, next_frame, delay)}, delay);;
+ }
+ return;
+ }
+ current_frame.style.opacity = '0';
+ if(background){
+ bg_timer = null;
+ }else{
+ frame_timer = null;
+ }
+ }
+
+
+ function animation_crossfade(background, current_frame, next_frame, delay){
+ /*
+ Animation at first fade out current frame, then fade in next frame
+ */
+ var current_opacity = parseFloat(current_frame.style.opacity);
+ var next_opacity = parseFloat(next_frame.style.opacity);
+ if(next_opacity < 1 || current_opacity >= 0.2){
+ if(next_opacity > 0.5){
+ current_frame.style.opacity = current_opacity - 0.1;
+ }
+ if(next_opacity < 1){
+ next_frame.style.opacity = next_opacity + 0.1;
+ }
+ if(background){
+ bg_timer = window.setTimeout(function(){animation_crossfade(background, current_frame, next_frame, delay)}, delay);
+ }else{
+ frame_timer = window.setTimeout(function(){animation_crossfade(background, current_frame, next_frame, delay)}, delay);
+ }
+
+ return;
+ }
+ current_frame.style.opacity = 0;
+ if(background){
+ bg_timer = null;
+ }else{
+ frame_timer = null;
+ }
+ }
+
+ function animation_move(background, current_frame, next_frame, delay, direction){
+ /*
+ Animation move current frame and next frame from right to left
+ */
+ var speed = 1;
+ var move = 0;
+ switch(direction){
+ case 'left':
+ speed = parseInt(width/10);
+ if(current_frame.style.left == '' || parseInt(current_frame.style.left) == 0){
+ next_frame.style.left = width + 'px';
+ current_frame.style.left = '0px';
+ }
+ move = parseInt(next_frame.style.left) - speed;
+ break;
+ case 'right':
+ speed = parseInt(width/10);
+ if(current_frame.style.right == '' || parseInt(current_frame.style.right) == 0){
+ next_frame.style.right = width + 'px';
+ current_frame.style.right = '0px';
+ }
+ move = parseInt(next_frame.style.right) - speed;
+ break;
+ case 'top':
+ speed = parseInt(height/10);
+ if(current_frame.style.top == '' || parseInt(current_frame.style.top) == 0){
+ next_frame.style.top = height + 'px';
+ current_frame.style.top = '0px';
+ }
+ move = parseInt(next_frame.style.top) - speed;
+ break;
+ case 'bottom':
+ speed = parseInt(height/10);
+ if(current_frame.style.bottom == '' || parseInt(current_frame.style.bottom) == 0){
+ next_frame.style.bottom = height + 'px';
+ current_frame.style.bottom = '0px';
+ }
+ move = parseInt(next_frame.style.bottom) - speed;
+ break;
+ }
+ next_frame.style.opacity = '1';
+ current_frame.style.opacity = '1';
+
+ if(move < 0){
+ move = 0;
+ }
+ switch(direction){
+ case 'left':
+ next_frame.style.left = move + 'px';
+ current_frame.style.left = parseInt(current_frame.style.left) - speed + 'px';
+ break;
+ case 'right':
+ next_frame.style.right = move + 'px';
+ current_frame.style.right = parseInt(current_frame.style.right) - speed + 'px';
+ break;
+ case 'top':
+ next_frame.style.top = move + 'px';
+ current_frame.style.top = parseInt(current_frame.style.top) - speed + 'px';
+ break;
+ case 'bottom':
+ next_frame.style.bottom = move + 'px';
+ current_frame.style.bottom = parseInt(current_frame.style.bottom) - speed + 'px';
+ break;
+ }
+ if(move > 0){
+ if(background){
+ bg_timer = window.setTimeout(function(){animation_move(background, current_frame, next_frame, delay, direction)}, delay);
+ }else{
+ frame_timer = window.setTimeout(function(){animation_move(background, current_frame, next_frame, delay, direction)}, delay);
+ }
+ return;
+ }
+ if(background){
+ bg_timer = null;
+ }else{
+ frame_timer = null;
+ }
+ current_frame.style.opacity = '0';
+ current_frame.style.left = '';
+ current_frame.style.right = '';
+ current_frame.style.top = '';
+ current_frame.style.bottom = '';
+ next_frame.style.left = '';
+ next_frame.style.right = '';
+ next_frame.style.top = '';
+ next_frame.style.bottom = '';
}
function show_text_completed(){
- return (timer == null);
+ return (frame_timer == null && bg_timer == null);
}
+
</script>
+
+
</head>
<body>
-<img id="bgimage" class="size" %s />
-<img id="image" class="size" %s />
-%s
-<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
-<div id="footer" class="footer"></div>
-<div id="black" class="size"></div>
+
+<div id="screen">
+<div class="background_frame" id="bg_frame1" style="opacity: 1;"></div>
+<div class="background_frame" id="bg_frame2" style="opacity: 0;"></div>
+<div id="footer"></div>
+<div class="frame" id="frame1" style="opacity: 1;"></div>
+<div class="frame" id="frame2" style="opacity: 0;"></div>
+</div>
+
</body>
</html>
"""
-
-def build_html(item, screen, is_live, background, image=None, plugins=None):
+HTML_BACKGROUND_SRC = """<div class="size" style="%background_css%;">%bg_content%</div>"""
+
+HTML_FOOTER_SRC = """<div style="%footer_css%;">%text%</div>"""
+
+HTML_LYRICS_SRC = """<div class="lyricstable" style="%lyricstable_css%;"><div id="lyricsmain"
+style="opacity:1;%lyricsmain_css%;" class="lyricscell lyricsmain">%slide%</div></div>
+"""
+
+HTML_IMAGE_SRC = """<img id="image" class="size" %image_src% />"""
+
+def build_html_display(item, screen, is_live, background, image=None, plugins=None):
"""
Build the full web paged structure for display
@@ -561,18 +795,6 @@
"""
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 = ''
@@ -581,17 +803,69 @@
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
- )
+ html = HTMLSRC
+ html = html.replace('%width%', str(width))
+ html = html.replace('%height%', str(height))
+ html = html.replace('%css_additions%', css_additions)
+ html = html.replace('%js_additions%', js_additions)
+ html = html.replace('%html_additions%', html_additions)
+ return html
+
+
+def build_html_background(item, screen, background, image=None):
+ """
+ Build the content for text frame
+
+ :param item: Service Item to be displayed
+ :param screen: Current display information
+ """
+ width = screen['size'].width()
+ html = HTML_BACKGROUND_SRC
+ if background:
+ bg_content = build_html_image(background)
+ elif item.bg_image_bytes:
+ bg_content = build_html_image(item.bg_image_bytes)
+ else:
+ bg_content = ''
+ if image:
+ bg_content = build_html_image(image)
+ html = html.replace('%bg_content%', bg_content)
+ html = html.replace('%background_css%', build_background_css(item, width))
+ return html
+
+
+def build_html_footer(item, screen, text):
+ """
+ Build the content for text frame
+
+ :param slide: html content of slide
+ """
+ height = screen['size'].height()
+ html = HTML_FOOTER_SRC.replace('%text%', text)
+ html = html.replace('%footer_css%', build_footer_css(item, height))
+ return html
+
+
+def build_html_text(item, slide):
+ """
+ Build the content for text frame
+
+ :param slide: html content of slide
+ """
+ css = build_lyrics_css(item)
+ html = HTML_LYRICS_SRC.replace('%slide%', slide)
+ html = html.replace('%lyricstable_css%', css['lyricstable'])
+ html = html.replace('%lyricsmain_css%', css['lyricsmain'])
+ return html
+
+
+def build_html_image(image):
+ """
+ Build the content for text frame
+
+ :param slide: html content of slide
+ """
+ html = HTML_IMAGE_SRC.replace('%image_src%', 'src="data:image/png;base64,%s" ' % image)
return html
@@ -625,19 +899,19 @@
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)
+ % (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)
+ % (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)
+ % (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)
+ (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)
+ 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
@@ -647,36 +921,21 @@
: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
-}
-"""
+ if hasattr(item, 'css'):
+ return item.css
theme_data = item.theme_data
- lyricstable = ''
- lyrics = ''
- lyricsmain = ''
+ lyricstable_css = 'z-index: 5; position: absolute; display: table;'
+ lyricsmain_css = 'display: table-cell; word-wrap: break-word; -webkit-transition: opacity 0.4s ease;'
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)
+ lyricstable_css += 'left: %spx; top: %spx;' % (item.main.x(), item.main.y())
+ lyricsmain_css += build_lyrics_format_css(theme_data, item.main.width(), item.main.height())
+ lyricsmain_css += 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
+ lyricsmain_css += ' text-shadow: %s %spx %spx;' % \
+ (theme_data.font_main_shadow_color, theme_data.font_main_shadow_size,
+ theme_data.font_main_shadow_size)
+ item.css = {'lyricstable': lyricstable_css, 'lyricsmain': lyricsmain_css}
+ return item.css
def build_lyrics_outline_css(theme_data):
@@ -719,9 +978,9 @@
'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)
+ (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:
@@ -737,6 +996,8 @@
:param height:
"""
style = """
+ position: absolute;
+ z-index: 6;
left: %spx;
bottom: %spx;
width: %spx;
@@ -748,7 +1009,7 @@
"""
theme = item.theme_data
if not theme or not item.footer:
- return ''
+ return 'position: absolute;'
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(),
=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py 2015-01-18 13:39:21 +0000
+++ openlp/core/lib/renderer.py 2015-04-18 08:51:32 +0000
@@ -213,7 +213,7 @@
service_item.footer = footer
service_item.render(True)
if not self.force_page:
- self.display.build_html(service_item)
+ self.display.show_background(service_item)
raw_html = service_item.get_rendered_frame(0)
self.display.text(raw_html, False)
preview = self.display.preview()
=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py 2015-01-18 13:39:21 +0000
+++ openlp/core/lib/theme.py 2015-04-18 08:51:32 +0000
@@ -140,7 +140,7 @@
Names = ['top', 'middle', 'bottom']
-BOOLEAN_LIST = ['bold', 'italics', 'override', 'outline', 'shadow', 'slide_transition']
+BOOLEAN_LIST = ['bold', 'italics', 'override', 'outline', 'shadow']
INTEGER_LIST = ['size', 'line_adjustment', 'x', 'height', 'y', 'width', 'shadow_size', 'outline_size',
'horizontal_align', 'vertical_align', 'wrap_style']
=== added file 'openlp/core/lib/transitions.py'
--- openlp/core/lib/transitions.py 1970-01-01 00:00:00 +0000
+++ openlp/core/lib/transitions.py 2015-04-18 08:51:32 +0000
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2015 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 #
+###############################################################################
+"""
+The :mod:`transitions` module provides management functionality for a transitions
+of text on main display.
+"""
+
+import logging
+
+
+log = logging.getLogger(__name__)
+
+
+class TransitionType(object):
+ """
+ Type enumeration for transitions on main display.
+ """
+ NoTransition = 0
+ FadeOutFadeIn = 1
+ CrossFade = 2
+ FadeIn = 3
+ MoveLeft = 4
+ MoveRight = 5
+ MoveUp = 6
+ MoveDown = 7
+
+ Names = ['No transition', 'Fade-out-Fade-in', 'Cross Fade', 'Fade-in', 'Move-left', 'Move-right', 'Move-Up',
+ 'Move-down']
+
+ @staticmethod
+ def to_string(transition_type):
+ """
+ Return a string representation of a transition type.
+ """
+ if transition_type == TransitionType.NoTransition:
+ return 'NoTransition'
+ elif transition_type == TransitionType.FadeOutFadeIn:
+ return 'FadeOutFadeIn'
+ elif transition_type == TransitionType.CrossFade:
+ return 'CrossFade'
+ elif transition_type == TransitionType.FadeIn:
+ return 'FadeIn'
+ elif transition_type == TransitionType.MoveLeft:
+ return 'MoveLeft'
+ elif transition_type == TransitionType.MoveRight:
+ return 'MoveRight'
+ elif transition_type == TransitionType.MoveUp:
+ return 'MoveUp'
+ elif transition_type == TransitionType.MoveDown:
+ return 'MoveDown'
+
+
+ @staticmethod
+ def from_string(type_string):
+ """
+ Return a transition type for the given string.
+ """
+ if type_string == 'NoTransition' or type_string == 'False':
+ return TransitionType.NoTransition
+ elif type_string == 'FadeOutFadeIn' or type_string == 'True':
+ return TransitionType.FadeOutFadeIn
+ elif type_string == 'CrossFade':
+ return TransitionType.CrossFade
+ elif type_string == 'FadeIn':
+ return TransitionType.FadeIn
+ elif type_string == 'MoveLeft':
+ return TransitionType.MoveLeft
+ elif type_string == 'MoveRight':
+ return TransitionType.MoveRight
+ elif type_string == 'MoveUp':
+ return TransitionType.MoveUp
+ elif type_string == 'MoveDown':
+ return TransitionType.MoveDown
+ else:
+ return TransitionType.NoTransition
\ No newline at end of file
=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py 2015-04-02 20:32:20 +0000
+++ openlp/core/ui/maindisplay.py 2015-04-18 08:51:32 +0000
@@ -41,7 +41,8 @@
PHONON_AVAILABLE = False
from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, Settings, translate, is_macosx
-from openlp.core.lib import ServiceItem, ImageSource, ScreenList, build_html, expand_tags, image_to_byte
+from openlp.core.lib import ServiceItem, ImageSource, ScreenList, build_html_display, build_html_text, build_html_image,\
+ build_html_background, build_html_footer, expand_tags, image_to_byte
from openlp.core.lib.theme import BackgroundType
from openlp.core.ui import HideMode, AlertLocation
@@ -141,6 +142,8 @@
self.screens = ScreenList()
self.rebuild_css = False
self.hide_mode = None
+ self.current_raw_frame = None
+ self.current_background = None
self.override = {}
self.retranslateUi()
self.media_object = None
@@ -218,30 +221,13 @@
self.screen = self.screens.current
self.setVisible(False)
Display.setup(self)
+ service_item = ServiceItem()
+ self.web_view.setHtml(build_html_display(service_item, self.screen, self.is_live, None,
+ plugins=self.plugin_manager.plugins))
if self.is_live:
- # Build the initial frame.
- background_color = QtGui.QColor()
- background_color.setNamedColor(Settings().value('advanced/default color'))
- if not background_color.isValid():
- background_color = QtCore.Qt.white
- image_file = Settings().value('advanced/default image')
- splash_image = QtGui.QImage(image_file)
- self.initial_fame = QtGui.QImage(
- self.screen['size'].width(),
- self.screen['size'].height(),
- QtGui.QImage.Format_ARGB32_Premultiplied)
- painter_image = QtGui.QPainter()
- painter_image.begin(self.initial_fame)
- painter_image.fillRect(self.initial_fame.rect(), background_color)
- painter_image.drawImage(
- (self.screen['size'].width() - splash_image.width()) // 2,
- (self.screen['size'].height() - splash_image.height()) // 2,
- splash_image)
- service_item = ServiceItem()
- service_item.bg_image_bytes = image_to_byte(self.initial_fame)
- self.web_view.setHtml(build_html(service_item, self.screen, self.is_live, None,
- plugins=self.plugin_manager.plugins))
self._hide_mouse()
+ self.set_background_transitions()
+ self.show_logoscreen()
def text(self, slide, animate=True):
"""
@@ -250,19 +236,21 @@
:param slide: The slide text to be displayed
:param animate: Perform transitions if applicable when setting the text
"""
+ if self.current_raw_frame == slide:
+ return
+ self.current_raw_frame = slide
# Wait for the webview to update before displaying text.
+ # FIXME: change to show_complete() JS
while not self.web_loaded:
self.application.process_events()
self.setGeometry(self.screen['size'])
- if animate:
- self.frame.evaluateJavaScript('show_text("%s")' % slide.replace('\\', '\\\\').replace('\"', '\\\"'))
- else:
- # This exists for https://bugs.launchpad.net/openlp/+bug/1016843
- # For unknown reasons if evaluateJavaScript is called
- # from the themewizard, then it causes a crash on
- # Windows if there are many items in the service to re-render.
- # Setting the div elements direct seems to solve the issue
- self.frame.findFirstElement("#lyricsmain").setInnerXml(slide)
+ html = build_html_text(self.service_item, slide)
+ next_frame_id = self.frame.evaluateJavaScript('get_next_frame_id();')
+ if not next_frame_id:
+ next_frame_id = 'frame1'
+ self.frame.findFirstElement('#'+next_frame_id).setInnerXml(html)
+ if not self.hide_mode:
+ self.frame.evaluateJavaScript('show_next();')
def alert(self, text, location):
"""
@@ -306,7 +294,7 @@
return False
self.override['image'] = path
self.override['theme'] = self.service_item.theme_data.background_filename
- self.image(path)
+ self.show_background(self.service_item)
# Update the preview frame.
if self.is_live:
self.live_controller.update_preview()
@@ -320,6 +308,9 @@
:param path: The path to the image to be displayed. **Note**, the path is only passed to identify the image.
If the image has changed it has to be re-added to the image manager.
"""
+ if self.current_raw_frame == path:
+ return
+ self.current_raw_frame = path
image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin)
self.controller.media_controller.media_reset(self.controller)
self.display_image(image)
@@ -332,10 +323,15 @@
"""
self.setGeometry(self.screen['size'])
if image:
- js = 'show_image("data:image/png;base64,%s");' % image
+ html = build_html_image(image)
else:
- js = 'show_image("");'
- self.frame.evaluateJavaScript(js)
+ html = ''
+ next_frame_id = self.frame.evaluateJavaScript('get_next_frame_id()')
+ if not next_frame_id:
+ next_frame_id = 'frame1'
+ self.frame.findFirstElement('#'+next_frame_id).setInnerXml(html)
+ if not self.hide_mode:
+ self.frame.evaluateJavaScript('show_next()')
def reset_image(self):
"""
@@ -358,11 +354,11 @@
was_visible = self.isVisible()
self.application.process_events()
# We must have a service item to preview.
- if self.is_live and hasattr(self, 'service_item'):
+ if self.is_live and hasattr(self, 'service_item') and not self.hide_mode:
# Wait for the fade to finish before geting the preview.
# Important otherwise preview will have incorrect text if at all!
if self.service_item.theme_data and self.service_item.theme_data.display_slide_transition:
- while not self.frame.evaluateJavaScript('show_text_completed()'):
+ while not self.frame.evaluateJavaScript('show_text_completed();'):
self.application.process_events()
# Wait for the webview to update before getting the preview.
# Important otherwise first preview will miss the background !
@@ -383,14 +379,13 @@
self.setVisible(True)
return QtGui.QPixmap.grabWidget(self)
- def build_html(self, service_item, image_path=''):
+ def show_background(self, service_item, image_path=''):
"""
Store the service_item and build the new HTML from it. Add the HTML to the display
:param service_item: The Service item to be used
:param image_path: Where the image resides.
"""
- self.web_loaded = False
self.initial_fame = None
self.service_item = service_item
background = None
@@ -407,8 +402,7 @@
else:
# replace the background
background = self.image_manager.get_image_bytes(self.override['image'], ImageSource.ImagePlugin)
- self.set_transparency(self.service_item.theme_data.background_type ==
- BackgroundType.to_string(BackgroundType.Transparent))
+ self.set_transparency(self.is_live)
if self.service_item.theme_data.background_filename:
self.service_item.bg_image_bytes = self.image_manager.get_image_bytes(
self.service_item.theme_data.background_filename, ImageSource.Theme)
@@ -416,9 +410,27 @@
image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
else:
image_bytes = None
- html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes,
- plugins=self.plugin_manager.plugins)
- self.web_view.setHtml(html)
+ if self.current_background != image_path \
+ and self.current_background != self.service_item.theme_data.background_filename:
+ if image_path:
+ self.current_background = image_path
+ elif self.service_item.theme_data.background_filename:
+ self.current_background = self.service_item.theme_data.background_filename
+ else:
+ self.current_background = None
+ if self.service_item.theme_data.background_type == BackgroundType.to_string(BackgroundType.Transparent):
+ html = ''
+ else:
+ html = build_html_background(self.service_item, self.screen, background, image_bytes)
+ next_frame_id = self.frame.evaluateJavaScript('get_next_frame_id(true);')
+ if not next_frame_id:
+ next_frame_id = 'bg_frame1'
+ self.frame.findFirstElement('#'+next_frame_id).setInnerXml(html)
+ self.frame.evaluateJavaScript('show_next(true);')
+ # FIXME: reset self.current_raw_frame if we change theme
+ self.current_raw_frame = None
+ if self.is_live:
+ self.set_transitions(self.service_item)
if service_item.foot_text:
self.footer(service_item.foot_text)
# if was hidden keep it hidden
@@ -429,14 +441,45 @@
self.hide_display(self.hide_mode)
self._hide_mouse()
+ def set_background_transitions(self):
+ """
+ set transitions for changing background frames
+
+ """
+ transitions = Settings().value('themes/background transitions')
+ self.frame.evaluateJavaScript('set_transition(\''+transitions+'\',true);')
+
+ def set_transitions(self, item):
+ """
+ set transitions for changing screen frames
+
+ :param item: Service Item to be displayed
+ """
+ theme_data = item.theme_data
+ if self.is_live and theme_data and theme_data.display_slide_transition:
+ self.frame.evaluateJavaScript('set_transition(\''+theme_data.display_slide_transition+'\',false);')
+ else:
+ self.frame.evaluateJavaScript('set_transition(\'None\',false);')
+
+ def hide_background(self):
+ """
+ Display the Footer
+
+ :param text: footer text to be displayed
+ """
+ html = ''
+ next_frame_id = self.frame.evaluateJavaScript('get_next_frame_id(true)')
+ self.frame.findFirstElement('#'+next_frame_id).setInnerXml(html)
+ self.frame.evaluateJavaScript('show_next(true)')
+
def footer(self, text):
"""
Display the Footer
:param text: footer text to be displayed
"""
- js = 'show_footer(\'' + text.replace('\\', '\\\\').replace('\'', '\\\'') + '\')'
- self.frame.evaluateJavaScript(js)
+ html = build_html_footer(self.service_item, self.screen, text)
+ self.frame.findFirstElement('#footer').setInnerXml(html)
def hide_display(self, mode=HideMode.Screen):
"""
@@ -449,19 +492,71 @@
# Only make visible if setting enabled.
if not Settings().value('core/display on monitor'):
return
+ if self.hide_mode == mode:
+ return
if mode == HideMode.Screen:
- self.frame.evaluateJavaScript('show_blank("desktop");')
+ self.hide_content()
+ self.hide_background()
+ if hasattr(self, 'service_item'):
+ self.footer('')
+ # FIXME: add time counter to hide display in 10 sec anyway
+ while not self.frame.evaluateJavaScript('show_text_completed();'):
+ self.application.process_events()
self.setVisible(False)
elif mode == HideMode.Blank or self.initial_fame:
- self.frame.evaluateJavaScript('show_blank("black");')
+ self.show_blackscreen()
else:
- self.frame.evaluateJavaScript('show_blank("theme");')
+ self.hide_content()
if mode != HideMode.Screen:
if self.isHidden():
self.setVisible(True)
self.web_view.setVisible(True)
self.hide_mode = mode
+ def show_blackscreen(self):
+ """
+ Show black layer over the top of all other layers
+ """
+ html = '<div class="frame" id="black"></div>'
+ next_frame_id = self.frame.evaluateJavaScript('get_next_frame_id()')
+ self.frame.findFirstElement('#'+next_frame_id).setInnerXml(html)
+ self.frame.evaluateJavaScript('show_next()')
+
+ def show_logoscreen(self):
+ """
+ Show logo image layer over the top of all other layers
+ """
+ # Build the initial frame.
+ background_color = QtGui.QColor()
+ background_color.setNamedColor(Settings().value('advanced/default color'))
+ if not background_color.isValid():
+ background_color = QtCore.Qt.white
+ image_file = Settings().value('advanced/default image')
+ splash_image = QtGui.QImage(image_file)
+ self.initial_fame = QtGui.QImage(
+ self.screen['size'].width(),
+ self.screen['size'].height(),
+ QtGui.QImage.Format_ARGB32_Premultiplied)
+ painter_image = QtGui.QPainter()
+ painter_image.begin(self.initial_fame)
+ painter_image.fillRect(self.initial_fame.rect(), background_color)
+ painter_image.drawImage(
+ (self.screen['size'].width() - splash_image.width()) // 2,
+ (self.screen['size'].height() - splash_image.height()) // 2,
+ splash_image)
+ image = image_to_byte(self.initial_fame)
+ self.display_image(image)
+
+ def hide_content(self):
+ """
+ Hides current content on screen: text, images.
+ Background frames not hides.
+ """
+ html = ''
+ next_frame_id = self.frame.evaluateJavaScript('get_next_frame_id()')
+ self.frame.findFirstElement('#'+next_frame_id).setInnerXml(html)
+ self.frame.evaluateJavaScript('show_next()')
+
def show_display(self):
"""
Show the stored layers so the screen reappears as it was originally.
@@ -471,7 +566,14 @@
# Only make visible if setting enabled.
if not Settings().value('core/display on monitor'):
return
- self.frame.evaluateJavaScript('show_blank("show");')
+ if hasattr(self, 'service_item') and self.service_item.foot_text:
+ self.footer(self.service_item.foot_text)
+ if self.hide_mode == HideMode.Screen:
+ if hasattr(self, 'service_item'):
+ self.show_background(self.service_item)
+ if self.hide_mode:
+ # FIXME: set current self.current_raw_frame to next frame
+ self.frame.evaluateJavaScript('show_next();')
if self.isHidden():
self.setVisible(True)
self.hide_mode = None
=== modified file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py 2015-04-03 18:31:19 +0000
+++ openlp/core/ui/media/mediacontroller.py 2015-04-18 08:51:32 +0000
@@ -581,8 +581,9 @@
else:
self.media_volume(controller, controller.media_info.volume)
if status:
+ #TODO: add support for bg video
if not controller.media_info.is_background:
- display.frame.evaluateJavaScript('show_blank("desktop");')
+ display.hide_background()
self.current_media_players[controller.controller_type].set_visible(display, True)
# Flash needs to be played and will not AutoPlay
if controller.media_info.is_flash:
@@ -642,7 +643,7 @@
log.debug('media_stop')
display = self._define_display(controller)
if controller.controller_type in self.current_media_players:
- display.frame.evaluateJavaScript('show_blank("black");')
+ display.show_blackscreen()
self.current_media_players[controller.controller_type].stop(display)
self.current_media_players[controller.controller_type].set_visible(display, False)
controller.seek_slider.setSliderPosition(0)
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2015-03-18 22:02:51 +0000
+++ openlp/core/ui/slidecontroller.py 2015-04-18 08:51:32 +0000
@@ -33,7 +33,7 @@
from openlp.core.common import Registry, RegistryProperties, Settings, SlideLimits, UiStrings, translate, \
RegistryMixin, OpenLPMixin
from openlp.core.lib import OpenLPToolbar, ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, \
- ScreenList, build_icon, build_html
+ ScreenList, build_icon, build_html_display
from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType
from openlp.core.lib.ui import create_action
from openlp.core.utils.actions import ActionList, CategoryOrder
@@ -592,7 +592,7 @@
self.preview_widget.screen_size_changed(self.ratio)
self.preview_display.setup()
service_item = ServiceItem()
- self.preview_display.web_view.setHtml(build_html(service_item, self.preview_display.screen, None, self.is_live,
+ self.preview_display.web_view.setHtml(build_html_display(service_item, self.preview_display.screen, None, self.is_live,
plugins=self.plugin_manager.plugins))
self.media_controller.setup_display(self.preview_display, True)
if self.service_item:
@@ -883,11 +883,7 @@
self.image_manager.get_image_bytes(frame['path'], ImageSource.ImagePlugin)
self.preview_widget.replace_service_item(self.service_item, width, slide_no)
self.enable_tool_bar(service_item)
- # Pass to display for viewing.
- # Postpone image build, we need to do this later to avoid the theme
- # flashing on the screen
- if not self.service_item.is_image():
- self.display.build_html(self.service_item)
+ self.display.show_background(self.service_item)
if service_item.is_media():
self.on_media_start(service_item)
self.slide_selected(True)
@@ -1089,10 +1085,7 @@
if self.service_item.is_text():
self.display.text(to_display)
else:
- if start:
- self.display.build_html(self.service_item, to_display)
- else:
- self.display.image(to_display)
+ self.display.image(to_display)
# reset the store used to display first image
self.service_item.bg_image_bytes = None
self.selected_row = row
=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py 2015-01-18 13:39:21 +0000
+++ openlp/core/ui/themeform.py 2015-04-18 08:51:32 +0000
@@ -33,6 +33,7 @@
from openlp.core.ui import ThemeLayoutForm
from openlp.core.utils import get_images_filter, is_not_image_file
from .themewizard import Ui_ThemeWizard
+from openlp.core.lib.transitions import TransitionType
log = logging.getLogger(__name__)
@@ -88,6 +89,7 @@
self.main_font_combo_box.activated.connect(self.calculate_lines)
self.footer_font_combo_box.activated.connect(self.update_theme)
self.footer_size_spin_box.valueChanged.connect(self.update_theme)
+ self.transitions_combo_box.currentIndexChanged.connect(self.on_transitions_combo_box_current_index_changed)
def set_defaults(self):
"""
@@ -133,7 +135,7 @@
self.area_position_page.registerField('footer_position_height', self.footer_height_spin_box)
self.background_page.registerField('horizontal', self.horizontal_combo_box)
self.background_page.registerField('vertical', self.vertical_combo_box)
- self.background_page.registerField('slide_transition', self.transitions_check_box)
+ self.background_page.registerField('slide_transition', self.transitions_combo_box)
self.background_page.registerField('name', self.theme_name_edit)
def calculate_lines(self):
@@ -365,7 +367,7 @@
"""
self.setField('horizontal', self.theme.display_horizontal_align)
self.setField('vertical', self.theme.display_vertical_align)
- self.setField('slide_transition', self.theme.display_slide_transition)
+ self.setField('slide_transition', TransitionType.from_string(self.theme.display_slide_transition))
def set_preview_page_values(self):
"""
@@ -464,6 +466,14 @@
"""
self.theme.font_footer_color = color
+ def on_transitions_combo_box_current_index_changed(self, index):
+ """
+ Background gradient Combo box has changed.
+ """
+ if self.update_theme_allowed:
+ self.theme.display_slide_transition = TransitionType.to_string(index)
+ self.set_alignment_page_values()
+
def update_theme(self):
"""
Update the theme object from the UI for fields not already updated
@@ -495,7 +505,7 @@
# position page
self.theme.display_horizontal_align = self.horizontal_combo_box.currentIndex()
self.theme.display_vertical_align = self.vertical_combo_box.currentIndex()
- self.theme.display_slide_transition = self.field('slide_transition')
+ self.theme.display_slide_transition = TransitionType.to_string(self.transitions_combo_box.currentIndex())
def accept(self):
"""
=== modified file 'openlp/core/ui/themestab.py'
--- openlp/core/ui/themestab.py 2015-01-18 13:39:21 +0000
+++ openlp/core/ui/themestab.py 2015-04-18 08:51:32 +0000
@@ -29,6 +29,7 @@
from openlp.core.common import Registry, Settings, ThemeLevel, UiStrings, translate
from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import find_and_set_in_combo_box
+from openlp.core.lib.transitions import TransitionType
class ThemesTab(SettingsTab):
@@ -66,6 +67,15 @@
self.universal_group_box.setObjectName('universal_group_box')
self.universal_group_box_layout = QtGui.QVBoxLayout(self.universal_group_box)
self.universal_group_box_layout.setObjectName('universal_group_box_layout')
+ self.background_transitions_label = QtGui.QLabel(self.universal_group_box)
+ self.background_transitions_label.setObjectName('background_transitions_label')
+ self.universal_group_box_layout.addWidget(self.background_transitions_label)
+ self.background_transitions_combo_box = QtGui.QComboBox(self.universal_group_box)
+ self.background_transitions_combo_box.addItems(TransitionType.Names)
+ self.background_transitions_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToMinimumContentsLength)
+ self.background_transitions_combo_box.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
+ self.background_transitions_combo_box.setObjectName('background_transitions_combo_box')
+ self.universal_group_box_layout.addWidget(self.background_transitions_combo_box)
self.wrap_footer_check_box = QtGui.QCheckBox(self.universal_group_box)
self.wrap_footer_check_box.setObjectName('wrap_footer_check_box')
self.universal_group_box_layout.addWidget(self.wrap_footer_check_box)
@@ -114,6 +124,10 @@
self.tab_title_visible = UiStrings().Themes
self.global_group_box.setTitle(translate('OpenLP.ThemesTab', 'Global Theme'))
self.universal_group_box.setTitle(translate('OpenLP.ThemesTab', 'Universal Settings'))
+ self.background_transitions_label.setText(translate('OpenLP.ThemesTab', 'Background Transitions:'))
+ for index in range(len(TransitionType.Names)):
+ self.background_transitions_combo_box.setItemText(index, translate('OpenLP.Transitions',
+ TransitionType.Names[index]))
self.wrap_footer_check_box.setText(translate('OpenLP.ThemesTab', '&Wrap footer text'))
self.level_group_box.setTitle(translate('OpenLP.ThemesTab', 'Theme Level'))
self.song_level_radio_button.setText(translate('OpenLP.ThemesTab', 'S&ong Level'))
@@ -139,6 +153,8 @@
settings.beginGroup(self.settings_section)
self.theme_level = settings.value('theme level')
self.global_theme = settings.value('global theme')
+ self.background_transitions_combo_box.setCurrentIndex(
+ TransitionType.from_string(settings.value('background transitions')))
self.wrap_footer_check_box.setChecked(settings.value('wrap footer'))
settings.endGroup()
if self.theme_level == ThemeLevel.Global:
@@ -157,6 +173,8 @@
settings.setValue('theme level', self.theme_level)
settings.setValue('global theme', self.global_theme)
settings.setValue('wrap footer', self.wrap_footer_check_box.isChecked())
+ settings.setValue('background transitions',
+ TransitionType.to_string(self.background_transitions_combo_box.currentIndex()))
settings.endGroup()
self.renderer.set_theme_level(self.theme_level)
if self.tab_visited:
=== modified file 'openlp/core/ui/themewizard.py'
--- openlp/core/ui/themewizard.py 2015-01-18 13:39:21 +0000
+++ openlp/core/ui/themewizard.py 2015-04-18 08:51:32 +0000
@@ -28,6 +28,7 @@
from openlp.core.lib import build_icon, ColorButton
from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
+from openlp.core.lib.transitions import TransitionType
class Ui_ThemeWizard(object):
@@ -257,9 +258,10 @@
self.alignment_layout.addRow(self.vertical_label, self.vertical_combo_box)
self.transitions_label = QtGui.QLabel(self.alignment_page)
self.transitions_label.setObjectName('transitions_label')
- self.transitions_check_box = QtGui.QCheckBox(self.alignment_page)
- self.transitions_check_box.setObjectName('transitions_check_box')
- self.alignment_layout.addRow(self.transitions_label, self.transitions_check_box)
+ self.transitions_combo_box = QtGui.QComboBox(self.alignment_page)
+ self.transitions_combo_box.addItems(TransitionType.Names)
+ self.transitions_combo_box.setObjectName('transitions_combo_box')
+ self.alignment_layout.addRow(self.transitions_label, self.transitions_combo_box)
self.alignment_layout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer)
theme_wizard.addPage(self.alignment_page)
# Area Position Page
@@ -458,6 +460,8 @@
self.horizontal_combo_box.setItemText(HorizontalType.Center, translate('OpenLP.ThemeWizard', 'Center'))
self.horizontal_combo_box.setItemText(HorizontalType.Justify, translate('OpenLP.ThemeWizard', 'Justify'))
self.transitions_label.setText(translate('OpenLP.ThemeWizard', 'Transitions:'))
+ for index in range(len(TransitionType.Names)):
+ self.transitions_combo_box.setItemText(index, translate('OpenLP.Transitions', TransitionType.Names[index]))
self.area_position_page.setTitle(translate('OpenLP.ThemeWizard', 'Output Area Locations'))
self.area_position_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Allows you to change and move the'
' Main and Footer areas.'))
=== modified file 'tests/functional/openlp_core_lib/test_htmlbuilder.py'
--- tests/functional/openlp_core_lib/test_htmlbuilder.py 2014-07-24 21:57:16 +0000
+++ tests/functional/openlp_core_lib/test_htmlbuilder.py 2015-04-18 08:51:32 +0000
@@ -7,7 +7,7 @@
from PyQt4 import QtCore
from openlp.core.common import Settings
-from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \
+from openlp.core.lib.htmlbuilder import build_html_display, build_background_css, build_lyrics_css, build_lyrics_outline_css, \
build_lyrics_format_css, build_footer_css
from openlp.core.lib.theme import HorizontalType, VerticalType
from tests.functional import MagicMock, patch
@@ -240,7 +240,7 @@
plugins = [plugin]
# WHEN: Create the html.
- html = build_html(item, screen, is_live, background, plugins=plugins)
+ html = build_html_display(item, screen, is_live, background, plugins=plugins)
# THEN: The returned html should match.
self.assertEqual(html, HTML, 'The returned html should match')
Follow ups