forked from openlp/openlp
Don't reload images on start (they are already loaded)
Someone should check if the start param in this function is even needed now, looks like an artifact from the old renderer
This commit is contained in:
parent
79950b6a85
commit
d5892b6258
@ -333,6 +333,7 @@ class Settings(QtCore.QSettings):
|
||||
'themes/last directory import': None,
|
||||
'themes/theme level': ThemeLevel.Global,
|
||||
'themes/wrap footer': False,
|
||||
'themes/item transitions': False,
|
||||
'user interface/live panel': True,
|
||||
'user interface/live splitter geometry': QtCore.QByteArray(),
|
||||
'user interface/lock panel': True,
|
||||
|
@ -22,14 +22,53 @@ sup {
|
||||
font-size: smaller !important;
|
||||
}
|
||||
|
||||
body,
|
||||
.reveal .slides,
|
||||
.reveal .footer {
|
||||
transition: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
body.transition,
|
||||
body.transition .reveal .slides,
|
||||
body.transition .reveal .footer {
|
||||
/* Transition speed for content visibility */
|
||||
transition: opacity 800ms ease-in-out !important;
|
||||
}
|
||||
|
||||
.reveal .slide-background {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: none !important;
|
||||
z-index: 2;
|
||||
/* important required to override inline attributes */
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
background-position: 50% 50% !important;
|
||||
}
|
||||
|
||||
.reveal .slide-background:nth-child(n+3) {
|
||||
/* Hide backgrounds beyond the first 2 (prevents ugly transitions in corner case) */
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.reveal .slide-background.future,
|
||||
.reveal .slide-background.past {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
body.transition .reveal .slide-background {
|
||||
transition: all 800ms ease-in-out !important;
|
||||
}
|
||||
|
||||
.reveal .slides > section,
|
||||
.reveal .slides > section > section {
|
||||
padding: 0;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.reveal .slides > section.text-slides {
|
||||
/* Need to override reveal styles to use our text aligment */
|
||||
.reveal .slides > section {
|
||||
/* Need to override reveal styles to use our text alignment */
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
word-wrap: break-word;
|
||||
@ -318,21 +357,24 @@ sup {
|
||||
.reveal[class*=fade] .slides section.present:not([data-transition]) {
|
||||
transition-delay: 400ms; }
|
||||
|
||||
.reveal .slides section.present[data-transition*=fade],
|
||||
.reveal .slides section.present[data-transition-speed="fast"][data-transition*=fade],
|
||||
.reveal[data-transition-speed="fast"][class*=fade] .slides section.present:not([data-transition]) {
|
||||
transition-delay: 200ms; }
|
||||
|
||||
.reveal .slides section.present[data-transition*=fade],
|
||||
.reveal .slides section.present[data-transition-speed="slow"][data-transition*=fade],
|
||||
.reveal[data-transition-speed="slow"][class*=fade] .slides section.present:not([data-transition]) {
|
||||
transition-delay: 800ms; }
|
||||
|
||||
.reveal[class*=fade] .slides section {
|
||||
.reveal[class*=fade] .slides section,
|
||||
.reveal .slides section[class*=fade] {
|
||||
transition-duration: 400ms !important; }
|
||||
|
||||
.reveal[data-transition-speed="fast"][class*=fade] .slides section {
|
||||
.reveal[data-transition-speed="fast"][class*=fade] .slides section,
|
||||
.reveal .slides section[data-transition-speed="fast"][class*=fade] {
|
||||
transition-duration: 200ms !important; }
|
||||
|
||||
.reveal[data-transition-speed="slow"][class*=fade] .slides section {
|
||||
.reveal[data-transition-speed="slow"][class*=fade] .slides section,
|
||||
.reveal .slides section[data-transition-speed="slow"][class*=fade] {
|
||||
transition-duration: 800ms !important; }
|
||||
|
||||
.reveal[class*=fade].overview .slides section {
|
||||
|
@ -352,6 +352,9 @@ AudioPlayer.prototype.stop = function () {
|
||||
* The Display object is what we use from OpenLP
|
||||
*/
|
||||
var Display = {
|
||||
_slidesContainer: null,
|
||||
_footerContainer: null,
|
||||
_backgroundsContainer: null,
|
||||
_alerts: [],
|
||||
_slides: {},
|
||||
_alertSettings: {},
|
||||
@ -359,6 +362,8 @@ var Display = {
|
||||
_transitionState: TransitionState.NoTransition,
|
||||
_animationState: AnimationState.NoAnimation,
|
||||
_doTransitions: false,
|
||||
_doItemTransitions: false,
|
||||
_themeApplied: true,
|
||||
_revealConfig: {
|
||||
margin: 0.0,
|
||||
minScale: 1.0,
|
||||
@ -380,9 +385,16 @@ var Display = {
|
||||
/**
|
||||
* Start up reveal and do any other initialisation
|
||||
*/
|
||||
init: function (doTransitions=false) {
|
||||
init: function (doTransitions=false, doItemtransitions=false) {
|
||||
var globalBackground = $("#global-background")[0];
|
||||
globalBackground.style.cssText = "";
|
||||
globalBackground.style.setProperty("background", "black");
|
||||
Display._slidesContainer = $(".slides")[0];
|
||||
Display._footerContainer = $(".footer")[0];
|
||||
Display._backgroundsContainer = $(".backgrounds")[0];
|
||||
Display._doTransitions = doTransitions;
|
||||
Reveal.initialize(Display._revealConfig);
|
||||
Display.setItemTransition(doItemtransitions && doTransitions);
|
||||
displayWatcher.setInitialised(true);
|
||||
},
|
||||
/**
|
||||
@ -394,30 +406,79 @@ var Display = {
|
||||
Reveal.slide(0);
|
||||
},
|
||||
/**
|
||||
* Set the transition type
|
||||
* @param {string} transitionType - Can be one of "none", "fade", "slide", "convex", "concave", "zoom"
|
||||
* @param {string} transitionSpeed - Can be one of "default", "fast", "slow"
|
||||
* Enable/Disable item transitions
|
||||
*/
|
||||
setTransition: function (transitionType, transitionSpeed) {
|
||||
Reveal.configure({"transition": transitionType, "transitionSpeed": transitionSpeed});
|
||||
setItemTransition: function (enable) {
|
||||
Display._doItemTransitions = enable;
|
||||
var body = $("body")[0];
|
||||
if (enable) {
|
||||
body.classList.add("transition");
|
||||
Reveal.configure({"backgroundTransition": "fade", "transitionSpeed": "default"});
|
||||
} else {
|
||||
body.classList.remove("transition");
|
||||
Reveal.configure({"backgroundTransition": "none"});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Clear the current list of slides
|
||||
*/
|
||||
clearSlides: function () {
|
||||
$(".slides")[0].innerHTML = "";
|
||||
Display._slidesContainer.innerHTML = "";
|
||||
Display._clearSlidesList();
|
||||
},
|
||||
/**
|
||||
* Clear the current list of slides
|
||||
*/
|
||||
_clearSlidesList: function () {
|
||||
Display._footerContainer.innerHTML = "";
|
||||
Display._slides = {};
|
||||
},
|
||||
/**
|
||||
* Add new item/slides, replacing the old one
|
||||
* Clears current list of slides but allows time for a transition animation
|
||||
* Items are ordered newest to oldest in the slides container
|
||||
* @param {element} new_slides - New slides to display
|
||||
* @param {element} is_text - Used to decide if the theme main area constraints should apply
|
||||
*/
|
||||
replaceSlides: function (new_slides, is_text=false) {
|
||||
if (Display._doItemTransitions) {
|
||||
new_slides.setAttribute('data-transition', "fade");
|
||||
new_slides.setAttribute('data-transition-speed', "default");
|
||||
}
|
||||
new_slides.classList.add("future");
|
||||
Display.applyTheme(new_slides, is_text);
|
||||
Display._slidesContainer.prepend(new_slides);
|
||||
var currentSlide = Reveal.getIndices();
|
||||
if (Display._doItemTransitions && Display._slidesContainer.children.length >= 2) {
|
||||
// Set the slide one section ahead so we'll stay on the old slide after reinit
|
||||
Reveal.slide(1, currentSlide.v);
|
||||
Display.reinit();
|
||||
// Timeout to allow time to transition before deleting the old slides
|
||||
setTimeout (Display._removeLastSection, 5000);
|
||||
} else {
|
||||
Reveal.slide(0, currentSlide.v);
|
||||
Reveal.sync();
|
||||
Display._removeLastSection();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Removes the last slides item if there are more than one
|
||||
*/
|
||||
_removeLastSection: function () {
|
||||
if (Display._slidesContainer.children.length > 1) {
|
||||
Display._slidesContainer.lastChild.remove();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Checks if the present slide content fits within the slide
|
||||
*/
|
||||
doesContentFit: function () {
|
||||
var currSlide = $("section.text-slides");
|
||||
if (currSlide.length === 0) {
|
||||
currSlide = $(".slides");
|
||||
}
|
||||
currSlide = Display._footerContainer;
|
||||
} else {
|
||||
currSlide = currSlide[0];
|
||||
console.debug("scrollHeight: " + currSlide.scrollHeight + ", clientHeight: " + currSlide.clientHeight);
|
||||
}
|
||||
return currSlide.clientHeight >= currSlide.scrollHeight;
|
||||
},
|
||||
/**
|
||||
@ -426,22 +487,17 @@ var Display = {
|
||||
* @param {string} image - Path to the splash image
|
||||
*/
|
||||
setStartupSplashScreen: function(bg_color, image) {
|
||||
Display.clearSlides();
|
||||
var globalBackground = $("#global-background")[0];
|
||||
globalBackground.style.cssText = "";
|
||||
globalBackground.style.setProperty("background", bg_color);
|
||||
var slidesDiv = $(".slides")[0];
|
||||
Display._clearSlidesList();
|
||||
var section = document.createElement("section");
|
||||
section.setAttribute("id", 0);
|
||||
section.setAttribute("data-background", bg_color);
|
||||
section.setAttribute("style", "height: 100%; width: 100%; position: relative;");
|
||||
section.setAttribute("style", "height: 100%; width: 100%;");
|
||||
var img = document.createElement('img');
|
||||
img.src = image;
|
||||
img.setAttribute("style", "position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; max-height: 100%; max-width: 100%");
|
||||
section.appendChild(img);
|
||||
slidesDiv.appendChild(section);
|
||||
Display._slides['0'] = 0;
|
||||
Display.reinit();
|
||||
Display.replaceSlides(section);
|
||||
},
|
||||
/**
|
||||
* Set fullscreen image from path
|
||||
@ -450,10 +506,6 @@ var Display = {
|
||||
*/
|
||||
setFullscreenImage: function(bg_color, image) {
|
||||
Display.clearSlides();
|
||||
var globalBackground = $("#global-background")[0];
|
||||
globalBackground.style.cssText = "";
|
||||
globalBackground.style.setProperty("background", bg_color);
|
||||
var slidesDiv = $(".slides")[0];
|
||||
var section = document.createElement("section");
|
||||
section.setAttribute("id", 0);
|
||||
section.setAttribute("data-background", bg_color);
|
||||
@ -462,9 +514,8 @@ var Display = {
|
||||
img.src = image;
|
||||
img.setAttribute("style", "height: 100%; width: 100%");
|
||||
section.appendChild(img);
|
||||
slidesDiv.appendChild(section);
|
||||
Display._slides['0'] = 0;
|
||||
Display.reinit();
|
||||
Display.replaceSlides(parentSection);
|
||||
},
|
||||
/**
|
||||
* Set fullscreen image from base64 data
|
||||
@ -473,10 +524,6 @@ var Display = {
|
||||
*/
|
||||
setFullscreenImageFromData: function(bg_color, image_data) {
|
||||
Display.clearSlides();
|
||||
var globalBackground = $("#global-background")[0];
|
||||
globalBackground.style.cssText = "";
|
||||
globalBackground.style.setProperty("background", bg_color);
|
||||
var slidesDiv = $(".slides")[0];
|
||||
var section = document.createElement("section");
|
||||
section.setAttribute("id", 0);
|
||||
section.setAttribute("data-background", bg_color);
|
||||
@ -485,7 +532,7 @@ var Display = {
|
||||
img.src = 'data:image/png;base64,' + image_data;
|
||||
img.setAttribute("style", "height: 100%; width: 100%");
|
||||
section.appendChild(img);
|
||||
slidesDiv.appendChild(section);
|
||||
Display._slidesContainer.appendChild(section);
|
||||
Display._slides['0'] = 0;
|
||||
Display.reinit();
|
||||
},
|
||||
@ -632,62 +679,64 @@ var Display = {
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Add a slide. If the slide exists but the HTML is different, update the slide.
|
||||
* Create a text slide.
|
||||
* @param {string} verse - The verse number, e.g. "v1"
|
||||
* @param {string} text - The HTML for the verse, e.g. "line1<br>line2"
|
||||
* @param {string} footer_text - The HTML for the footer
|
||||
* @param {bool} reinit - True if React should reinit when creating a new slide
|
||||
*/
|
||||
addTextSlide: function (verse, text, footerText, reinit=true) {
|
||||
_createTextSlide: function (verse, text) {
|
||||
var slide;
|
||||
var html = _prepareText(text);
|
||||
if (Display._slides.hasOwnProperty(verse)) {
|
||||
slide = $("#" + verse)[0];
|
||||
if (slide.innerHTML != html) {
|
||||
slide.innerHTML = html;
|
||||
}
|
||||
} else {
|
||||
var parent = $("section.text-slides");
|
||||
if (parent.length === 0) {
|
||||
Display._createTextContainer();
|
||||
parent = $("section.text-slides");
|
||||
}
|
||||
parent = parent[0];
|
||||
slide = document.createElement("section");
|
||||
slide.setAttribute("id", verse);
|
||||
slide.innerHTML = html;
|
||||
parent.appendChild(slide);
|
||||
Display._slides[verse] = parent.children.length - 1;
|
||||
if (footerText) {
|
||||
$(".footer")[0].innerHTML = footerText;
|
||||
}
|
||||
if (reinit) {
|
||||
Display.reinit();
|
||||
}
|
||||
}
|
||||
return slide;
|
||||
},
|
||||
/**
|
||||
* Set text slides.
|
||||
* @param {Object[]} slides - A list of slides to add as JS objects: {"verse": "v1", "text": "line 1\nline2"}
|
||||
*/
|
||||
setTextSlides: function (slides) {
|
||||
Display.clearSlides();
|
||||
Display._clearSlidesList();
|
||||
var slide_html;
|
||||
var parentSection = document.createElement("section");
|
||||
parentSection.classList = "text-slides";
|
||||
slides.forEach(function (slide) {
|
||||
Display.addTextSlide(slide.verse, slide.text, slide.footer, false);
|
||||
slide_html = Display._createTextSlide(slide.verse, slide.text);
|
||||
parentSection.appendChild(slide_html);
|
||||
Display._slides[slide.verse] = parentSection.children.length - 1;
|
||||
if (slide.footer) {
|
||||
Display._footerContainer.innerHTML = slide.footer;
|
||||
}
|
||||
});
|
||||
Display.reinit();
|
||||
Display.replaceSlides(parentSection, true);
|
||||
},
|
||||
/**
|
||||
* Create the <section> that will contain text slides (vertical slides in react)
|
||||
* Set a single text slide. This changes the slide with no transition.
|
||||
* Prevents the need to reapply the theme if only changing content.
|
||||
* @param String slide - Text to put on the slide
|
||||
*/
|
||||
_createTextContainer: function () {
|
||||
var slideContainer = document.createElement("section");
|
||||
slideContainer.classList = "text-slides";
|
||||
var slidesDiv = $(".slides")[0];
|
||||
slidesDiv.appendChild(slideContainer);
|
||||
// Apply the current theme to the new container
|
||||
if (!!Display._theme) {
|
||||
Display.setTheme(Display._theme);
|
||||
setTextSlide: function (text) {
|
||||
if (Display._slides.hasOwnProperty("test-slide") && Object.keys(Display._slides).length === 1) {
|
||||
var slide = $("#" + "test-slide")[0];
|
||||
var html = _prepareText(text);
|
||||
if (slide.innerHTML != html) {
|
||||
slide.innerHTML = html;
|
||||
}
|
||||
if (!Display._themeApplied) {
|
||||
Display.applyTheme(slide.parent);
|
||||
}
|
||||
} else {
|
||||
Display._clearSlidesList();
|
||||
var slide_html;
|
||||
var parentSection = document.createElement("section");
|
||||
parentSection.classList = "text-slides";
|
||||
slide_html = Display._createTextSlide("test-slide", text);
|
||||
parentSection.appendChild(slide_html);
|
||||
Display._slides["test-slide"] = 0;
|
||||
Display.applyTheme(parentSection);
|
||||
Display._slidesContainer.innerHTML = "";
|
||||
Display._slidesContainer.prepend(parentSection);
|
||||
Display.reinit();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -695,8 +744,7 @@ var Display = {
|
||||
* @param {Object[]} slides - A list of images to add as JS objects [{"path": "url/to/file"}]
|
||||
*/
|
||||
setImageSlides: function (slides) {
|
||||
Display.clearSlides();
|
||||
var slidesDiv = $(".slides")[0];
|
||||
Display._clearSlidesList();
|
||||
var parentSection = document.createElement("section");
|
||||
slides.forEach(function (slide, index) {
|
||||
var section = document.createElement("section");
|
||||
@ -710,15 +758,14 @@ var Display = {
|
||||
parentSection.appendChild(section);
|
||||
Display._slides[index.toString()] = index;
|
||||
});
|
||||
slidesDiv.appendChild(parentSection);
|
||||
Display.reinit();
|
||||
Display.replaceSlides(parentSection);
|
||||
},
|
||||
/**
|
||||
* Set a video
|
||||
* @param {Object} video - The video to show as a JS object: {"path": "url/to/file"}
|
||||
*/
|
||||
setVideo: function (video) {
|
||||
Display.clearSlides();
|
||||
Display._clearSlidesList();
|
||||
var section = document.createElement("section");
|
||||
section.setAttribute("data-background", "#000");
|
||||
var videoElement = document.createElement("video");
|
||||
@ -747,8 +794,7 @@ var Display = {
|
||||
mediaWatcher.has_muted(event.target.muted);
|
||||
});
|
||||
section.appendChild(videoElement);
|
||||
$(".slides")[0].appendChild(section);
|
||||
Display.reinit();
|
||||
Display.replaceSlides(section);
|
||||
},
|
||||
/**
|
||||
* Play a video
|
||||
@ -856,32 +902,45 @@ var Display = {
|
||||
/**
|
||||
* Blank the screen
|
||||
*/
|
||||
blankToBlack: function () {
|
||||
toBlack: function () {
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
if (!Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
// var slidesDiv = $(".slides")[0];
|
||||
},
|
||||
/**
|
||||
* Blank to theme
|
||||
* Hide all but theme background
|
||||
*/
|
||||
blankToTheme: function () {
|
||||
var slidesDiv = $(".slides")[0];
|
||||
slidesDiv.style.visibility = "hidden";
|
||||
var footerDiv = $(".footer")[0];
|
||||
footerDiv.style.visibility = "hidden";
|
||||
toTheme: function () {
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
Display._slidesContainer.style.opacity = 0;
|
||||
Display._footerContainer.style.opacity = 0;
|
||||
if (Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Hide everything (CAUTION: Causes a invisible mouse barrier)
|
||||
*/
|
||||
toTransparent: function () {
|
||||
Display._slidesContainer.style.opacity = 0;
|
||||
Display._footerContainer.style.opacity = 0;
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 0;
|
||||
if (!Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Show the screen
|
||||
*/
|
||||
show: function () {
|
||||
var slidesDiv = $(".slides")[0];
|
||||
slidesDiv.style.visibility = "visible";
|
||||
var footerDiv = $(".footer")[0];
|
||||
footerDiv.style.visibility = "visible";
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
Display._slidesContainer.style.opacity = 1;
|
||||
Display._footerContainer.style.opacity = 1;
|
||||
if (Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
@ -903,13 +962,31 @@ var Display = {
|
||||
var dh = parseFloat(_getStyle(d, "height"));
|
||||
return Math.floor(dh / lh);
|
||||
},
|
||||
/**
|
||||
* Prepare the theme for the next item to be added
|
||||
* @param theme The theme to be used
|
||||
*/
|
||||
setTheme: function (theme) {
|
||||
if (Display._theme != theme) {
|
||||
Display._themeApplied = false;
|
||||
Display._theme = theme;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Apply the theme to the provided element
|
||||
* @param targetElement The target element to apply the theme (expected to be a <section> in the slides container)
|
||||
* @param is_text Used to decide if the main area constraints should be applied
|
||||
*/
|
||||
applyTheme: function (targetElement, is_text=true) {
|
||||
Display._themeApplied = true;
|
||||
if (!Display._theme) {
|
||||
return;
|
||||
}
|
||||
// Set slide transitions
|
||||
var new_transition_type = "none",
|
||||
new_transition_speed = "default";
|
||||
if (!!theme.display_slide_transition && Display._doTransitions) {
|
||||
switch (theme.display_slide_transition_type) {
|
||||
if (!!Display._theme.display_slide_transition && Display._doTransitions) {
|
||||
switch (Display._theme.display_slide_transition_type) {
|
||||
case TransitionType.Fade:
|
||||
new_transition_type = "fade";
|
||||
break;
|
||||
@ -928,7 +1005,7 @@ var Display = {
|
||||
default:
|
||||
new_transition_type = "fade";
|
||||
}
|
||||
switch (theme.display_slide_transition_speed) {
|
||||
switch (Display._theme.display_slide_transition_speed) {
|
||||
case TransitionSpeed.Normal:
|
||||
new_transition_speed = "default";
|
||||
break;
|
||||
@ -941,7 +1018,7 @@ var Display = {
|
||||
default:
|
||||
new_transition_speed = "default";
|
||||
}
|
||||
switch (theme.display_slide_transition_direction) {
|
||||
switch (Display._theme.display_slide_transition_direction) {
|
||||
case TransitionDirection.Vertical:
|
||||
new_transition_type += "-vertical";
|
||||
break;
|
||||
@ -949,95 +1026,102 @@ var Display = {
|
||||
default:
|
||||
new_transition_type += "-horizontal";
|
||||
}
|
||||
if (theme.display_slide_transition_reverse) {
|
||||
if (Display._theme.display_slide_transition_reverse) {
|
||||
new_transition_type += "-reverse";
|
||||
}
|
||||
}
|
||||
|
||||
Display.setTransition(new_transition_type, new_transition_speed);
|
||||
var slides = targetElement.children;
|
||||
for (var i = 0; i < slides.length; i++) {
|
||||
slides[i].setAttribute("data-transition", new_transition_type);
|
||||
slides[i].setAttribute("data-transition-speed", new_transition_speed);
|
||||
}
|
||||
// Set the background
|
||||
var globalBackground = $("#global-background")[0];
|
||||
var backgroundStyle = {};
|
||||
var backgroundContent = "";
|
||||
var backgroundHtml = "";
|
||||
switch (theme.background_type) {
|
||||
var globalBackground = $("#global-background")[0];
|
||||
globalBackground.style.setProperty("background", "black");
|
||||
switch (Display._theme.background_type) {
|
||||
case BackgroundType.Transparent:
|
||||
backgroundStyle.background = "transparent";
|
||||
backgroundContent = "transparent";
|
||||
globalBackground.style.setProperty("background", "transparent");
|
||||
break;
|
||||
case BackgroundType.Solid:
|
||||
backgroundStyle.background = theme.background_color;
|
||||
backgroundContent = Display._theme.background_color;
|
||||
break;
|
||||
case BackgroundType.Gradient:
|
||||
switch (theme.background_direction) {
|
||||
switch (Display._theme.background_direction) {
|
||||
case GradientType.Horizontal:
|
||||
backgroundStyle.background = _buildLinearGradient("left top", "left bottom",
|
||||
theme.background_start_color,
|
||||
theme.background_end_color);
|
||||
backgroundContent = _buildLinearGradient("left top", "left bottom",
|
||||
Display._theme.background_start_color,
|
||||
Display._theme.background_end_color);
|
||||
break;
|
||||
case GradientType.Vertical:
|
||||
backgroundStyle.background = _buildLinearGradient("left top", "right top",
|
||||
theme.background_start_color,
|
||||
theme.background_end_color);
|
||||
backgroundContent = _buildLinearGradient("left top", "right top",
|
||||
Display._theme.background_start_color,
|
||||
Display._theme.background_end_color);
|
||||
break;
|
||||
case GradientType.LeftTop:
|
||||
backgroundStyle.background = _buildLinearGradient("left top", "right bottom",
|
||||
theme.background_start_color,
|
||||
theme.background_end_color);
|
||||
backgroundContent = _buildLinearGradient("left top", "right bottom",
|
||||
Display._theme.background_start_color,
|
||||
Display._theme.background_end_color);
|
||||
break;
|
||||
case GradientType.LeftBottom:
|
||||
backgroundStyle.background = _buildLinearGradient("left bottom", "right top",
|
||||
theme.background_start_color,
|
||||
theme.background_end_color);
|
||||
backgroundContent = _buildLinearGradient("left bottom", "right top",
|
||||
Display._theme.background_start_color,
|
||||
Display._theme.background_end_color);
|
||||
break;
|
||||
case GradientType.Circular:
|
||||
backgroundStyle.background = _buildRadialGradient(window.innerWidth / 2, theme.background_start_color,
|
||||
theme.background_end_color);
|
||||
backgroundContent = _buildRadialGradient(window.innerWidth / 2, Display._theme.background_start_color,
|
||||
Display._theme.background_end_color);
|
||||
break;
|
||||
default:
|
||||
backgroundStyle.background = "#000";
|
||||
backgroundContent = "#000";
|
||||
}
|
||||
break;
|
||||
case BackgroundType.Image:
|
||||
backgroundStyle["background-image"] = "url('" + theme.background_filename + "')";
|
||||
console.warn(backgroundStyle["background-image"]);
|
||||
backgroundContent = "url('" + Display._theme.background_filename + "')";
|
||||
console.warn(backgroundContent);
|
||||
break;
|
||||
case BackgroundType.Video:
|
||||
// never actually used since background type is overridden from video to transparent in window.py
|
||||
backgroundStyle["background-color"] = theme.background_border_color;
|
||||
backgroundHtml = "<video loop autoplay muted><source src='" + theme.background_filename + "'></video>";
|
||||
backgroundContent = Display._theme.background_border_color;
|
||||
backgroundHtml = "<video loop autoplay muted><source src='" + Display._theme.background_filename + "'></video>";
|
||||
console.warn(backgroundHtml);
|
||||
break;
|
||||
default:
|
||||
backgroundStyle.background = "#000";
|
||||
}
|
||||
globalBackground.style.cssText = "";
|
||||
for (var bgKey in backgroundStyle) {
|
||||
if (backgroundStyle.hasOwnProperty(bgKey)) {
|
||||
globalBackground.style.setProperty(bgKey, backgroundStyle[bgKey]);
|
||||
}
|
||||
backgroundContent = "#000";
|
||||
}
|
||||
targetElement.style.cssText = "";
|
||||
targetElement.setAttribute("data-background", backgroundContent);
|
||||
targetElement.setAttribute("data-background-size", "cover");
|
||||
if (!!backgroundHtml) {
|
||||
globalBackground.innerHTML = backgroundHtml;
|
||||
background.innerHTML = backgroundHtml;
|
||||
}
|
||||
|
||||
// set up the main area
|
||||
if (!is_text) {
|
||||
// only transition and background for non text slides
|
||||
return;
|
||||
}
|
||||
mainStyle = {};
|
||||
if (!!theme.font_main_outline) {
|
||||
mainStyle["-webkit-text-stroke"] = "" + theme.font_main_outline_size + "pt " +
|
||||
theme.font_main_outline_color;
|
||||
mainStyle["-webkit-text-fill-color"] = theme.font_main_color;
|
||||
if (!!Display._theme.font_main_outline) {
|
||||
mainStyle["-webkit-text-stroke"] = "" + Display._theme.font_main_outline_size + "pt " +
|
||||
Display._theme.font_main_outline_color;
|
||||
mainStyle["-webkit-text-fill-color"] = Display._theme.font_main_color;
|
||||
}
|
||||
// These need to be fixed, in the Python they use a width passed in as a parameter
|
||||
mainStyle.width = theme.font_main_width + "px";
|
||||
mainStyle.height = theme.font_main_height + "px";
|
||||
mainStyle["margin-top"] = "" + theme.font_main_y + "px";
|
||||
mainStyle.left = "" + theme.font_main_x + "px";
|
||||
mainStyle.color = theme.font_main_color;
|
||||
mainStyle["font-family"] = theme.font_main_name;
|
||||
mainStyle["font-size"] = "" + theme.font_main_size + "pt";
|
||||
mainStyle["font-style"] = !!theme.font_main_italics ? "italic" : "";
|
||||
mainStyle["font-weight"] = !!theme.font_main_bold ? "bold" : "";
|
||||
mainStyle["line-height"] = "" + (100 + theme.font_main_line_adjustment) + "%";
|
||||
mainStyle.width = Display._theme.font_main_width + "px";
|
||||
mainStyle.height = Display._theme.font_main_height + "px";
|
||||
mainStyle["margin-top"] = "" + Display._theme.font_main_y + "px";
|
||||
mainStyle.left = "" + Display._theme.font_main_x + "px";
|
||||
mainStyle.color = Display._theme.font_main_color;
|
||||
mainStyle["font-family"] = Display._theme.font_main_name;
|
||||
mainStyle["font-size"] = "" + Display._theme.font_main_size + "pt";
|
||||
mainStyle["font-style"] = !!Display._theme.font_main_italics ? "italic" : "";
|
||||
mainStyle["font-weight"] = !!Display._theme.font_main_bold ? "bold" : "";
|
||||
mainStyle["line-height"] = "" + (100 + Display._theme.font_main_line_adjustment) + "%";
|
||||
// Using text-align-last because there is a <br> seperating each line
|
||||
switch (theme.display_horizontal_align) {
|
||||
switch (Display._theme.display_horizontal_align) {
|
||||
case HorizontalAlign.Justify:
|
||||
mainStyle["text-align"] = "justify";
|
||||
mainStyle["text-align-last"] = "justify";
|
||||
@ -1058,7 +1142,7 @@ var Display = {
|
||||
mainStyle["text-align"] = "center";
|
||||
mainStyle["text-align-last"] = "center";
|
||||
}
|
||||
switch (theme.display_vertical_align) {
|
||||
switch (Display._theme.display_vertical_align) {
|
||||
case VerticalAlign.Middle:
|
||||
mainStyle["justify-content"] = "center";
|
||||
break;
|
||||
@ -1068,23 +1152,19 @@ var Display = {
|
||||
case VerticalAlign.Bottom:
|
||||
mainStyle["justify-content"] = "flex-end";
|
||||
// This gets around the webkit scroll height bug
|
||||
mainStyle["padding-bottom"] = "" + (theme.font_main_size / 8) + "px";
|
||||
mainStyle["padding-bottom"] = "" + (Display._theme.font_main_size / 8) + "px";
|
||||
break;
|
||||
default:
|
||||
mainStyle["justify-content"] = "center";
|
||||
}
|
||||
if (theme.hasOwnProperty('font_main_shadow_size') && !!theme.font_main_shadow) {
|
||||
mainStyle["text-shadow"] = theme.font_main_shadow_color + " " + theme.font_main_shadow_size + "pt " +
|
||||
theme.font_main_shadow_size + "pt";
|
||||
if (Display._theme.hasOwnProperty('font_main_shadow_size') && !!Display._theme.font_main_shadow) {
|
||||
mainStyle["text-shadow"] = Display._theme.font_main_shadow_color + " " + Display._theme.font_main_shadow_size + "pt " +
|
||||
Display._theme.font_main_shadow_size + "pt";
|
||||
}
|
||||
var slidesDiv = $("section.text-slides");
|
||||
if (slidesDiv.length > 0) {
|
||||
slidesDiv = slidesDiv[0];
|
||||
slidesDiv.style.cssText = "";
|
||||
targetElement.style.cssText = "";
|
||||
for (var mainKey in mainStyle) {
|
||||
if (mainStyle.hasOwnProperty(mainKey)) {
|
||||
slidesDiv.style.setProperty(mainKey, mainStyle[mainKey]);
|
||||
}
|
||||
targetElement.style.setProperty(mainKey, mainStyle[mainKey]);
|
||||
}
|
||||
}
|
||||
// Set up the footer
|
||||
@ -1092,19 +1172,18 @@ var Display = {
|
||||
"text-align": "left"
|
||||
};
|
||||
footerStyle.position = "absolute";
|
||||
footerStyle.left = "" + theme.font_footer_x + "px";
|
||||
footerStyle.top = "" + theme.font_footer_y + "px";
|
||||
footerStyle.width = "" + theme.font_footer_width + "px";
|
||||
footerStyle.height = "" + theme.font_footer_height + "px";
|
||||
footerStyle.color = theme.font_footer_color;
|
||||
footerStyle["font-family"] = theme.font_footer_name;
|
||||
footerStyle["font-size"] = "" + theme.font_footer_size + "pt";
|
||||
footerStyle["white-space"] = theme.font_footer_wrap ? "normal" : "nowrap";
|
||||
var footer = $(".footer")[0];
|
||||
footer.style.cssText = "";
|
||||
footerStyle.left = "" + Display._theme.font_footer_x + "px";
|
||||
footerStyle.top = "" + Display._theme.font_footer_y + "px";
|
||||
footerStyle.width = "" + Display._theme.font_footer_width + "px";
|
||||
footerStyle.height = "" + Display._theme.font_footer_height + "px";
|
||||
footerStyle.color = Display._theme.font_footer_color;
|
||||
footerStyle["font-family"] = Display._theme.font_footer_name;
|
||||
footerStyle["font-size"] = "" + Display._theme.font_footer_size + "pt";
|
||||
footerStyle["white-space"] = Display._theme.font_footer_wrap ? "normal" : "nowrap";
|
||||
Display._footerContainer.style.cssText = "";
|
||||
for (var footerKey in footerStyle) {
|
||||
if (footerStyle.hasOwnProperty(footerKey)) {
|
||||
footer.style.setProperty(footerKey, footerStyle[footerKey]);
|
||||
Display._footerContainer.style.setProperty(footerKey, footerStyle[footerKey]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -812,7 +812,7 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow):
|
||||
"""
|
||||
self.clear_slides()
|
||||
self.log_debug('_text_fits_on_slide: 1\n{text}'.format(text=text))
|
||||
self.run_javascript('Display.addTextSlide("v1", "{text}", "Dummy Footer");'
|
||||
self.run_javascript('Display.setTextSlide("{text}");'
|
||||
.format(text=text.replace('"', '\\"')), is_sync=True)
|
||||
self.log_debug('_text_fits_on_slide: 2')
|
||||
does_text_fits = self.run_javascript('Display.doesContentFit();', is_sync=True)
|
||||
|
@ -244,7 +244,9 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties):
|
||||
Add stuff after page initialisation
|
||||
"""
|
||||
js_is_display = str(self.is_display).lower()
|
||||
self.run_javascript('Display.init({do_transitions});'.format(do_transitions=js_is_display))
|
||||
item_transitions = str(self.settings.value('themes/item transitions')).lower()
|
||||
self.run_javascript('Display.init({do_transitions}, {do_item_transitions});'
|
||||
.format(do_transitions=js_is_display, do_item_transitions=item_transitions))
|
||||
wait_for(lambda: self._is_initialised)
|
||||
if self.scale != 1:
|
||||
self.set_scale(self.scale)
|
||||
@ -430,12 +432,6 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties):
|
||||
if self.is_display:
|
||||
Registry().execute('live_display_active')
|
||||
|
||||
def blank_to_theme(self):
|
||||
"""
|
||||
Blank to theme
|
||||
"""
|
||||
self.run_javascript('Display.blankToTheme();')
|
||||
|
||||
def hide_display(self, mode=HideMode.Screen):
|
||||
"""
|
||||
Hide the display by making all layers transparent Store the images so they can be replaced when required
|
||||
@ -450,9 +446,11 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties):
|
||||
if mode == HideMode.Screen:
|
||||
self.setVisible(False)
|
||||
elif mode == HideMode.Blank:
|
||||
self.run_javascript('Display.blankToBlack();')
|
||||
self.run_javascript('Display.toBlack();')
|
||||
elif mode == HideMode.Theme:
|
||||
self.run_javascript('Display.toTheme();')
|
||||
else:
|
||||
self.run_javascript('Display.blankToTheme();')
|
||||
self.run_javascript('Display.toTransparent();')
|
||||
if mode != HideMode.Screen:
|
||||
if self.isHidden():
|
||||
self.setVisible(True)
|
||||
|
@ -41,6 +41,7 @@ class HideMode(object):
|
||||
Blank = 1
|
||||
Theme = 2
|
||||
Screen = 3
|
||||
Transparent = 4
|
||||
|
||||
|
||||
class DisplayControllerType(object):
|
||||
|
@ -40,7 +40,7 @@ from openlp.core.common.path import path_to_str
|
||||
from openlp.core.common.registry import Registry, RegistryBase
|
||||
from openlp.core.lib.serviceitem import ItemCapabilities
|
||||
from openlp.core.lib.ui import critical_error_message_box
|
||||
from openlp.core.ui import DisplayControllerType
|
||||
from openlp.core.ui import DisplayControllerType, HideMode
|
||||
from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path, parse_devicestream_path, \
|
||||
VIDEO_EXT, AUDIO_EXT
|
||||
from openlp.core.ui.media.remote import register_views
|
||||
@ -454,7 +454,9 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
||||
controller.media_info.is_playing = True
|
||||
if not controller.media_info.is_background:
|
||||
display = self._define_display(controller)
|
||||
display.setVisible(False)
|
||||
display.hide_display(HideMode.Transparent)
|
||||
controller._set_theme(controller.service_item)
|
||||
display.load_verses([{"verse": "v1", "text": "", "footer": " "}])
|
||||
return True
|
||||
|
||||
def tick(self, controller):
|
||||
@ -466,9 +468,14 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
||||
start_again = False
|
||||
if controller.media_info.is_playing and controller.media_info.length > 0:
|
||||
if controller.media_info.timer > controller.media_info.length:
|
||||
self.media_stop(controller)
|
||||
if controller.media_info.is_looping_playback:
|
||||
start_again = True
|
||||
else:
|
||||
self.media_stop(controller)
|
||||
elif controller.media_info.timer > controller.media_info.length - TICK_TIME * 4:
|
||||
if not controller.media_info.is_looping_playback:
|
||||
display = self._define_display(controller)
|
||||
display.show_display()
|
||||
controller.media_info.timer += TICK_TIME
|
||||
seconds = controller.media_info.timer // 1000
|
||||
minutes = seconds // 60
|
||||
@ -479,7 +486,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
||||
controller.position_label.setText(' %02d:%02d / %02d:%02d' %
|
||||
(minutes, seconds, total_minutes, total_seconds))
|
||||
if start_again:
|
||||
self.media_play(controller, True)
|
||||
controller.seek_slider.setSliderPosition(0)
|
||||
self.media_play(controller, False)
|
||||
|
||||
def media_pause_msg(self, msg):
|
||||
"""
|
||||
@ -560,6 +568,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
||||
controller.media_info.is_playing = False
|
||||
controller.media_info.timer = 1000
|
||||
controller.media_timer = 0
|
||||
display = self._define_display(controller)
|
||||
display.show_display()
|
||||
|
||||
def media_volume_msg(self, msg):
|
||||
"""
|
||||
@ -615,6 +625,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
||||
"""
|
||||
self.set_controls_visible(controller, False)
|
||||
if controller.controller_type in self.current_media_players:
|
||||
display = self._define_display(controller)
|
||||
display.show_display()
|
||||
self.current_media_players[controller.controller_type].reset(controller)
|
||||
self.current_media_players[controller.controller_type].set_visible(controller, False)
|
||||
del self.current_media_players[controller.controller_type]
|
||||
|
@ -855,7 +855,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
||||
self.preview_display.set_theme(theme_data, service_item_type=service_item.service_item_type)
|
||||
# Set theme for displays
|
||||
for display in self.displays:
|
||||
display.set_theme(service_item.get_theme_data(), service_item_type=service_item.service_item_type)
|
||||
display.set_theme(theme_data, service_item_type=service_item.service_item_type)
|
||||
|
||||
def _process_item(self, service_item, slide_no):
|
||||
"""
|
||||
@ -1168,20 +1168,9 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
||||
Registry().execute('{text}_slide'.format(text=self.service_item.name.lower()),
|
||||
[self.service_item, self.is_live, row])
|
||||
else:
|
||||
# to_display = self.service_item.get_rendered_frame(row)
|
||||
if self.service_item.is_text():
|
||||
for display in self.displays:
|
||||
display.go_to_slide(row)
|
||||
# self.display.text(to_display, row != old_selected_row)
|
||||
else:
|
||||
if start:
|
||||
for display in self.displays:
|
||||
display.load_images(self.service_item.slides)
|
||||
# self.display.build_html(self.service_item, to_display)
|
||||
else:
|
||||
for display in self.displays:
|
||||
display.go_to_slide(row)
|
||||
# self.display.image(to_display)
|
||||
if not self.service_item.is_text():
|
||||
# reset the store used to display first image
|
||||
self.service_item.bg_image_bytes = None
|
||||
self.selected_row = row
|
||||
|
@ -69,6 +69,9 @@ class ThemesTab(SettingsTab):
|
||||
self.wrap_footer_check_box = QtWidgets.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)
|
||||
self.item_transitions_check_box = QtWidgets.QCheckBox(self.universal_group_box)
|
||||
self.item_transitions_check_box.setObjectName('item_transitions_check_box')
|
||||
self.universal_group_box_layout.addWidget(self.item_transitions_check_box)
|
||||
self.left_layout.addWidget(self.universal_group_box)
|
||||
self.left_layout.addStretch()
|
||||
self.level_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||
@ -115,6 +118,7 @@ class ThemesTab(SettingsTab):
|
||||
self.global_group_box.setTitle(translate('OpenLP.ThemesTab', 'Global Theme'))
|
||||
self.universal_group_box.setTitle(translate('OpenLP.ThemesTab', 'Universal Settings'))
|
||||
self.wrap_footer_check_box.setText(translate('OpenLP.ThemesTab', '&Wrap footer text'))
|
||||
self.item_transitions_check_box.setText(translate('OpenLP.ThemesTab', '&Transition between service items'))
|
||||
self.level_group_box.setTitle(translate('OpenLP.ThemesTab', 'Theme Level'))
|
||||
self.song_level_radio_button.setText(translate('OpenLP.ThemesTab', 'S&ong Level'))
|
||||
self.song_level_label.setText(
|
||||
@ -139,6 +143,7 @@ class ThemesTab(SettingsTab):
|
||||
self.theme_level = self.settings.value('theme level')
|
||||
self.global_theme = self.settings.value('global theme')
|
||||
self.wrap_footer_check_box.setChecked(self.settings.value('wrap footer'))
|
||||
self.item_transitions_check_box.setChecked(self.settings.value('item transitions'))
|
||||
self.settings.endGroup()
|
||||
if self.theme_level == ThemeLevel.Global:
|
||||
self.global_level_radio_button.setChecked(True)
|
||||
@ -155,6 +160,7 @@ class ThemesTab(SettingsTab):
|
||||
self.settings.setValue('theme level', self.theme_level)
|
||||
self.settings.setValue('global theme', self.global_theme)
|
||||
self.settings.setValue('wrap footer', self.wrap_footer_check_box.isChecked())
|
||||
self.settings.setValue('item transitions', self.item_transitions_check_box.isChecked())
|
||||
self.settings.endGroup()
|
||||
self.renderer.set_theme_level(self.theme_level)
|
||||
if self.tab_visited:
|
||||
|
@ -32,6 +32,7 @@ from PyQt5 import QtCore
|
||||
sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
|
||||
|
||||
from openlp.core.display.window import DisplayWindow
|
||||
from openlp.core.ui import HideMode
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@ -103,6 +104,31 @@ def test_set_scale_initialised(mocked_webengine, mocked_addWidget, mock_settings
|
||||
display_window.run_javascript.assert_called_once_with('Display.setScale(50.0);')
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
def test_after_loaded(mocked_webengine, mocked_addWidget, mock_settings):
|
||||
"""
|
||||
Test the correct steps are taken when the webview is loaded
|
||||
"""
|
||||
# GIVEN: An initialised display window and settings for item transitions returns true
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = True
|
||||
mock_settings.value.return_value = True
|
||||
display_window.scale = 2
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.set_scale = MagicMock()
|
||||
display_window.set_startup_screen = MagicMock()
|
||||
|
||||
# WHEN: after_loaded is run
|
||||
display_window.after_loaded()
|
||||
|
||||
# THEN: The following functions should have been called
|
||||
display_window.run_javascript.assert_called_once_with('Display.init(true, true);')
|
||||
display_window.set_scale.assert_called_once_with(2)
|
||||
display_window.set_startup_screen.assert_called_once()
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
@patch.object(time, 'time')
|
||||
@ -146,3 +172,75 @@ def test_run_javascript_sync_no_wait(mock_time, mocked_webengine, mocked_addWidg
|
||||
assert result == 1234
|
||||
webengine_page.runJavaScript.assert_called_once()
|
||||
mock_time.sleep.assert_not_called()
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
def test_hide_display_to_screen(mocked_webengine, mocked_addWidget, mock_settings):
|
||||
"""
|
||||
Test hide to screen in the hide_display function
|
||||
"""
|
||||
# GIVEN:
|
||||
display_window = DisplayWindow()
|
||||
display_window.setVisible = MagicMock()
|
||||
|
||||
# WHEN: Hide display is run with no mode (should default to Screen)
|
||||
display_window.hide_display()
|
||||
|
||||
# THEN: Should hide the display and set the hide mode
|
||||
display_window.setVisible.assert_called_once_with(False)
|
||||
assert display_window.hide_mode == HideMode.Screen
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
def test_hide_display_to_blank(mocked_webengine, mocked_addWidget, mock_settings):
|
||||
"""
|
||||
Test hide to screen in the hide_display function
|
||||
"""
|
||||
# GIVEN:
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
|
||||
# WHEN: Hide display is run with HideMode.Blank
|
||||
display_window.hide_display(HideMode.Blank)
|
||||
|
||||
# THEN: Should run the correct javascript on the display and set the hide mode
|
||||
display_window.run_javascript.assert_called_once_with('Display.toBlack();')
|
||||
assert display_window.hide_mode == HideMode.Blank
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
def test_hide_display_to_theme(mocked_webengine, mocked_addWidget, mock_settings):
|
||||
"""
|
||||
Test hide to screen in the hide_display function
|
||||
"""
|
||||
# GIVEN:
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
|
||||
# WHEN: Hide display is run with HideMode.Theme
|
||||
display_window.hide_display(HideMode.Theme)
|
||||
|
||||
# THEN: Should run the correct javascript on the display and set the hide mode
|
||||
display_window.run_javascript.assert_called_once_with('Display.toTheme();')
|
||||
assert display_window.hide_mode == HideMode.Theme
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
def test_hide_display_to_transparent(mocked_webengine, mocked_addWidget, mock_settings):
|
||||
"""
|
||||
Test hide to screen in the hide_display function
|
||||
"""
|
||||
# GIVEN:
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
|
||||
# WHEN: Hide display is run with HideMode.Transparent
|
||||
display_window.hide_display(HideMode.Transparent)
|
||||
|
||||
# THEN: Should run the correct javascript on the display and set the hide mode
|
||||
display_window.run_javascript.assert_called_once_with('Display.toTransparent();')
|
||||
assert display_window.hide_mode == HideMode.Transparent
|
||||
|
@ -324,3 +324,23 @@ def test_setup_display(MockItemMediaInfo, media_env):
|
||||
assert controller.has_audio is False
|
||||
media_env.media_controller._define_display.assert_called_once_with(controller)
|
||||
media_env.media_controller.vlc_player.setup(controller, mocked_display, False)
|
||||
|
||||
|
||||
def test_media_play(media_env):
|
||||
"""
|
||||
Test that the display/controllers are set up correctly
|
||||
"""
|
||||
# GIVEN: A mocked controller where is_background is false
|
||||
media_env.current_media_players = MagicMock()
|
||||
Registry().register('settings', MagicMock())
|
||||
media_env.live_timer = MagicMock()
|
||||
mocked_controller = MagicMock()
|
||||
mocked_controller.media_info.is_background = False
|
||||
|
||||
# WHEN: media_play is called
|
||||
result = media_env.media_play(mocked_controller)
|
||||
|
||||
# THEN: The web display should become transparent (only tests that the theme is reset here)
|
||||
# And the function should return true to indicate success
|
||||
assert result is True
|
||||
mocked_controller._set_theme.assert_called_once()
|
||||
|
@ -43,6 +43,29 @@ def test_initial_slide_controller(registry):
|
||||
assert slide_controller.is_live is False, 'The base slide controller should not be a live controller'
|
||||
|
||||
|
||||
def test_slide_selected(settings):
|
||||
"""
|
||||
Test the slide selected method
|
||||
"""
|
||||
# GIVEN: A new SlideController instance on slide 4 of 10, and is not a command
|
||||
slide_controller = SlideController(None)
|
||||
slide_controller.update_preview = MagicMock()
|
||||
slide_controller.slide_selected_lock = MagicMock()
|
||||
slide_controller.service_item = MagicMock()
|
||||
slide_controller.service_item.is_command.return_value = False
|
||||
slide_controller.preview_widget = MagicMock()
|
||||
slide_controller.preview_widget.slide_count.return_value = 10
|
||||
slide_controller.preview_widget.current_slide_number.return_value = 4
|
||||
mocked_display = MagicMock()
|
||||
slide_controller.displays = [mocked_display]
|
||||
|
||||
# WHEN: The slide_selected method is run
|
||||
slide_controller.slide_selected(True)
|
||||
|
||||
# THEN: The display is updated with the slide number
|
||||
mocked_display.go_to_slide.assert_called_once_with(4)
|
||||
|
||||
|
||||
def test_text_service_item_blank(settings):
|
||||
"""
|
||||
Test that loading a text-based service item into the slide controller sets the correct blank menu
|
||||
|
@ -76,6 +76,7 @@ describe("The function", function () {
|
||||
});
|
||||
|
||||
describe("The Display object", function () {
|
||||
|
||||
it("should start with a blank _slides object", function () {
|
||||
expect(Display._slides).toEqual({});
|
||||
});
|
||||
@ -107,6 +108,8 @@ describe("The Display object", function () {
|
||||
|
||||
it("should initialise Reveal when init is called", function () {
|
||||
spyOn(Reveal, "initialize");
|
||||
document.body.innerHTML = "";
|
||||
_createDiv({"id": "global-background"});
|
||||
Display.init();
|
||||
expect(Reveal.initialize).toHaveBeenCalled();
|
||||
});
|
||||
@ -123,16 +126,18 @@ describe("The Display object", function () {
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("should have a setTransition() method", function () {
|
||||
expect(Display.setTransition).toBeDefined();
|
||||
it("should have a setItemTransition() method", function () {
|
||||
expect(Display.setItemTransition).toBeDefined();
|
||||
});
|
||||
|
||||
it("should have a correctly functioning clearSlides() method", function () {
|
||||
expect(Display.clearSlides).toBeDefined();
|
||||
|
||||
document.body.innerHTML = "";
|
||||
var slidesDiv = _createDiv({"class": "slides"});
|
||||
slidesDiv.innerHTML = "<section><p></p></section>";
|
||||
Display._slidesContainer = slidesDiv;
|
||||
var footerDiv = _createDiv({"class": "footer"});
|
||||
Display._footerContainer = footerDiv;
|
||||
|
||||
Display.clearSlides();
|
||||
expect($(".slides")[0].innerHTML).toEqual("");
|
||||
@ -167,42 +172,48 @@ describe("Transitions", function () {
|
||||
Display._theme = null;
|
||||
});
|
||||
|
||||
it("should have a correctly functioning setTransition() method", function () {
|
||||
it("should have a correctly functioning setItemTransition() method", function () {
|
||||
spyOn(Reveal, "configure");
|
||||
Display.setTransition("fade", "slow");
|
||||
expect(Reveal.configure).toHaveBeenCalledWith({"transition": "fade", "transitionSpeed": "slow"});
|
||||
Display.setItemTransition(true);
|
||||
expect(Reveal.configure).toHaveBeenCalledWith({"backgroundTransition": "fade", "transitionSpeed": "default"});
|
||||
});
|
||||
|
||||
it("should have enabled transitions when _doTransitions is true and setTheme is run", function () {
|
||||
spyOn(Display, "setTransition");
|
||||
it("should have enabled transitions when _doTransitions is true and applyTheme is run", function () {
|
||||
Display._doTransitions = true;
|
||||
var theme = {
|
||||
"display_slide_transition": true,
|
||||
"display_slide_transition_type": TransitionType.Slide,
|
||||
"display_slide_transition_speed": TransitionSpeed.Fast
|
||||
}
|
||||
|
||||
Display.setTheme(theme);
|
||||
var slidesDiv = _createDiv({"class": "slides"});
|
||||
slidesDiv.innerHTML = "<section><section><p></p></section></section>";
|
||||
Display._slidesContainer = slidesDiv;
|
||||
|
||||
expect(Display.setTransition).toHaveBeenCalledWith("slide-horizontal", "fast");
|
||||
Display.applyTheme(Display._slidesContainer.children[0])
|
||||
|
||||
expect(Display._slidesContainer.children[0].children[0].getAttribute("data-transition")).toEqual("slide-horizontal");
|
||||
expect(Display._slidesContainer.children[0].children[0].getAttribute("data-transition-speed")).toEqual("fast");
|
||||
});
|
||||
|
||||
it("should have not enabled transitions when init() with no transitions and setTheme is run", function () {
|
||||
spyOn(Display, "setTransition");
|
||||
Display._doTransitions = false;
|
||||
var theme = {
|
||||
"display_slide_transition": true,
|
||||
"display_slide_transition_type": TransitionType.Slide,
|
||||
"display_slide_transition_speed": TransitionSpeed.Fast,
|
||||
}
|
||||
|
||||
Display.setTheme(theme);
|
||||
var slidesDiv = _createDiv({"class": "slides"});
|
||||
slidesDiv.innerHTML = "<section><section><p></p></section></section>";
|
||||
Display._slidesContainer = slidesDiv;
|
||||
|
||||
expect(Display.setTransition).toHaveBeenCalledWith("none", "default");
|
||||
Display.applyTheme(Display._slidesContainer.children[0])
|
||||
|
||||
expect(Display._slidesContainer.children[0].children[0].getAttribute("data-transition")).toEqual("none");
|
||||
});
|
||||
|
||||
it("should have enabled transitions in the correct direction", function () {
|
||||
spyOn(Display, "setTransition");
|
||||
Display._doTransitions = true;
|
||||
var theme = {
|
||||
"display_slide_transition": true,
|
||||
@ -211,10 +222,15 @@ describe("Transitions", function () {
|
||||
"display_slide_transition_direction": TransitionDirection.Vertical,
|
||||
"display_slide_transition_reverse": true,
|
||||
}
|
||||
|
||||
Display.setTheme(theme);
|
||||
var slidesDiv = _createDiv({"class": "slides"});
|
||||
slidesDiv.innerHTML = "<section><section><p></p></section></section>";
|
||||
Display._slidesContainer = slidesDiv;
|
||||
|
||||
expect(Display.setTransition).toHaveBeenCalledWith("convex-vertical-reverse", "slow");
|
||||
Display.applyTheme(Display._slidesContainer.children[0])
|
||||
|
||||
expect(Display._slidesContainer.children[0].children[0].getAttribute("data-transition")).toEqual("convex-vertical-reverse");
|
||||
expect(Display._slidesContainer.children[0].children[0].getAttribute("data-transition-speed")).toEqual("slow");
|
||||
});
|
||||
|
||||
});
|
||||
@ -504,63 +520,49 @@ describe("Display.alertAnimationEndEvent", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Display.addTextSlide", function () {
|
||||
describe("Display.setTextSlide", function () {
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
_createDiv({"class": "slides"});
|
||||
_createDiv({"class": "footer"});
|
||||
var slides_container = _createDiv({"class": "slides"});
|
||||
var footer_container = _createDiv({"class": "footer"});
|
||||
Display._slidesContainer = slides_container;
|
||||
Display._footerContainer = footer_container;
|
||||
Display._slides = {};
|
||||
});
|
||||
|
||||
it("should add a new slide", function () {
|
||||
var verse = "v1",
|
||||
text = "Amazing grace,\nhow sweet the sound",
|
||||
footer = "Public Domain";
|
||||
var text = "Amazing grace,\nhow sweet the sound";
|
||||
spyOn(Display, "reinit");
|
||||
|
||||
Display.addTextSlide(verse, text, footer);
|
||||
Display.setTextSlide(text);
|
||||
|
||||
expect(Display._slides[verse]).toEqual(0);
|
||||
expect(Display._slides["test-slide"]).toEqual(0);
|
||||
expect($(".slides > section > section").length).toEqual(1);
|
||||
expect($(".slides > section > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should add a new slide without calling reinit()", function () {
|
||||
var verse = "v1",
|
||||
text = "Amazing grace,\nhow sweet the sound",
|
||||
footer = "Public Domain";
|
||||
spyOn(Display, "reinit");
|
||||
|
||||
Display.addTextSlide(verse, text, footer, false);
|
||||
|
||||
expect(Display._slides[verse]).toEqual(0);
|
||||
expect($(".slides > section > section").length).toEqual(1);
|
||||
expect($(".slides > section > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should update an existing slide", function () {
|
||||
var verse = "v1",
|
||||
text = "Amazing grace, how sweet the sound\nThat saved a wretch like me",
|
||||
footer = "Public Domain";
|
||||
Display.addTextSlide(verse, "Amazing grace,\nhow sweet the sound", footer, false);
|
||||
var text = "That saved a wretch\nlike me";
|
||||
spyOn(Display, "reinit");
|
||||
Display.setTextSlide("Amazing grace,\nhow sweet the sound");
|
||||
|
||||
Display.addTextSlide(verse, text, footer, true);
|
||||
Display.setTextSlide(text);
|
||||
|
||||
expect(Display._slides[verse]).toEqual(0);
|
||||
expect(Display._slides["test-slide"]).toEqual(0);
|
||||
expect($(".slides > section > section").length).toEqual(1);
|
||||
expect($(".slides > section > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(0);
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1); // only called once for the first setTextSlide
|
||||
});
|
||||
});
|
||||
|
||||
describe("Display.setTextSlides", function () {
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
_createDiv({"class": "slides"});
|
||||
_createDiv({"class": "footer"});
|
||||
var slides_container = _createDiv({"class": "slides"});
|
||||
var footer_container = _createDiv({"class": "footer"});
|
||||
Display._slidesContainer = slides_container;
|
||||
Display._footerContainer = footer_container;
|
||||
_createDiv({"id": "global-background"});
|
||||
Display._slides = {};
|
||||
});
|
||||
@ -581,15 +583,16 @@ describe("Display.setTextSlides", function () {
|
||||
}
|
||||
];
|
||||
spyOn(Display, "clearSlides");
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
expect(Display.clearSlides).toHaveBeenCalledTimes(1);
|
||||
expect(Display.clearSlides).toHaveBeenCalledTimes(0);
|
||||
expect(Display._slides["v1"]).toEqual(0);
|
||||
expect(Display._slides["v2"]).toEqual(1);
|
||||
expect($(".slides > section > section").length).toEqual(2);
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1);
|
||||
expect(Reveal.sync).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should correctly set outline width", function () {
|
||||
@ -607,7 +610,7 @@ describe("Display.setTextSlides", function () {
|
||||
'font_main_outline_size': 42,
|
||||
'font_main_outline_color': 'red'
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
@ -633,7 +636,7 @@ describe("Display.setTextSlides", function () {
|
||||
'display_horizontal_align': 3,
|
||||
'display_vertical_align': 1
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
@ -659,7 +662,7 @@ describe("Display.setTextSlides", function () {
|
||||
'font_main_shadow_color': "#000",
|
||||
'font_main_shadow_size': 5
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
@ -684,7 +687,7 @@ describe("Display.setTextSlides", function () {
|
||||
'font_main_shadow_color': "#000",
|
||||
'font_main_shadow_size': 5
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
@ -710,7 +713,7 @@ describe("Display.setTextSlides", function () {
|
||||
'font_main_width': 1230,
|
||||
'font_main_height': 4560
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
@ -727,20 +730,21 @@ describe("Display.setTextSlides", function () {
|
||||
describe("Display.setImageSlides", function () {
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
_createDiv({"class": "slides"});
|
||||
_createDiv({"class": "footer"});
|
||||
var slides_container = _createDiv({"class": "slides"});
|
||||
var footer_container = _createDiv({"class": "footer"});
|
||||
Display._slidesContainer = slides_container;
|
||||
Display._footerContainer = footer_container;
|
||||
_createDiv({"id": "global-background"});
|
||||
Display._slides = {};
|
||||
});
|
||||
|
||||
it("should add a list of images", function () {
|
||||
var slides = [{"path": "file:///openlp1.jpg"}, {"path": "file:///openlp2.jpg"}];
|
||||
spyOn(Display, "clearSlides");
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setImageSlides(slides);
|
||||
|
||||
expect(Display.clearSlides).toHaveBeenCalledTimes(1);
|
||||
expect(Display._slides["0"]).toEqual(0);
|
||||
expect(Display._slides["1"]).toEqual(1);
|
||||
expect($(".slides > section > section").length).toEqual(2);
|
||||
@ -749,30 +753,30 @@ describe("Display.setImageSlides", function () {
|
||||
expect($(".slides > section > section > img")[0].getAttribute("style")).toEqual("max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);")
|
||||
expect($(".slides > section > section > img")[1].getAttribute("src")).toEqual("file:///openlp2.jpg")
|
||||
expect($(".slides > section > section > img")[1].getAttribute("style")).toEqual("max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);")
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1);
|
||||
expect(Reveal.sync).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Display.setVideo", function () {
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
_createDiv({"class": "slides"});
|
||||
var slides_container = _createDiv({"class": "slides"});
|
||||
Display._slidesContainer = slides_container;
|
||||
_createDiv({"id": "global-background"});
|
||||
Display._slides = {};
|
||||
});
|
||||
|
||||
it("should add a video to the page", function () {
|
||||
var video = {"path": "file:///video.mp4"};
|
||||
spyOn(Display, "clearSlides");
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setVideo(video);
|
||||
|
||||
expect(Display.clearSlides).toHaveBeenCalledTimes(1);
|
||||
expect($(".slides > section").length).toEqual(1);
|
||||
expect($(".slides > section > video").length).toEqual(1);
|
||||
expect($(".slides > section > video")[0].src).toEqual("file:///video.mp4")
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1);
|
||||
expect(Reveal.sync).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user