diff --git a/openlp/core/display/html/display.css b/openlp/core/display/html/display.css
index cb79612e6..d45aca116 100644
--- a/openlp/core/display/html/display.css
+++ b/openlp/core/display/html/display.css
@@ -98,3 +98,387 @@ sup {
transition: opacity 0.5s linear;
z-index: 100;
}
+
+/*********************************************
+ * Transition overrides to allow different directions
+ *********************************************/
+/*********************************************
+ * SLIDE TRANSITION
+ * Aliased 'linear' for backwards compatibility
+ *********************************************/
+.reveal .slides section[data-transition~=concave].stack,
+.reveal[class~=slide] .slides section.stack {
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d; }
+
+.reveal .slides > section[data-transition=slide].past,
+.reveal .slides > section[data-transition~=slide-out].past,
+.reveal.slide .slides > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=slide-horizontal].past,
+.reveal .slides > section > section[data-transition~=slide-horizontal-out].past,
+.reveal.slide-horizontal .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=slide-horizontal-reverse].future,
+.reveal .slides > section > section[data-transition~=slide-horizontal-reverse-in].future,
+.reveal.slide-horizontal-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: translate(-150%, 0);
+ transform: translate(-150%, 0); }
+
+.reveal .slides > section[data-transition=slide].future,
+.reveal .slides > section[data-transition~=slide-in].future,
+.reveal.slide .slides > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=slide-horizontal].future,
+.reveal .slides > section > section[data-transition~=slide-horizontal-in].future,
+.reveal.slide-horizontal .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=slide-horizontal-reverse].past,
+.reveal .slides > section > section[data-transition~=slide-horizontal-reverse-out].past,
+.reveal.slide-horizontal-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: translate(150%, 0);
+ transform: translate(150%, 0); }
+
+.reveal .slides > section > section[data-transition=slide-vertical].past,
+.reveal .slides > section > section[data-transition~=slide-vertical-out].past,
+.reveal.slide-vertical .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=slide-vertical-reverse].future,
+.reveal .slides > section > section[data-transition~=slide-vertical-reverse-in].future,
+.reveal.slide-vertical-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: translate(0, -150%);
+ transform: translate(0, -150%); }
+
+.reveal .slides > section > section[data-transition=slide-vertical].future,
+.reveal .slides > section > section[data-transition~=slide-vertical-in].future,
+.reveal.slide-vertical .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=slide-vertical-reverse].past,
+.reveal .slides > section > section[data-transition~=slide-vertical-reverse-out].past,
+.reveal.slide-vertical-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: translate(0, 150%);
+ transform: translate(0, 150%); }
+
+/*********************************************
+ * CONVEX TRANSITION
+ * Aliased 'default' for backwards compatibility
+ *********************************************/
+.reveal .slides section[data-transition~=convex].stack,
+.reveal[class~=convex] .slides section.stack {
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d; }
+
+.reveal .slides > section[data-transition=convex].past,
+.reveal .slides > section[data-transition~=convex-out].past,
+.reveal.convex .slides > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=convex-horizontal].past,
+.reveal .slides > section > section[data-transition~=convex-horizontal-out].past,
+.reveal.convex-horizontal .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=convex-horizontal-reverse].future,
+.reveal .slides > section > section[data-transition~=convex-horizontal-reverse-in].future,
+.reveal.convex-horizontal-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); }
+
+.reveal .slides > section[data-transition=convex].future,
+.reveal .slides > section[data-transition~=convex-in].future,
+.reveal.convex .slides > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=convex-horizontal].future,
+.reveal .slides > section > section[data-transition~=convex-horizontal-in].future,
+.reveal.convex-horizontal .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=convex-horizontal-reverse].past,
+.reveal .slides > section > section[data-transition~=convex-horizontal-reverse-out].past,
+.reveal.convex-horizontal-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); }
+
+.reveal .slides > section > section[data-transition=convex-vertical].past,
+.reveal .slides > section > section[data-transition~=convex-vertical-out].past,
+.reveal.convex-vertical .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=convex-vertical-reverse].future,
+.reveal .slides > section > section[data-transition~=convex-vertical-reverse-in].future,
+.reveal.convex-vertical-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0);
+ transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); }
+
+.reveal .slides > section > section[data-transition=convex-vertical].future,
+.reveal .slides > section > section[data-transition~=convex-vertical-in].future,
+.reveal.convex-vertical .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=convex-vertical-reverse].past,
+.reveal .slides > section > section[data-transition~=convex-vertical-reverse-out].past,
+.reveal.convex-vertical-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0);
+ transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); }
+
+/*********************************************
+ * CONCAVE TRANSITION
+ *********************************************/
+.reveal .slides section[data-transition~=concave].stack,
+.reveal[class~=concave] .slides section.stack {
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d; }
+
+.reveal .slides > section[data-transition=concave-vertical].past,
+.reveal .slides > section[data-transition~=concave-vertical-out].past,
+.reveal.concave-vertical .slides > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=concave-horizontal].past,
+.reveal .slides > section > section[data-transition~=concave-horizontal-out].past,
+.reveal.concave-horizontal .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=concave-horizontal-reverse].future,
+.reveal .slides > section > section[data-transition~=concave-horizontal-reverse-in].future,
+.reveal.concave-horizontal-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); }
+
+.reveal .slides > section[data-transition=concave-vertical].future,
+.reveal .slides > section[data-transition~=concave-vertical-in].future,
+.reveal.concave-vertical .slides > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=concave-horizontal].future,
+.reveal .slides > section > section[data-transition~=concave-horizontal-in].future,
+.reveal.concave-horizontal .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=concave-horizontal-reverse].past,
+.reveal .slides > section > section[data-transition~=concave-horizontal-reverse-out].past,
+.reveal.concave-horizontal-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); }
+
+.reveal .slides > section > section[data-transition=concave-vertical].past,
+.reveal .slides > section > section[data-transition~=concave-vertical-out].past,
+.reveal.concave-vertical .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=concave-vertical-reverse].future,
+.reveal .slides > section > section[data-transition~=concave-vertical-reverse-in].future,
+.reveal.concave-vertical-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: translate3d(0, -80%, 0) rotateX(-70deg) translate3d(0, -80%, 0);
+ transform: translate3d(0, -80%, 0) rotateX(-70deg) translate3d(0, -80%, 0); }
+
+.reveal .slides > section > section[data-transition=concave-vertical].future,
+.reveal .slides > section > section[data-transition~=concave-vertical-in].future,
+.reveal.concave-vertical .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=concave-vertical-reverse].past,
+.reveal .slides > section > section[data-transition~=concave-vertical-reverse-out].past,
+.reveal.concave-vertical-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: translate3d(0, 80%, 0) rotateX(70deg) translate3d(0, 80%, 0);
+ transform: translate3d(0, 80%, 0) rotateX(70deg) translate3d(0, 80%, 0); }
+
+/*********************************************
+ * ZOOM TRANSITION
+ *********************************************/
+.reveal .slides section[data-transition~=zoom],
+.reveal[class~=zoom] .slides section:not([data-transition]) {
+ transition-timing-function: ease; }
+
+.reveal .slides > section[data-transition=zoom].past,
+.reveal .slides > section[data-transition~=zoom-out].past,
+.reveal.zoom .slides > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=zoom-horizontal].past,
+.reveal .slides > section > section[data-transition~=zoom-horizontal-out].past,
+.reveal.zoom-horizontal .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=zoom-horizontal-reverse].future,
+.reveal .slides > section > section[data-transition~=zoom-horizontal-reverse-in].future,
+.reveal.zoom-horizontal-reverse .slides > section > section:not([data-transition]).future {
+ visibility: hidden;
+ -webkit-transform: scale(16);
+ transform: scale(16); }
+
+.reveal .slides > section[data-transition=zoom].future,
+.reveal .slides > section[data-transition~=zoom-in].future,
+.reveal.zoom .slides > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=zoom-horizontal].future,
+.reveal .slides > section > section[data-transition~=zoom-horizontal-in].future,
+.reveal.zoom-horizontal .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=zoom-horizontal-reverse].past,
+.reveal .slides > section > section[data-transition~=zoom-horizontal-reverse-out].past,
+.reveal.zoom-horizontal-reverse .slides > section > section:not([data-transition]).past {
+ visibility: hidden;
+ -webkit-transform: scale(0.2);
+ transform: scale(0.2); }
+
+.reveal .slides > section > section[data-transition=zoom-vertical].past,
+.reveal .slides > section > section[data-transition~=zoom-vertical-out].past,
+.reveal.zoom-vertical .slides > section > section:not([data-transition]).past,
+.reveal .slides > section > section[data-transition=zoom-vertical-reverse].future,
+.reveal .slides > section > section[data-transition~=zoom-vertical-reverse-in].future,
+.reveal.zoom-vertical-reverse .slides > section > section:not([data-transition]).future {
+ -webkit-transform: scale(16);
+ transform: scale(16); }
+
+.reveal .slides > section > section[data-transition=zoom-vertical].future,
+.reveal .slides > section > section[data-transition~=zoom-vertical-in].future,
+.reveal.zoom-vertical .slides > section > section:not([data-transition]).future,
+.reveal .slides > section > section[data-transition=zoom-vertical-reverse].past,
+.reveal .slides > section > section[data-transition~=zoom-vertical-reverse-out].past,
+.reveal.zoom-vertical-reverse .slides > section > section:not([data-transition]).past {
+ -webkit-transform: scale(0.2);
+ transform: scale(0.2); }
+
+/*********************************************
+ * CUBE TRANSITION
+ *
+ * WARNING:
+ * this is deprecated and will be removed in a
+ * future version.
+ *********************************************/
+.reveal[class~=cube] .slides {
+ -webkit-perspective: 1300px;
+ perspective: 1300px; }
+
+.reveal[class~=cube] .slides section {
+ padding: 30px;
+ min-height: 700px;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ box-sizing: border-box;
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d; }
+
+.reveal.center[class~=cube] .slides section {
+ min-height: 0; }
+
+.reveal[class~=cube] .slides section:not(.stack):before {
+ content: '';
+ position: absolute;
+ display: block;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ background: rgba(0, 0, 0, 0.1);
+ border-radius: 4px;
+ -webkit-transform: translateZ(-20px);
+ transform: translateZ(-20px); }
+
+.reveal[class~=cube] .slides section:not(.stack):after {
+ content: '';
+ position: absolute;
+ display: block;
+ width: 90%;
+ height: 30px;
+ left: 5%;
+ bottom: 0;
+ background: none;
+ z-index: 1;
+ border-radius: 4px;
+ box-shadow: 0px 95px 25px rgba(0, 0, 0, 0.2);
+ -webkit-transform: translateZ(-90px) rotateX(65deg);
+ transform: translateZ(-90px) rotateX(65deg); }
+
+.reveal[class~=cube] .slides > section.stack {
+ padding: 0;
+ background: none; }
+
+.reveal.cube .slides > section.past,
+.reveal.cube-horizontal .slides > section > section.past,
+.reveal.cube-horizontal-reverse .slides > section > section.future {
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ -webkit-transform: translate3d(-100%, 0, 0) rotateY(-90deg);
+ transform: translate3d(-100%, 0, 0) rotateY(-90deg); }
+
+.reveal.cube .slides > section.future,
+.reveal.cube-horizontal .slides > section > section.future,
+.reveal.cube-horizontal-reverse .slides > section > section.past {
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ -webkit-transform: translate3d(100%, 0, 0) rotateY(90deg);
+ transform: translate3d(100%, 0, 0) rotateY(90deg); }
+
+.reveal.cube-vertical .slides > section > section.past,
+.reveal.cube-vertical-reverse .slides > section > section.future {
+ -webkit-transform-origin: 0% 100%;
+ transform-origin: 0% 100%;
+ -webkit-transform: translate3d(0, -100%, 0) rotateX(90deg);
+ transform: translate3d(0, -100%, 0) rotateX(90deg); }
+
+.reveal.cube-vertical .slides > section > section.future,
+.reveal.cube-vertical-reverse .slides > section > section.past {
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ -webkit-transform: translate3d(0, 100%, 0) rotateX(-90deg);
+ transform: translate3d(0, 100%, 0) rotateX(-90deg); }
+
+/*********************************************
+ * PAGE TRANSITION
+ *
+ * WARNING:
+ * this is deprecated and will be removed in a
+ * future version.
+ *********************************************/
+.reveal[class~=page] .slides {
+ -webkit-perspective-origin: 0% 50%;
+ perspective-origin: 0% 50%;
+ -webkit-perspective: 3000px;
+ perspective: 3000px; }
+
+.reveal[class~=page] .slides section {
+ padding: 30px;
+ min-height: 700px;
+ box-sizing: border-box;
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d; }
+
+.reveal[class~=page] .slides section.past {
+ z-index: 12; }
+
+.reveal[class~=page] .slides section:not(.stack):before {
+ content: '';
+ position: absolute;
+ display: block;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ background: rgba(0, 0, 0, 0.1);
+ -webkit-transform: translateZ(-20px);
+ transform: translateZ(-20px); }
+
+.reveal[class~=page] .slides section:not(.stack):after {
+ content: '';
+ position: absolute;
+ display: block;
+ width: 90%;
+ height: 30px;
+ left: 5%;
+ bottom: 0;
+ background: none;
+ z-index: 1;
+ border-radius: 4px;
+ box-shadow: 0px 95px 25px rgba(0, 0, 0, 0.2);
+ -webkit-transform: translateZ(-90px) rotateX(65deg); }
+
+.reveal[class~=page] .slides > section.stack {
+ padding: 0;
+ background: none; }
+
+.reveal.page .slides > section.past,
+.reveal.page-horizontal .slides > section > section.past,
+.reveal.page-horizontal-reverse .slides > section > section.future {
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ -webkit-transform: translate3d(-40%, 0, 0) rotateY(-80deg);
+ transform: translate3d(-40%, 0, 0) rotateY(-80deg); }
+
+.reveal.page .slides > section.future,
+.reveal.page-horizontal .slides > section > section.future,
+.reveal.page-horizontal-reverse .slides > section > section.past {
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0); }
+
+.reveal.page-vertical .slides > section > section.past,
+.reveal.page-vertical-reverse .slides > section > section.future {
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ -webkit-transform: translate3d(0, -40%, 0) rotateX(80deg);
+ transform: translate3d(0, -40%, 0) rotateX(80deg); }
+
+.reveal.page-vertical .slides > section > section.future,
+.reveal.page-vertical-reverse .slides > section > section.past {
+ -webkit-transform-origin: 0% 100%;
+ transform-origin: 0% 100%;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0); }
+
+/*********************************************
+ * FADE TRANSITION
+ *********************************************/
+.reveal .slides section[data-transition~=fade],
+.reveal[class~=fade] .slides section:not([data-transition]),
+.reveal[class~=fade] .slides > section > section:not([data-transition]) {
+ -webkit-transform: none;
+ transform: none;
+ transition: opacity 0.5s; }
\ No newline at end of file
diff --git a/openlp/core/display/html/display.js b/openlp/core/display/html/display.js
index 6d9284a2c..44ca1374b 100644
--- a/openlp/core/display/html/display.js
+++ b/openlp/core/display/html/display.js
@@ -63,6 +63,15 @@ var TransitionSpeed = {
Slow: 2
};
+
+/**
+ * Transition direction enumeration
+ */
+var TransitionDirection = {
+ Horizontal: 0,
+ Vertical: 1
+};
+
/**
* Audio state enumeration
*/
@@ -931,7 +940,19 @@ var Display = {
default:
new_transition_speed = "default";
}
+ switch (theme.display_slide_transition_direction) {
+ case TransitionDirection.Vertical:
+ new_transition_type += "-vertical";
+ break;
+ case TransitionDirection.Horizontal:
+ default:
+ new_transition_type += "-horizontal";
+ }
+ if (theme.display_slide_transition_reverse) {
+ new_transition_type += "-reverse";
+ }
}
+
Display.setTransition(new_transition_type, new_transition_speed);
// Set the background
var globalBackground = $("#global-background")[0];
diff --git a/openlp/core/lib/json/theme.json b/openlp/core/lib/json/theme.json
index 1a6018535..6504478d4 100644
--- a/openlp/core/lib/json/theme.json
+++ b/openlp/core/lib/json/theme.json
@@ -13,6 +13,8 @@
"slide_transition": false,
"slide_transition_type": 0,
"slide_transition_speed": 0,
+ "slide_transition_direction": 0,
+ "slide_transition_reverse": false,
"vertical_align": 0
},
"font": {
diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py
index a840a4a3c..5692fea01 100644
--- a/openlp/core/lib/theme.py
+++ b/openlp/core/lib/theme.py
@@ -203,6 +203,34 @@ class TransitionSpeed(object):
return TransitionSpeed.Slow
+class TransitionDirection(object):
+ """
+ Type enumeration for transition types.
+ """
+ Horizontal = 0
+ Vertical = 1
+
+ @staticmethod
+ def to_string(transition_direction):
+ """
+ Return a string representation of a transition type.
+ """
+ if transition_direction == TransitionDirection.Horizontal:
+ return 'horizontal'
+ elif transition_direction == TransitionDirection.Vertical:
+ return 'vertical'
+
+ @staticmethod
+ def from_string(type_string):
+ """
+ Return a transition type for the given string.
+ """
+ if type_string == 'horizontal':
+ return TransitionDirection.Horizontal
+ if type_string == 'vertical':
+ return TransitionDirection.Vertical
+
+
class HorizontalType(object):
"""
Type enumeration for horizontal alignment.
@@ -254,10 +282,11 @@ class VerticalType(object):
return VerticalType.Names.index(align)
-BOOLEAN_LIST = ['bold', 'italics', 'override', 'outline', 'shadow', 'slide_transition']
+BOOLEAN_LIST = ['bold', 'italics', 'override', 'outline', 'shadow', 'slide_transition', 'slide_transition_reverse']
INTEGER_LIST = ['size', 'line_adjustment', 'x', 'height', 'y', 'width', 'shadow_size', 'outline_size',
- 'horizontal_align', 'vertical_align', 'wrap_style', 'slide_transition_type', 'slide_transition_speed']
+ 'horizontal_align', 'vertical_align', 'wrap_style', 'slide_transition_type', 'slide_transition_speed',
+ 'slide_transition_direction']
class Theme(object):
diff --git a/openlp/core/pages/alignment.py b/openlp/core/pages/alignment.py
index b25a4e305..ddd9b7b31 100644
--- a/openlp/core/pages/alignment.py
+++ b/openlp/core/pages/alignment.py
@@ -24,7 +24,7 @@ The :mod:`~openlp.core.pages.alignment` module contains the alignment page used
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
-from openlp.core.lib.theme import HorizontalType, VerticalType, TransitionType, TransitionSpeed
+from openlp.core.lib.theme import HorizontalType, VerticalType, TransitionType, TransitionSpeed, TransitionDirection
from openlp.core.lib.ui import create_valign_selection_widgets
from openlp.core.pages import GridLayoutPage
from openlp.core.widgets.labels import FormLabel
@@ -69,11 +69,21 @@ class AlignmentTransitionsPage(GridLayoutPage):
self.layout.addWidget(self.transition_effect_combo_box, 4, 1)
self.transition_speed_label = FormLabel(self)
self.transition_speed_label.setObjectName('transition_speed_label')
- self.layout.addWidget(self.transition_speed_label, 4, 2)
+ self.layout.addWidget(self.transition_speed_label, 5, 0)
self.transition_speed_combo_box = QtWidgets.QComboBox(self)
self.transition_speed_combo_box.setObjectName('transition_speed_combo_box')
self.transition_speed_combo_box.addItems(['', '', ''])
- self.layout.addWidget(self.transition_speed_combo_box, 4, 3)
+ self.layout.addWidget(self.transition_speed_combo_box, 5, 1)
+ self.transition_direction_label = FormLabel(self)
+ self.transition_direction_label.setObjectName('transition_direction_label')
+ self.layout.addWidget(self.transition_direction_label, 4, 2)
+ self.transition_direction_combo_box = QtWidgets.QComboBox(self)
+ self.transition_direction_combo_box.setObjectName('transition_direction_combo_box')
+ self.transition_direction_combo_box.addItems(['', ''])
+ self.layout.addWidget(self.transition_direction_combo_box, 4, 3)
+ self.transition_reverse_check_box = QtWidgets.QCheckBox(self)
+ self.transition_reverse_check_box.setObjectName('transition_reverse_check_box')
+ self.layout.addWidget(self.transition_reverse_check_box, 5, 3)
# Connect slots
self.transitions_enabled_check_box.stateChanged.connect(self._on_transition_enabled_changed)
@@ -97,6 +107,12 @@ class AlignmentTransitionsPage(GridLayoutPage):
self.transition_speed_combo_box.setItemText(TransitionSpeed.Normal, translate('OpenLP.ThemeWizard', 'Normal'))
self.transition_speed_combo_box.setItemText(TransitionSpeed.Fast, translate('OpenLP.ThemeWizard', 'Fast'))
self.transition_speed_combo_box.setItemText(TransitionSpeed.Slow, translate('OpenLP.ThemeWizard', 'Slow'))
+ self.transition_direction_label.setText(translate('OpenLP.ThemeWizard', 'Direction:'))
+ self.transition_direction_combo_box.setItemText(TransitionDirection.Horizontal, translate('OpenLP.ThemeWizard',
+ 'Horizontal'))
+ self.transition_direction_combo_box.setItemText(TransitionDirection.Vertical, translate('OpenLP.ThemeWizard',
+ 'Vertical'))
+ self.transition_reverse_check_box.setText(translate('OpenLP.ThemeWizard', 'Reverse'))
def _on_transition_enabled_changed(self, value):
"""
@@ -106,6 +122,9 @@ class AlignmentTransitionsPage(GridLayoutPage):
self.transition_effect_combo_box.setEnabled(value)
self.transition_speed_label.setEnabled(value)
self.transition_speed_combo_box.setEnabled(value)
+ self.transition_direction_combo_box.setEnabled(value)
+ self.transition_direction_label.setEnabled(value)
+ self.transition_reverse_check_box.setEnabled(value)
@property
def horizontal_align(self):
@@ -167,3 +186,24 @@ class AlignmentTransitionsPage(GridLayoutPage):
self.transition_speed_combo_box.setCurrentIndex(value)
else:
raise TypeError('transition_speed must either be a string or an int')
+
+ @property
+ def transition_direction(self):
+ return self.transition_direction_combo_box.currentIndex()
+
+ @transition_direction.setter
+ def transition_direction(self, value):
+ if isinstance(value, str):
+ self.transition_direction_combo_box.setCurrentIndex(TransitionDirection.from_string(value))
+ elif isinstance(value, int):
+ self.transition_direction_combo_box.setCurrentIndex(value)
+ else:
+ raise TypeError('transition_direction must either be a string or an int')
+
+ @property
+ def is_transition_reverse_enabled(self):
+ return self.transition_reverse_check_box.isChecked()
+
+ @is_transition_reverse_enabled.setter
+ def is_transition_reverse_enabled(self, value):
+ self.transition_reverse_check_box.setChecked(value)
diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py
index 5f253851f..689b165b8 100644
--- a/openlp/core/ui/themeform.py
+++ b/openlp/core/ui/themeform.py
@@ -304,6 +304,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.alignment_page.is_transition_enabled = self.theme.display_slide_transition
self.alignment_page.transition_type = self.theme.display_slide_transition_type
self.alignment_page.transition_speed = self.theme.display_slide_transition_speed
+ self.alignment_page.transition_direction = self.theme.display_slide_transition_direction
+ self.alignment_page.is_transition_reverse_enabled = self.theme.display_slide_transition_reverse
def set_preview_page_values(self):
"""
@@ -371,6 +373,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.theme.display_slide_transition = self.alignment_page.is_transition_enabled
self.theme.display_slide_transition_type = self.alignment_page.transition_type
self.theme.display_slide_transition_speed = self.alignment_page.transition_speed
+ self.theme.display_slide_transition_direction = self.alignment_page.transition_direction
+ self.theme.display_slide_transition_reverse = self.alignment_page.is_transition_reverse_enabled
def accept(self):
"""
diff --git a/tests/functional/openlp_core/lib/test_theme.py b/tests/functional/openlp_core/lib/test_theme.py
index 7f7d944c3..9d92431ed 100644
--- a/tests/functional/openlp_core/lib/test_theme.py
+++ b/tests/functional/openlp_core/lib/test_theme.py
@@ -337,4 +337,4 @@ class TestTheme(TestCase):
assert 0 == theme.display_vertical_align, 'display_vertical_align should be 0'
assert theme.font_footer_bold is False, 'font_footer_bold should be False'
assert 'Arial' == theme.font_main_name, 'font_main_name should be "Arial"'
- assert 51 == len(theme.__dict__), 'The theme should have 51 attributes'
+ assert 53 == len(theme.__dict__), 'The theme should have 53 attributes'
diff --git a/tests/js/test_display.js b/tests/js/test_display.js
index 748ad9b6e..ce0298e37 100644
--- a/tests/js/test_display.js
+++ b/tests/js/test_display.js
@@ -184,7 +184,7 @@ describe("Transitions", function () {
Display.setTheme(theme);
- expect(Display.setTransition).toHaveBeenCalledWith("slide", "fast");
+ expect(Display.setTransition).toHaveBeenCalledWith("slide-horizontal", "fast");
});
it("should have not enabled transitions when init() with no transitions and setTheme is run", function () {
@@ -201,6 +201,22 @@ describe("Transitions", function () {
expect(Display.setTransition).toHaveBeenCalledWith("none", "default");
});
+ it("should have enabled transitions in the correct direction", function () {
+ spyOn(Display, "setTransition");
+ Display._doTransitions = true;
+ var theme = {
+ "display_slide_transition": true,
+ "display_slide_transition_type": TransitionType.Convex,
+ "display_slide_transition_speed": TransitionSpeed.Slow,
+ "display_slide_transition_direction": TransitionDirection.Vertical,
+ "display_slide_transition_reverse": true,
+ }
+
+ Display.setTheme(theme);
+
+ expect(Display.setTransition).toHaveBeenCalledWith("convex-vertical-reverse", "slow");
+ });
+
});
describe("Display.alert", function () {
diff --git a/tests/openlp_core/pages/test_alignment.py b/tests/openlp_core/pages/test_alignment.py
index 2a317d2a0..557c2c745 100644
--- a/tests/openlp_core/pages/test_alignment.py
+++ b/tests/openlp_core/pages/test_alignment.py
@@ -26,7 +26,7 @@ from unittest.mock import MagicMock
import pytest
-from openlp.core.lib.theme import HorizontalType, VerticalType, TransitionType, TransitionSpeed
+from openlp.core.lib.theme import HorizontalType, VerticalType, TransitionType, TransitionSpeed, TransitionDirection
from openlp.core.pages.alignment import AlignmentTransitionsPage
from tests.helpers.testmixin import TestMixin
@@ -66,6 +66,8 @@ class TestAlignmentTransitionsPage(TestCase, TestMixin):
assert page.transition_effect_combo_box.isEnabled()
assert page.transition_speed_label.isEnabled()
assert page.transition_speed_combo_box.isEnabled()
+ assert page.transition_direction_combo_box.isEnabled()
+ assert page.transition_reverse_check_box.isEnabled()
def test_get_horizontal_align(self):
"""
@@ -256,7 +258,7 @@ class TestAlignmentTransitionsPage(TestCase, TestMixin):
"""
Test the transition_speed getter
"""
- # GIVEN: A AlignmentTransitionsPage instance with the combobox set to index 1
+ # GIVEN: A AlignmentTransitionsPage instance with the combobox set to index 0
page = AlignmentTransitionsPage()
page.transition_speed_combo_box.setCurrentIndex(0)
@@ -303,3 +305,82 @@ class TestAlignmentTransitionsPage(TestCase, TestMixin):
# THEN: An exception is raised
with pytest.raises(TypeError, match='transition_speed must either be a string or an int'):
page.transition_speed = []
+
+ def test_get_transition_direction(self):
+ """
+ Test the transition_direction getter
+ """
+ # GIVEN: A AlignmentTransitionsPage instance with the combobox set to index 0
+ page = AlignmentTransitionsPage()
+ page.transition_direction_combo_box.setCurrentIndex(0)
+
+ # WHEN: The property is accessed
+ result = page.transition_direction
+
+ # THEN: The result should be correct
+ assert result == TransitionDirection.Horizontal
+
+ def test_set_transition_direction_int(self):
+ """
+ Test the transition_direction setter with an int
+ """
+ # GIVEN: A AlignmentTransitionsPage instance
+ page = AlignmentTransitionsPage()
+
+ # WHEN: The property is set
+ page.transition_direction = TransitionDirection.Horizontal
+
+ # THEN: The combobox should be correct
+ assert page.transition_direction_combo_box.currentIndex() == 0
+
+ def test_set_transition_direction_str(self):
+ """
+ Test the transition_direction setter with a str
+ """
+ # GIVEN: A AlignmentTransitionsPage instance
+ page = AlignmentTransitionsPage()
+
+ # WHEN: The property is set
+ page.transition_direction = TransitionDirection.to_string(TransitionDirection.Vertical)
+
+ # THEN: The combobox should be correct
+ assert page.transition_direction_combo_box.currentIndex() == 1
+
+ def test_set_transition_direction_exception(self):
+ """
+ Test the transition_direction setter with something other than a str or int
+ """
+ # GIVEN: A AlignmentTransitionsPage instance
+ page = AlignmentTransitionsPage()
+
+ # WHEN: The property is set
+ # THEN: An exception is raised
+ with pytest.raises(TypeError, match='transition_direction must either be a string or an int'):
+ page.transition_direction = []
+
+ def test_on_transition_reverse_getter(self):
+ """
+ Test the is_transition_reverse_enabled getter
+ """
+ # GIVEN: And instance of AlignmentTransitionsPage and transition_reverse checked
+ page = AlignmentTransitionsPage()
+ page.transition_reverse_check_box.setChecked(True)
+
+ # WHEN: The property is accessed
+ result = page.is_transition_reverse_enabled
+
+ # THEN: The result should be correct
+ assert result is True
+
+ def test_on_transition_reverse_setter(self):
+ """
+ Test the is_transition_reverse_enabled setter
+ """
+ # GIVEN: And instance of AlignmentTransitionsPage and transition_reverse checked
+ page = AlignmentTransitionsPage()
+
+ # WHEN: The property is set
+ page.is_transition_reverse_enabled = True
+
+ # THEN: The checkbox should be correct
+ assert page.transition_reverse_check_box.isChecked() is True