← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~manndarryl/openlp/trunk into lp:openlp

 

Darryl Mann has proposed merging lp:~manndarryl/openlp/trunk into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~manndarryl/openlp/trunk/+merge/239527

Added a few more options to the Theme Manager on background and output area pages.
-- 
https://code.launchpad.net/~manndarryl/openlp/trunk/+merge/239527
Your team OpenLP Core is requested to review the proposed merge of lp:~manndarryl/openlp/trunk into lp:openlp.
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py	2014-07-21 06:37:41 +0000
+++ openlp/core/lib/htmlbuilder.py	2014-10-24 02:22:21 +0000
@@ -399,7 +399,8 @@
 from PyQt4 import QtWebKit
 
 from openlp.core.common import Settings
-from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType
+from openlp.core.lib.theme import BackgroundColorType, BackgroundGradientType, \
+    VerticalType, HorizontalType, MediaAlignType, MediaScaleType
 
 log = logging.getLogger(__name__)
 
@@ -432,6 +433,7 @@
     display: none;
 }
 #bgimage {
+    position: absolute;
     z-index: 1;
 }
 #image {
@@ -544,7 +546,7 @@
 </script>
 </head>
 <body>
-<img id="bgimage" class="size" %s />
+<img id="bgimage" %s />
 <img id="image" class="size" %s />
 %s
 <div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
@@ -566,6 +568,7 @@
     :param image: Image media item - bytes
     :param plugins: The List of available plugins
     """
+    css_additions = ''
     width = screen['size'].width()
     height = screen['size'].height()
     theme_data = item.theme_data
@@ -574,13 +577,32 @@
         bgimage_src = 'src="data:image/png;base64,%s"' % background
     elif item.bg_image_bytes:
         bgimage_src = 'src="data:image/png;base64,%s"' % item.bg_image_bytes
+        if theme_data != None:
+            if theme_data.background_media_scale == MediaScaleType.to_string(MediaScaleType.Fullscreen):
+                left = (width - (item.image_width * height / item.image_height )) / 2
+                css_additions = '#bgimage { top:0; left:%dpx; width:auto; height:100%% }' % left
+            else:
+                media_alignment = MediaAlignType.from_string(theme_data.background_media_align)
+                if media_alignment & MediaAlignType.Top:
+                    top = 25
+                elif media_alignment & MediaAlignType.Bottom:
+                    top = item.footer.y() - item.image_height - 25
+                else:
+                    top = (height - item.image_height) / 2
+                if media_alignment & MediaAlignType.Left:
+                    left = 25
+                elif media_alignment & MediaAlignType.Right:
+                    left = width - item.image_width - 25
+                else:
+                    left = (width - item.image_width) / 2
+
+                css_additions = '#bgimage { top: %dpx; left: %dpx; }' % (top, left)
     else:
         bgimage_src = 'style="display:none;"'
     if image:
         image_src = 'src="data:image/png;base64,%s"' % image
     else:
         image_src = 'style="display:none;"'
-    css_additions = ''
     js_additions = ''
     html_additions = ''
     if plugins:
@@ -625,26 +647,26 @@
     theme = item.theme_data
     background = 'background-color: black'
     if theme:
-        if theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
+        if theme.background_color_type == BackgroundColorType.to_string(BackgroundColorType.Transparent):
             background = ''
-        elif theme.background_type == BackgroundType.to_string(BackgroundType.Solid):
+        elif theme.background_color_type == BackgroundColorType.to_string(BackgroundColorType.Solid):
             background = 'background-color: %s' % theme.background_color
         else:
-            if theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
+            if theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
                 background = 'background: -webkit-gradient(linear, left top, left bottom, from(%s), to(%s)) fixed' \
-                    % (theme.background_start_color, theme.background_end_color)
-            elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
+                    % (theme.background_color_start, theme.background_color_end)
+            elif theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
                 background = 'background: -webkit-gradient(linear, left top, right bottom, from(%s), to(%s)) fixed' \
-                    % (theme.background_start_color, theme.background_end_color)
-            elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftBottom):
+                    % (theme.background_color_start, theme.background_color_end)
+            elif theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftBottom):
                 background = 'background: -webkit-gradient(linear, left bottom, right top, from(%s), to(%s)) fixed' \
-                    % (theme.background_start_color, theme.background_end_color)
-            elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
+                    % (theme.background_color_start, theme.background_color_end)
+            elif theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
                 background = 'background: -webkit-gradient(linear, left top, right top, from(%s), to(%s)) fixed' % \
-                    (theme.background_start_color, theme.background_end_color)
+                    (theme.background_color_start, theme.background_color_end)
             else:
                 background = 'background: -webkit-gradient(radial, %s 50%%, 100, %s 50%%, %s, from(%s), to(%s)) fixed'\
-                    % (width, width, width, theme.background_start_color, theme.background_end_color)
+                    % (width, width, width, theme.background_color_start, theme.background_color_end)
     return background
 
 

=== modified file 'openlp/core/lib/imagemanager.py'
--- openlp/core/lib/imagemanager.py	2014-09-11 10:08:44 +0000
+++ openlp/core/lib/imagemanager.py	2014-10-24 02:22:21 +0000
@@ -117,6 +117,8 @@
             ratio does not match with the display ratio.
         :param width: The width of the image, defaults to -1 meaning that the screen width will be used.
         :param height: The height of the image, defaults to -1 meaning that the screen height will be used.
+        :param valign: Vertical alignment of image, either top, middle (default) or bottom
+        :param halign: Horizontal alignment of image, either left, center (default) or right
         """
         self.path = path
         self.image = None

=== modified file 'openlp/core/lib/json/theme.json'
--- openlp/core/lib/json/theme.json	2013-10-18 18:10:47 +0000
+++ openlp/core/lib/json/theme.json	2014-10-24 02:22:21 +0000
@@ -1,12 +1,16 @@
 {
     "background" : {
-        "border_color": "#000000",
         "color": "#000000",
-        "direction": "vertical",
-        "end_color": "#000000",
-        "filename": "",
-        "start_color": "#000000",
-        "type": "solid"
+        "color_type": "solid",
+        "color_end": "#000000",
+        "color_start": "#000000",
+        "color_direction": "vertical",
+        "media_type": "none",
+        "media_align": "middle-center",
+        "media_scale": "fullscreen",
+        "media_width": "-1",
+        "media_height": "-1",
+        "media_filename": ""
     },
     "display" :{
         "horizontal_align": 0,
@@ -16,40 +20,52 @@
     "font": {
         "footer": {
             "bold": false,
+            "bottom": 10,
             "color": "#FFFFFF",
             "height": 78,
             "italics": false,
+            "left": 10,
             "line_adjustment": 0,
+            "margin": "",
             "location": "",
+            "position": "location",
             "name": "Arial",
             "outline": false,
             "outline_color": "#000000",
             "outline_size": 2,
             "override": false,
+            "right": 10,
             "shadow": true,
             "shadow_color": "#000000",
             "shadow_size": 5,
             "size": 12,
+            "top": 0,
             "width": 1004,
             "x": 10,
             "y": 690
             },
         "main": {
             "bold": false,
+            "bottom": 10,
             "color": "#FFFFFF",
             "height": 690,
             "italics": false,
+            "left": 10,
             "line_adjustment": 0,
+            "margin": "margin",
             "location": "",
+            "position": "location",
             "name": "Arial",
             "outline": false,
             "outline_color": "#000000",
             "outline_size": 2,
             "override": false,
+            "right": 10,
             "shadow": true,
             "shadow_color": "#000000",
             "shadow_size": 5,
             "size": 40,
+            "top": 10,
             "width": 1004,
             "x": 10,
             "y": 10

=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2014-07-02 18:13:23 +0000
+++ openlp/core/lib/renderer.py	2014-10-24 02:22:21 +0000
@@ -122,9 +122,22 @@
         else:
             theme_data, main_rect, footer_rect = self._theme_dimensions[theme_name]
         # if No file do not update cache
-        if theme_data.background_filename:
-            self.image_manager.add_image(theme_data.background_filename,
-                                         ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
+        if theme_data.background_media_filename:
+            theme_background_color = QtCore.Qt.transparent
+            theme_media_width = int(theme_data.background_media_width)
+            theme_media_height = int(theme_data.background_media_height)
+            if theme_data.background_media_scale == 'auto':
+                image = QtGui.QImage(theme_data.background_media_filename)
+                theme_media_width = int(image.width())
+                theme_media_height = int(image.height())
+            if theme_data.background_color_type == 'solid':
+                theme_background_color = QtGui.QColor(theme_data.background_color)
+            self.image_manager.add_image(
+                theme_data.background_media_filename,
+                ImageSource.Theme,
+                theme_background_color,
+                theme_media_width,
+                theme_media_height)
 
     def pre_render(self, override_theme_data=None):
         """
@@ -211,9 +224,22 @@
             service_item.add_from_text(VERSE)
         service_item.raw_footer = FOOTER
         # if No file do not update cache
-        if theme_data.background_filename:
+        if theme_data.background_media_filename:
+            theme_background_color = QtCore.Qt.transparent
+            theme_media_width = int(theme_data.background_media_width)
+            theme_media_height = int(theme_data.background_media_height)
+            if theme_data.background_media_scale == 'auto':
+                image = QtGui.QImage(theme_data.background_media_filename)
+                theme_media_width = int(image.width())
+                theme_media_height = int(image.height())
+            if theme_data.background_color_type == 'solid':
+                theme_background_color = QtGui.QColor(theme_data.background_color)
             self.image_manager.add_image(
-                theme_data.background_filename, ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
+                theme_data.background_media_filename,
+                ImageSource.Theme,
+                theme_background_color,
+                theme_media_width,
+                theme_media_height)
         theme_data, main, footer = self.pre_render(theme_data)
         service_item.theme_data = theme_data
         service_item.main = main
@@ -326,11 +352,18 @@
 
         :param theme_data: The theme information
         """
-        if not theme_data.font_main_override:
-            return QtCore.QRect(10, 0, self.width - 20, self.footer_start)
-        else:
+        font_footer_top = self.get_footer_top(theme_data)
+        if theme_data.font_main_override == 0:
+            return QtCore.QRect(10, 0, self.width - 20, font_footer_top)
+        elif theme_data.font_main_override == 1:
             return QtCore.QRect(theme_data.font_main_x, theme_data.font_main_y,
-                                theme_data.font_main_width - 1, theme_data.font_main_height - 1)
+                                theme_data.font_main_width - 1, font_footer_top - 1)
+        elif theme_data.font_main_override == 3:
+            main_width = self.width - theme_data.font_main_left - theme_data.font_main_right - 1
+            main_height = font_footer_top - theme_data.font_main_top - theme_data.font_main_bottom - 1
+            return QtCore.QRect(theme_data.font_main_left,theme_data.font_main_top, main_width, main_height)
+        else:
+            return QtCore.QRect(20, 20, self.width - 40, font_footer_top - 40)
 
     def get_footer_rectangle(self, theme_data):
         """
@@ -338,12 +371,34 @@
 
         :param theme_data: The theme data.
         """
-        if not theme_data.font_footer_override:
-            return QtCore.QRect(10, self.footer_start, self.width - 20, self.height - self.footer_start)
-        else:
+        font_footer_top = self.get_footer_top(theme_data)
+        if theme_data.font_footer_override == 0:
+            return QtCore.QRect(10, font_footer_top, self.width - 20, self.height - font_footer_top)
+        elif theme_data.font_footer_override == 1:
             return QtCore.QRect(theme_data.font_footer_x,
                                 theme_data.font_footer_y, theme_data.font_footer_width - 1,
                                 theme_data.font_footer_height - 1)
+        elif theme_data.font_footer_override == 3:
+            return QtCore.QRect(theme_data.font_footer_left, font_footer_top,
+                                self.width - theme_data.font_footer_left - theme_data.font_footer_right - 1,
+                                theme_data.font_footer_height - 1)
+        else:
+            return QtCore.QRect(20, font_footer_top, self.width - 40, theme_data.font_footer_height - 1)
+
+    def get_footer_top(self, theme_data):
+        """
+        Calculates the footer top coordinate
+
+        :param theme_data: The theme information
+        """
+        if theme_data.font_footer_override == 0:
+            return self.footer_start
+        elif theme_data.font_footer_override == 1:
+            return theme_data.font_footer_y
+        elif theme_data.font_footer_override == 3:
+            return self.height - theme_data.font_footer_height - theme_data.font_footer_bottom
+        else:
+            return self.height - 78 - 20
 
     def _set_text_rectangle(self, theme_data, rect_main, rect_footer):
         """

=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py	2014-03-17 19:05:55 +0000
+++ openlp/core/lib/theme.py	2014-10-24 02:22:21 +0000
@@ -43,43 +43,150 @@
 log = logging.getLogger(__name__)
 
 
-class BackgroundType(object):
+class BackgroundColorType(object):
     """
-    Type enumeration for backgrounds.
+    Color type enumeration for backgrounds.
     """
     Solid = 0
     Gradient = 1
-    Image = 2
-    Transparent = 3
+    Transparent = 2
 
     @staticmethod
-    def to_string(background_type):
-        """
-        Return a string representation of a background type.
-        """
-        if background_type == BackgroundType.Solid:
+    def to_string(background_color_type):
+        """
+        Return a string representation of a background color type.
+        """
+        if background_color_type == BackgroundColorType.Solid:
             return 'solid'
-        elif background_type == BackgroundType.Gradient:
+        elif background_color_type == BackgroundColorType.Gradient:
             return 'gradient'
-        elif background_type == BackgroundType.Image:
-            return 'image'
-        elif background_type == BackgroundType.Transparent:
+        elif background_color_type == BackgroundColorType.Transparent:
             return 'transparent'
 
     @staticmethod
     def from_string(type_string):
         """
-        Return a background type for the given string.
+        Return a background color type for the given string.
         """
         if type_string == 'solid':
-            return BackgroundType.Solid
+            return BackgroundColorType.Solid
         elif type_string == 'gradient':
-            return BackgroundType.Gradient
+            return BackgroundColorType.Gradient
+        elif type_string == 'transparent':
+            return BackgroundColorType.Transparent
+
+class BackgroundMediaType(object):
+    """
+    Media type enumeration for backgrounds.
+    """
+    Nothing = 0
+    Image = 1
+
+    @staticmethod
+    def to_string(media_type):
+        """
+        Return a string representation of a background media type.
+        """
+        if media_type == None or media_type == BackgroundMediaType.Nothing:
+            return 'none'
+        elif media_type == BackgroundMediaType.Image:
+            return 'image'
+
+    @staticmethod
+    def from_string(type_string):
+        """
+        Return a background media type for the given string.
+        """
+        if type_string == None or type_string == 'none':
+            return BackgroundMediaType.Nothing
         elif type_string == 'image':
-            return BackgroundType.Image
-        elif type_string == 'transparent':
-            return BackgroundType.Transparent
-
+            return BackgroundMediaType.Image
+
+class MediaScaleType(object):
+    """
+    Scale enumeration for media.
+    """
+    Auto = 0
+    Fullscreen = 1
+    Fixed = 2
+
+    @staticmethod
+    def to_string(image_scale):
+        """
+        Return a string representation of a media scale.
+        """
+        if image_scale == MediaScaleType.Auto:
+            return 'auto'
+        elif image_scale == MediaScaleType.Fullscreen:
+            return 'fullscreen'
+        elif image_scale == MediaScaleType.Fixed:
+            return 'fixed'
+
+    @staticmethod
+    def from_string(image_scale):
+        """
+        Return a media scale for the given string.
+        """
+        if image_scale == 'auto':
+            return MediaScaleType.Auto
+        elif image_scale == 'fullscreen':
+            return MediaScaleType.Fullscreen
+        elif image_scale == 'fixed':
+            return MediaScaleType.Fixed
+
+class MediaAlignType(object):
+    """
+    Alignment enumeration for media.
+    """
+    Top = 1
+    Middle = 0
+    Bottom = 2
+    Left = 4
+    Center = 0
+    Right = 8
+
+    @staticmethod
+    def to_string(media_align):
+        """
+        Return a string representation of a media alignment.
+        """
+        if media_align == None or media_align == 0:
+            return 'middle-center'
+        if media_align & MediaAlignType.Top:
+            align = 'top'
+        elif media_align & MediaAlignType.Bottom:
+            align = 'bottom'
+        else:
+            align = 'middle'
+        if media_align & MediaAlignType.Right:
+            align = align + '-right'
+        elif media_align & MediaAlignType.Left:
+            align = align + '-left'
+        else:
+            align = align + '-center'
+        return align
+
+    @staticmethod
+    def from_string(media_align):
+        """
+        Return a media alignment for the given string.
+        """
+        align = 0
+        media_align = str(media_align)
+        valign, halign = media_align.split("-")
+        if valign == 'top':
+            align = MediaAlignType.Top
+        elif valign == 'bottom':
+            align = MediaAlignType.Bottom
+        else:
+            align = MediaAlignType.Middle
+        if halign == 'left':
+            align = align | MediaAlignType.Left
+        elif halign == 'right':
+            align = align | MediaAlignType.Right
+        else:
+            align = align | MediaAlignType.Center
+        return align
 
 class BackgroundGradientType(object):
     """
@@ -147,10 +254,10 @@
     Names = ['top', 'middle', 'bottom']
 
 
-BOOLEAN_LIST = ['bold', 'italics', 'override', 'outline', 'shadow', 'slide_transition']
+BOOLEAN_LIST = ['bold', 'italics', 'outline', 'shadow', 'slide_transition']
 
-INTEGER_LIST = ['size', 'line_adjustment', 'x', 'height', 'y', 'width', 'shadow_size', 'outline_size',
-                'horizontal_align', 'vertical_align', 'wrap_style']
+INTEGER_LIST = ['size', 'line_adjustment', 'x', 'height', 'y', 'width', 'left', 'right', 'top', 'bottom',
+                'shadow_size', 'outline_size', 'horizontal_align', 'vertical_align', 'wrap_style', 'override']
 
 
 class ThemeXML(object):
@@ -191,11 +298,10 @@
 
         :param path: The path name to be added.
         """
-        if self.background_type == 'image':
-            if self.background_filename and path:
-                self.theme_name = self.theme_name.strip()
-                self.background_filename = self.background_filename.strip()
-                self.background_filename = os.path.join(path, self.theme_name, self.background_filename)
+        if self.background_media_filename and path:
+            self.theme_name = self.theme_name.strip()
+            self.background_media_filename  = self.background_media_filename.strip()
+            self.background_media_filename  = os.path.join(path, self.theme_name, self.background_media_filename )
 
     def _new_document(self, name):
         """
@@ -210,61 +316,45 @@
         self.name.appendChild(text_node)
         self.theme.appendChild(self.name)
 
-    def add_background_transparent(self):
-        """
-        Add a transparent background.
-        """
-        background = self.theme_xml.createElement('background')
-        background.setAttribute('type', 'transparent')
-        self.theme.appendChild(background)
-
-    def add_background_solid(self, bkcolor):
-        """
-        Add a Solid background.
-
-        :param bkcolor: The color of the background.
-        """
-        background = self.theme_xml.createElement('background')
-        background.setAttribute('type', 'solid')
-        self.theme.appendChild(background)
-        self.child_element(background, 'color', str(bkcolor))
-
-    def add_background_gradient(self, startcolor, endcolor, direction):
-        """
-        Add a gradient background.
-
-        :param startcolor: The gradient's starting colour.
-        :param endcolor: The gradient's ending colour.
-        :param direction: The direction of the gradient.
-        """
-        background = self.theme_xml.createElement('background')
-        background.setAttribute('type', 'gradient')
-        self.theme.appendChild(background)
-        # Create startColor element
-        self.child_element(background, 'startColor', str(startcolor))
-        # Create endColor element
-        self.child_element(background, 'endColor', str(endcolor))
-        # Create direction element
-        self.child_element(background, 'direction', str(direction))
-
-    def add_background_image(self, filename, border_color):
-        """
-        Add a image background.
-
-        :param filename: The file name of the image.
-        :param border_color:
-        """
-        background = self.theme_xml.createElement('background')
-        background.setAttribute('type', 'image')
-        self.theme.appendChild(background)
-        # Create Filename element
-        self.child_element(background, 'filename', filename)
-        # Create endColor element
-        self.child_element(background, 'borderColor', str(border_color))
+    def add_background(self, color_type, bkcolor, color_start, color_end, color_direction,
+                       media_type, media_align, media_scale, media_width, media_height, media_filename):
+        """
+        Add a background.
+        """
+        filename = ''
+        if media_type == None:
+            media_type = 'none'
+        if color_type == None:
+            color_type = 'transparent'
+        background = self.theme_xml.createElement('background')
+        color = self.theme_xml.createElement('color')
+        color.setAttribute('type', str(color_type))
+        #if color_type == BackgroundColorType.to_string(BackgroundColorType.Gradient):
+        color.setAttribute('start', str(color_start))
+        color.setAttribute('end', str(color_end))
+        color.setAttribute('direction', str(color_direction))
+        #if not color_type == BackgroundColorType.to_string(BackgroundColorType.Transparent):
+        color_node = self.theme_xml.createTextNode(str(bkcolor))
+        color.appendChild(color_node)
+        background.appendChild(color)
+        #if not media_type == BackgroundMediaType.to_string(BackgroundMediaType.Nothing):
+        if media_filename:
+            filename = os.path.split(media_filename)[1]
+        media = self.theme_xml.createElement('media')
+        media.setAttribute('type', str(media_type))
+        media.setAttribute('align', str(media_align))
+        media.setAttribute('scale', str(media_scale))
+        media.setAttribute('width', str(media_width))
+        media.setAttribute('height', str(media_height))
+        media.setAttribute('filename', str(filename))
+        media.setAttribute('borderColor', str(bkcolor))
+        background.appendChild(media)
+        self.theme.appendChild(background)
 
     def add_font(self, name, color, size, override, fonttype='main', bold='False', italics='False',
-                 line_adjustment=0, xpos=0, ypos=0, width=0, height=0, outline='False', outline_color='#ffffff',
-                 outline_pixel=2, shadow='False', shadow_color='#ffffff', shadow_pixel=5):
+                 line_adjustment=0, xpos=0, ypos=0, width=0, height=0, left=0, right=0, top=0, bottom=0,
+                 outline='False', outline_color='#ffffff', outline_pixel=2, shadow='False',
+                 shadow_color='#ffffff', shadow_pixel=5):
         """
         Add a Font.
 
@@ -287,6 +377,14 @@
         :param shadow_color: The colour of the shadow.
         :param shadow_pixel: How big the Shadow is
         """
+        if override >= 2:
+            margin_override = (override == 3)
+        else:
+            margin_override = 0
+        if override <= 1:
+            location_override = (override == 1)
+        else:
+            location_override = 0
         background = self.theme_xml.createElement('font')
         background.setAttribute('type', fonttype)
         self.theme.appendChild(background)
@@ -302,9 +400,20 @@
         self.child_element(background, 'italics', str(italics))
         # Create indentation name element
         self.child_element(background, 'line_adjustment', str(line_adjustment))
+        # Create Margin element
+        element = self.theme_xml.createElement('margin')
+        element.setAttribute('override', str(margin_override))
+        element.setAttribute('left', str(left))
+        element.setAttribute('right', str(right))
+        element.setAttribute('bottom', str(bottom))
+        if fonttype == 'footer':
+            element.setAttribute('height', str(height))
+        else:
+            element.setAttribute('top', str(top))
+        background.appendChild(element)
         # Create Location element
         element = self.theme_xml.createElement('location')
-        element.setAttribute('override', str(override))
+        element.setAttribute('override', str(location_override))
         element.setAttribute('x', str(xpos))
         element.setAttribute('y', str(ypos))
         element.setAttribute('width', str(width))
@@ -333,23 +442,23 @@
         :param vertical: The vertical alignment of the text.
         :param transition: Whether the slide transition is active.
         """
-        background = self.theme_xml.createElement('display')
-        self.theme.appendChild(background)
+        display = self.theme_xml.createElement('display')
+        self.theme.appendChild( display)
         # Horizontal alignment
         element = self.theme_xml.createElement('horizontalAlign')
         value = self.theme_xml.createTextNode(str(horizontal))
         element.appendChild(value)
-        background.appendChild(element)
+        display.appendChild(element)
         # Vertical alignment
         element = self.theme_xml.createElement('verticalAlign')
         value = self.theme_xml.createTextNode(str(vertical))
         element.appendChild(value)
-        background.appendChild(element)
+        display.appendChild(element)
         # Slide Transition
         element = self.theme_xml.createElement('slideTransition')
         value = self.theme_xml.createTextNode(str(transition))
         element.appendChild(value)
-        background.appendChild(element)
+        display.appendChild(element)
 
     def child_element(self, element, tag, value):
         """
@@ -439,8 +548,13 @@
                 if element.attrib:
                     for attr in element.attrib:
                         base_element = attr
-                        # correction for the shadow and outline tags
-                        if element.tag == 'shadow' or element.tag == 'outline':
+                        # correction for special tags -- shadow, outline, ect...
+                        special_tags = ['shadow', 'outline', 'color', 'media']
+                        override_tags = ['margin', 'location']
+                        if element.tag in special_tags:
+                            if not attr.startswith(element.tag):
+                                base_element = element.tag + '_' + attr
+                        elif attr == 'override' and element.tag in override_tags:
                             if not attr.startswith(element.tag):
                                 base_element = element.tag + '_' + attr
                         self._create_attr(master, base_element, element.attrib[attr])
@@ -469,6 +583,22 @@
                 value = True
         if element == 'proportion':
             element = 'size'
+        if element == 'location_override':
+            element = 'override'
+            if value == 'False':
+                value = '0'
+            elif value == 'True':
+                value = '1'
+            else:
+                return True, None, None, None
+        elif element == 'margin_override':
+            element = 'override'
+            if value == 'False':
+                value = '2'
+            elif value == 'True':
+                value = '3'
+            else:
+                return True, None, None, None
         return False, master, element, value
 
     def _create_attr(self, master, element, value):
@@ -508,19 +638,19 @@
         Build the XML from the varables in the object
         """
         self._new_document(self.theme_name)
-        if self.background_type == BackgroundType.to_string(BackgroundType.Solid):
-            self.add_background_solid(self.background_color)
-        elif self.background_type == BackgroundType.to_string(BackgroundType.Gradient):
-            self.add_background_gradient(
-                self.background_start_color,
-                self.background_end_color,
-                self.background_direction
-            )
-        elif self.background_type == BackgroundType.to_string(BackgroundType.Image):
-            filename = os.path.split(self.background_filename)[1]
-            self.add_background_image(filename, self.background_border_color)
-        elif self.background_type == BackgroundType.to_string(BackgroundType.Transparent):
-            self.add_background_transparent()
+        self.add_background(
+            self.background_color_type,
+            self.background_color,
+            self.background_color_start,
+            self.background_color_end,
+            self.background_color_direction,
+            self.background_media_type,
+            self.background_media_align,
+            self.background_media_scale,
+            self.background_media_width,
+            self.background_media_height,
+            self.background_media_filename
+        )
         self.add_font(
             self.font_main_name,
             self.font_main_color,
@@ -533,6 +663,10 @@
             self.font_main_y,
             self.font_main_width,
             self.font_main_height,
+            self.font_main_left,
+            self.font_main_right,
+            self.font_main_top,
+            self.font_main_bottom,
             self.font_main_outline,
             self.font_main_outline_color,
             self.font_main_outline_size,
@@ -547,11 +681,15 @@
             self.font_footer_override, 'footer',
             self.font_footer_bold,
             self.font_footer_italics,
-            0,  # line adjustment
+            self.font_footer_line_adjustment,
             self.font_footer_x,
             self.font_footer_y,
             self.font_footer_width,
             self.font_footer_height,
+            self.font_footer_left,
+            self.font_footer_right,
+            self.font_footer_top,
+            self.font_footer_bottom,
             self.font_footer_outline,
             self.font_footer_outline_color,
             self.font_footer_outline_size,

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2014-08-27 23:18:06 +0000
+++ openlp/core/ui/maindisplay.py	2014-10-24 02:22:21 +0000
@@ -45,7 +45,7 @@
 
 from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, Settings, translate, is_macosx
 from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte
-from openlp.core.lib.theme import BackgroundType
+from openlp.core.lib.theme import BackgroundColorType, BackgroundMediaType
 
 from openlp.core.lib import ScreenList
 from openlp.core.ui import HideMode, AlertLocation
@@ -168,7 +168,7 @@
             self.setStyleSheet("QGraphicsView {background: transparent; border: 0px;}")
         else:
             self.setAttribute(QtCore.Qt.WA_NoSystemBackground, False)
-            self.setStyleSheet("QGraphicsView {}")
+            self.setStyleSheet("QGraphicsView {border: 0px;}")
         self.setAttribute(QtCore.Qt.WA_TranslucentBackground, enabled)
         self.repaint()
 
@@ -280,7 +280,7 @@
         if not hasattr(self, 'service_item'):
             return False
         self.override['image'] = path
-        self.override['theme'] = self.service_item.theme_data.background_filename
+        self.override['theme'] = self.service_item.theme_data.background_media_filename
         self.image(path)
         # Update the preview frame.
         if self.is_live:
@@ -376,21 +376,31 @@
                 Registry().execute('video_background_replaced')
                 self.override = {}
             # We have a different theme.
-            elif self.override['theme'] != service_item.theme_data.background_filename:
+            elif self.override['theme'] != service_item.theme_data.background_media_filename :
                 Registry().execute('live_theme_changed')
                 self.override = {}
             else:
                 # replace the background
                 background = self.image_manager.get_image_bytes(self.override['image'], ImageSource.ImagePlugin)
-        self.set_transparency(self.service_item.theme_data.background_type ==
-                              BackgroundType.to_string(BackgroundType.Transparent))
-        if self.service_item.theme_data.background_filename:
-            self.service_item.bg_image_bytes = self.image_manager.get_image_bytes(
-                self.service_item.theme_data.background_filename, ImageSource.Theme)
-        if image_path:
-            image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
-        else:
-            image_bytes = None
+        self.set_transparency(self.service_item.theme_data.background_color_type ==
+                              BackgroundColorType.to_string(BackgroundColorType.Transparent))
+        image_bytes = None
+        media_image = BackgroundMediaType.to_string(BackgroundMediaType.Image)
+        if self.service_item.theme_data.background_media_type == media_image:
+            if self.service_item.theme_data.background_media_filename:
+                self.service_item.image_width = int(self.service_item.theme_data.background_media_width)
+                self.service_item.image_height = int(self.service_item.theme_data.background_media_height)
+                if self.service_item.theme_data.background_media_scale == 'auto':
+                    image = QtGui.QImage(self.service_item.theme_data.background_media_filename)
+                    self.service_item.image_width = int(image.width())
+                    self.service_item.image_height = int(image.height())
+                self.service_item.bg_image_bytes = self.image_manager.get_image_bytes(
+                    self.service_item.theme_data.background_media_filename,
+                    ImageSource.Theme,
+                    self.service_item.image_width,
+                    self.service_item.image_height)
+            if image_path:
+                image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
         html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes,
                           plugins=self.plugin_manager.plugins)
         self.web_view.setHtml(html)

=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py	2014-09-04 20:25:23 +0000
+++ openlp/core/ui/themeform.py	2014-10-24 02:22:21 +0000
@@ -35,10 +35,11 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.common import Registry, RegistryProperties, UiStrings, translate
-from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
+from openlp.core.lib.theme import BackgroundColorType, BackgroundGradientType, \
+    BackgroundMediaType, MediaScaleType, MediaAlignType
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui import ThemeLayoutForm
-from openlp.core.utils import get_images_filter, is_not_image_file
+from openlp.core.utils import get_images_filter, is_not_image_file, delete_file
 from .themewizard import Ui_ThemeWizard
 
 log = logging.getLogger(__name__)
@@ -61,25 +62,32 @@
         self.setupUi(self)
         self.registerFields()
         self.update_theme_allowed = True
-        self.temp_background_filename = ''
+        self.old_background_filename = ''
         self.theme_layout_form = ThemeLayoutForm(self)
-        self.background_combo_box.currentIndexChanged.connect(self.on_background_combo_box_current_index_changed)
+        self.color_type_combo_box.currentIndexChanged.connect(self.on_color_type_combo_box_current_index_changed)
+        self.media_type_combo_box.currentIndexChanged.connect(self.on_media_type_combo_box_current_index_changed)
+        self.image_scale_combo_box.currentIndexChanged.connect(self.on_image_scale_combo_box_current_index_changed)
+        self.image_valign_combo_box.currentIndexChanged.connect(self.on_alignment_combo_box_current_index_changed)
+        self.image_halign_combo_box.currentIndexChanged.connect(self.on_alignment_combo_box_current_index_changed)
         self.gradient_combo_box.currentIndexChanged.connect(self.on_gradient_combo_box_current_index_changed)
         self.color_button.clicked.connect(self.on_color_button_clicked)
-        self.image_color_button.clicked.connect(self.on_image_color_button_clicked)
         self.gradient_start_button.clicked.connect(self.on_gradient_start_button_clicked)
         self.gradient_end_button.clicked.connect(self.on_gradient_end_button_clicked)
         self.image_browse_button.clicked.connect(self.on_image_browse_button_clicked)
         self.image_file_edit.editingFinished.connect(self.on_image_file_edit_editing_finished)
+        self.image_width_spin_box.valueChanged.connect(self.update_theme)
+        self.image_height_spin_box.valueChanged.connect(self.update_theme)
         self.main_color_button.clicked.connect(self.on_main_color_button_clicked)
         self.outline_color_button.clicked.connect(self.on_outline_color_button_clicked)
         self.shadow_color_button.clicked.connect(self.on_shadow_color_button_clicked)
         self.outline_check_box.stateChanged.connect(self.on_outline_check_check_box_state_changed)
         self.shadow_check_box.stateChanged.connect(self.on_shadow_check_check_box_state_changed)
         self.footer_color_button.clicked.connect(self.on_footer_color_button_clicked)
-        self.customButtonClicked.connect(self.on_custom_1_button_clicked)
-        self.main_position_check_box.stateChanged.connect(self.on_main_position_check_box_state_changed)
-        self.footer_position_check_box.stateChanged.connect(self.on_footer_position_check_box_state_changed)
+        self.customButtonClicked.connect(self.on_custom_button_clicked)
+        self.main_position_combo_box.currentIndexChanged.connect(
+            self.on_main_position_combo_box_current_index_changed)
+        self.footer_position_combo_box.currentIndexChanged.connect(
+            self.on_footer_position_combo_box_current_index_changed)
         self.currentIdChanged.connect(self.on_current_id_changed)
         Registry().register_function('theme_line_count', self.update_lines_text)
         self.main_size_spin_box.valueChanged.connect(self.calculate_lines)
@@ -90,11 +98,19 @@
         self.footer_font_combo_box.activated.connect(self.update_theme)
         self.footer_size_spin_box.valueChanged.connect(self.update_theme)
 
+    def init_values(self):
+        """
+        Set up the inital values of variables
+        """
+        self.setField('image_width', self.theme.background_media_width)
+        self.setField('image_height', self.theme.background_media_height)
+
     def set_defaults(self):
         """
         Set up display at start of theme edit.
         """
         self.restart()
+        self.init_values()
         self.set_background_page_values()
         self.set_main_area_page_values()
         self.set_footer_area_page_values()
@@ -106,12 +122,18 @@
         """
         Map field names to screen names,
         """
-        self.background_page.registerField('background_type', self.background_combo_box)
+        self.background_page.registerField('color_type', self.color_type_combo_box)
+        self.background_page.registerField('media_type', self.media_type_combo_box)
         self.background_page.registerField('color', self.color_button)
         self.background_page.registerField('gradient_start', self.gradient_start_button)
         self.background_page.registerField('gradient_end', self.gradient_end_button)
         self.background_page.registerField('background_image', self.image_file_edit)
         self.background_page.registerField('gradient', self.gradient_combo_box)
+        self.background_page.registerField('image_valign', self.image_valign_combo_box)
+        self.background_page.registerField('image_halign', self.image_halign_combo_box)
+        self.background_page.registerField('image_scale', self.image_scale_combo_box)
+        self.background_page.registerField('image_width', self.image_width_spin_box)
+        self.background_page.registerField('image_height', self.image_height_spin_box)
         self.main_area_page.registerField('main_color_button', self.main_color_button)
         self.main_area_page.registerField('main_size_spin_box', self.main_size_spin_box)
         self.main_area_page.registerField('line_spacing_spin_box', self.line_spacing_spin_box)
@@ -124,13 +146,22 @@
         self.main_area_page.registerField('shadow_color_button', self.shadow_color_button)
         self.main_area_page.registerField('shadow_size_spin_box', self.shadow_size_spin_box)
         self.main_area_page.registerField('footer_size_spin_box', self.footer_size_spin_box)
+        self.area_position_page.registerField('main_position_override', self.main_position_combo_box)
         self.area_position_page.registerField('main_position_x', self.main_x_spin_box)
         self.area_position_page.registerField('main_position_y', self.main_y_spin_box)
         self.area_position_page.registerField('main_position_width', self.main_width_spin_box)
         self.area_position_page.registerField('main_position_height', self.main_height_spin_box)
+        self.area_position_page.registerField('main_position_left', self.main_left_spin_box)
+        self.area_position_page.registerField('main_position_right', self.main_right_spin_box)
+        self.area_position_page.registerField('main_position_top', self.main_top_spin_box)
+        self.area_position_page.registerField('main_position_bottom', self.main_bottom_spin_box)
+        self.area_position_page.registerField('footer_position_override', self.footer_position_combo_box)
         self.area_position_page.registerField('footer_position_x', self.footer_x_spin_box)
         self.area_position_page.registerField('footer_position_y', self.footer_y_spin_box)
         self.area_position_page.registerField('footer_position_width', self.footer_width_spin_box)
+        self.area_position_page.registerField('footer_position_left', self.footer_left_spin_box)
+        self.area_position_page.registerField('footer_position_right', self.footer_right_spin_box)
+        self.area_position_page.registerField('footer_position_bottom', self.footer_bottom_spin_box)
         self.area_position_page.registerField('footer_position_height', self.footer_height_spin_box)
         self.background_page.registerField('horizontal', self.horizontal_combo_box)
         self.background_page.registerField('vertical', self.vertical_combo_box)
@@ -175,9 +206,10 @@
         """
         Validate the current page
         """
-        background_image = BackgroundType.to_string(BackgroundType.Image)
+        background_image = BackgroundMediaType.to_string(BackgroundMediaType.Image)
         if self.page(self.currentId()) == self.background_page and \
-                self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename):
+                self.theme.background_media_type == background_image and \
+                is_not_image_file(self.theme.background_media_filename):
             QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),
                                        translate('OpenLP.ThemeWizard', 'You have not selected a '
                                                  'background image. Please select one before continuing.'))
@@ -189,8 +221,22 @@
         """
         Detects Page changes and updates as appropriate.
         """
-        enabled = self.page(page_id) == self.area_position_page
-        self.setOption(QtGui.QWizard.HaveCustomButton1, enabled)
+        is_first_page = page_id == 0
+        is_last_page = self.page(page_id) == self.preview_page
+        is_position_page = self.page(page_id) == self.area_position_page
+        if is_first_page:
+            button_layout = [QtGui.QWizard.Stretch, QtGui.QWizard.NextButton, QtGui.QWizard.CancelButton]
+        elif is_position_page:
+            button_layout = [QtGui.QWizard.CustomButton1, QtGui.QWizard.Stretch, QtGui.QWizard.CustomButton2, \
+                             QtGui.QWizard.BackButton, QtGui.QWizard.NextButton, QtGui.QWizard.CancelButton]
+        elif is_last_page:
+            button_layout = [QtGui.QWizard.Stretch, QtGui.QWizard.BackButton, \
+                             QtGui.QWizard.FinishButton, QtGui.QWizard.CancelButton]
+        else:
+            button_layout = [QtGui.QWizard.CustomButton1, QtGui.QWizard.Stretch, \
+                             QtGui.QWizard.BackButton, QtGui.QWizard.NextButton, \
+                             QtGui.QWizard.CancelButton]
+        self.setButtonLayout(button_layout)
         if self.page(page_id) == self.preview_page:
             self.update_theme()
             frame = self.theme_manager.generate_image(self.theme)
@@ -198,8 +244,25 @@
             self.display_aspect_ratio = float(frame.width()) / frame.height()
             self.resizeEvent()
 
+    def on_custom_button_clicked(self, number):
+        """
+        Determine which custom button was clicked
+        """
+        if number == QtGui.QWizard.CustomButton1.numerator:
+            self.on_custom_1_button_clicked(number)
+        elif number == QtGui.QWizard.CustomButton2.numerator:
+            self.on_custom_2_button_clicked(number)
+
     def on_custom_1_button_clicked(self, number):
         """
+        Save has been clicked
+        """
+        if self.validateCurrentPage():
+            self.update_theme()
+            self.accept()
+
+    def on_custom_2_button_clicked(self, number):
+        """
         Generate layout preview and display the form.
         """
         self.update_theme()
@@ -238,28 +301,47 @@
             self.shadow_size_spin_box.setEnabled(self.theme.font_main_shadow)
             self.calculate_lines()
 
-    def on_main_position_check_box_state_changed(self, value):
-        """
-        Change state as Main Area _position check box changed
-        NOTE the font_main_override is the inverse of the check box value
-        """
-        if self.update_theme_allowed:
-            self.theme.font_main_override = not (value == QtCore.Qt.Checked)
-
-    def on_footer_position_check_box_state_changed(self, value):
-        """
-        Change state as Footer Area _position check box changed
-        NOTE the font_footer_override is the inverse of the check box value
-        """
-        if self.update_theme_allowed:
-            self.theme.font_footer_override = not (value == QtCore.Qt.Checked)
+    def on_main_position_combo_box_current_index_changed(self, index):
+        """
+        Change state as Main Area _position combo box changed
+        NOTE the font_main_override equals 1 means use location override
+        and 2 means use margin override; whereas, 0 means to use defaults
+        """
+        if self.update_theme_allowed:
+            self.theme.font_main_override = int(index)
+            self.set_position_page_values()
+
+    def on_main_position_combo_box_current_index_changed(self, index):
+        """
+        Change state as Main Area _position combo box changed
+        NOTE the font_main_override
+            0 means to use location defaults
+            1 means to use location user-defined values
+            2 means to use margin defaults
+            3 means to use margin user-defined values
+        """
+        if self.update_theme_allowed:
+            self.theme.font_main_override = int(index)
+            self.set_position_page_values()
+
+    def on_footer_position_combo_box_current_index_changed(self, index):
+        """
+        Change state as Footer Area _position combo box changed
+        NOTE the font_footer_override
+            0 means to use location defaults
+            1 means to use location user-defined values
+            2 means to use margin defaults
+            3 means to use margin user-defined values
+        """
+        if self.update_theme_allowed:
+            self.theme.font_footer_override = int(index)
+            self.set_position_page_values()
 
     def exec_(self, edit=False):
         """
         Run the wizard.
         """
         log.debug('Editing theme %s' % self.theme.theme_name)
-        self.temp_background_filename = ''
         self.update_theme_allowed = False
         self.set_defaults()
         self.update_theme_allowed = True
@@ -294,29 +376,51 @@
         """
         Handle the display and state of the Background page.
         """
-        if self.theme.background_type == BackgroundType.to_string(BackgroundType.Solid):
+        if self.theme.background_color_type == BackgroundColorType.to_string(BackgroundColorType.Solid):
             self.color_button.setStyleSheet('background-color: %s' % self.theme.background_color)
-            self.setField('background_type', 0)
-        elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Gradient):
-            self.gradient_start_button.setStyleSheet('background-color: %s' % self.theme.background_start_color)
-            self.gradient_end_button.setStyleSheet('background-color: %s' % self.theme.background_end_color)
-            self.setField('background_type', 1)
-        elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
-            self.image_color_button.setStyleSheet('background-color: %s' % self.theme.background_border_color)
-            self.image_file_edit.setText(self.theme.background_filename)
-            self.setField('background_type', 2)
-        elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
-            self.setField('background_type', 3)
-        if self.theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
-            self.setField('gradient', 0)
-        elif self.theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
-            self.setField('gradient', 1)
-        elif self.theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Circular):
-            self.setField('gradient', 2)
-        elif self.theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
-            self.setField('gradient', 3)
+            self.setField('color_type', BackgroundColorType.Solid)
+        elif self.theme.background_color_type == BackgroundColorType.to_string(BackgroundColorType.Gradient):
+            self.gradient_start_button.setStyleSheet('background-color: %s' % self.theme.background_color_start)
+            self.gradient_end_button.setStyleSheet('background-color: %s' % self.theme.background_color_end)
+            self.setField('color_type', BackgroundColorType.Gradient)
+        elif self.theme.background_color_type == BackgroundColorType.to_string(BackgroundColorType.Transparent):
+            self.setField('color_type', BackgroundColorType.Transparent)
+        if self.theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
+            self.setField('gradient', BackgroundGradientType.Horizontal)
+        elif self.theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
+            self.setField('gradient', BackgroundGradientType.Vertical)
+        elif self.theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.Circular):
+            self.setField('gradient', BackgroundGradientType.Circular)
+        elif self.theme.background_color_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
+            self.setField('gradient', BackgroundGradientType.LeftTop)
         else:
-            self.setField('gradient', 4)
+            self.setField('gradient', BackgroundGradientType.LeftBottom)
+        if self.theme.background_media_type == BackgroundMediaType.to_string(BackgroundMediaType.Image):
+            if self.theme.background_media_filename:
+                self.image_file_edit.setText(os.path.split(str(self.theme.background_media_filename))[1])
+            self.setField('media_type', BackgroundMediaType.Image)
+            self.setField('image_scale', MediaScaleType.from_string(self.theme.background_media_scale))
+            fixed_enabled = self.theme.background_media_scale == \
+                            MediaScaleType.to_string(MediaScaleType.Fixed)
+            self.image_fixed_widget.setVisible(fixed_enabled)
+            fullscreen_enabled = self.theme.background_media_scale == \
+                                 MediaScaleType.to_string(MediaScaleType.Fullscreen)
+            self.image_align_label.setVisible(not fullscreen_enabled)
+            self.image_align_widget.setVisible(not fullscreen_enabled)
+            if not fullscreen_enabled:
+                media_align = MediaAlignType.from_string(self.theme.background_media_align)
+                if media_align & MediaAlignType.Top:
+                    self.setField('image_valign', 0)
+                elif media_align & MediaAlignType.Bottom:
+                    self.setField('image_valign', 2)
+                else:
+                    self.setField('image_valign', 1)
+                if media_align & MediaAlignType.Left:
+                    self.setField('image_halign', 0)
+                elif media_align & MediaAlignType.Right:
+                    self.setField('image_halign', 2)
+                else:
+                    self.setField('image_halign', 1)
 
     def set_main_area_page_values(self):
         """
@@ -348,17 +452,31 @@
         Handle the display and state of the _position page.
         """
         # Main Area
-        self.main_position_check_box.setChecked(not self.theme.font_main_override)
         self.setField('main_position_x', self.theme.font_main_x)
         self.setField('main_position_y', self.theme.font_main_y)
         self.setField('main_position_height', self.theme.font_main_height)
         self.setField('main_position_width', self.theme.font_main_width)
-        # Footer
-        self.footer_position_check_box.setChecked(not self.theme.font_footer_override)
+        self.setField('main_position_left', self.theme.font_main_left)
+        self.setField('main_position_right', self.theme.font_main_right)
+        self.setField('main_position_top', self.theme.font_main_top)
+        self.setField('main_position_bottom', self.theme.font_main_bottom)
+        self.setField('main_position_override', self.theme.font_main_override)
+        self.main_margin_widget.setEnabled(self.theme.font_main_override == 3)
+        self.main_location_widget.setEnabled(self.theme.font_main_override == 1)
+        self.main_position_stack.setCurrentIndex(int(self.theme.font_main_override > 1))
+        # Footer Area
         self.setField('footer_position_x', self.theme.font_footer_x)
         self.setField('footer_position_y', self.theme.font_footer_y)
         self.setField('footer_position_height', self.theme.font_footer_height)
         self.setField('footer_position_width', self.theme.font_footer_width)
+        self.setField('footer_position_left', self.theme.font_footer_left)
+        self.setField('footer_position_right', self.theme.font_footer_right)
+        self.setField('footer_position_bottom', self.theme.font_footer_bottom)
+        self.setField('footer_position_override', self.theme.font_footer_override)
+        self.footer_height_widget.setEnabled(self.theme.font_footer_override % 2)
+        self.footer_margin_widget.setEnabled(self.theme.font_footer_override == 3)
+        self.footer_location_widget.setEnabled(self.theme.font_footer_override == 1)
+        self.footer_position_stack.setCurrentIndex(int(self.theme.font_footer_override > 1))
 
     def set_alignment_page_values(self):
         """
@@ -374,21 +492,22 @@
         """
         self.setField('name', self.theme.theme_name)
 
-    def on_background_combo_box_current_index_changed(self, index):
-        """
-        Background style Combo box has changed.
-        """
-        # do not allow updates when screen is building for the first time.
-        if self.update_theme_allowed:
-            self.theme.background_type = BackgroundType.to_string(index)
-            if self.theme.background_type != BackgroundType.to_string(BackgroundType.Image) and \
-                    self.temp_background_filename == '':
-                self.temp_background_filename = self.theme.background_filename
-                self.theme.background_filename = ''
-            if self.theme.background_type == BackgroundType.to_string(BackgroundType.Image) and \
-                    self.temp_background_filename != '':
-                self.theme.background_filename = self.temp_background_filename
-                self.temp_background_filename = ''
+    def on_color_type_combo_box_current_index_changed(self, index):
+        """
+        Background color type Combo box has changed.
+        """
+        # do not allow updates when screen is building for the first time.
+        if self.update_theme_allowed:
+            self.theme.background_color_type = BackgroundColorType.to_string(index)
+            self.set_background_page_values()
+
+    def on_media_type_combo_box_current_index_changed(self, index):
+        """
+        Background media type Combo box has changed.
+        """
+        # do not allow updates when screen is building for the first time.
+        if self.update_theme_allowed:
+            self.theme.background_media_type = BackgroundMediaType.to_string(index)
             self.set_background_page_values()
 
     def on_gradient_combo_box_current_index_changed(self, index):
@@ -396,7 +515,37 @@
         Background gradient Combo box has changed.
         """
         if self.update_theme_allowed:
-            self.theme.background_direction = BackgroundGradientType.to_string(index)
+            self.theme.background_color_direction = BackgroundGradientType.to_string(index)
+            self.set_background_page_values()
+
+    def on_image_scale_combo_box_current_index_changed(self, index):
+        """
+        Background image scale Combo box has changed.
+        """
+        if self.update_theme_allowed:
+            self.theme.background_media_scale = MediaScaleType.to_string(index)
+            self.set_background_page_values()
+
+    def on_alignment_combo_box_current_index_changed(self, index):
+        """
+        Background image alignment Combo box has changed.
+        """
+        if self.update_theme_allowed:
+            valign = self.image_valign_combo_box.currentIndex()
+            halign = self.image_halign_combo_box.currentIndex()
+            if valign == 0:
+                valign = MediaAlignType.Top
+            elif valign == 1:
+                valign = MediaAlignType.Middle
+            elif valign == 2:
+                valign = MediaAlignType.Bottom
+            if halign == 0:
+                halign = MediaAlignType.Left
+            elif halign == 1:
+                halign = MediaAlignType.Center
+            elif halign == 2:
+                halign = MediaAlignType.Right
+            self.theme.background_media_align = MediaAlignType.to_string(valign | halign)
             self.set_background_page_values()
 
     def on_color_button_clicked(self):
@@ -406,25 +555,18 @@
         self.theme.background_color = self._color_button(self.theme.background_color)
         self.set_background_page_values()
 
-    def on_image_color_button_clicked(self):
-        """
-        Background / Gradient 1 _color button pushed.
-        """
-        self.theme.background_border_color = self._color_button(self.theme.background_border_color)
-        self.set_background_page_values()
-
     def on_gradient_start_button_clicked(self):
         """
         Gradient 2 _color button pushed.
         """
-        self.theme.background_start_color = self._color_button(self.theme.background_start_color)
+        self.theme.background_color_start = self._color_button(self.theme.background_color_start)
         self.set_background_page_values()
 
     def on_gradient_end_button_clicked(self):
         """
         Gradient 2 _color button pushed.
         """
-        self.theme.background_end_color = self._color_button(self.theme.background_end_color)
+        self.theme.background_color_end = self._color_button(self.theme.background_color_end)
         self.set_background_page_values()
 
     def on_image_browse_button_clicked(self):
@@ -436,14 +578,15 @@
         filename = QtGui.QFileDialog.getOpenFileName(self, translate('OpenLP.ThemeWizard', 'Select Image'), '',
                                                      images_filter)
         if filename:
-            self.theme.background_filename = str(filename)
+            self.theme.background_media_filename = str(filename)
         self.set_background_page_values()
 
     def on_image_file_edit_editing_finished(self):
         """
         Background image path edited
         """
-        self.theme.background_filename = str(self.image_file_edit.text())
+        if os.path.split(str(self.theme.background_media_filename))[1] != str(self.image_file_edit.text()):
+            self.theme.background_media_filename = str(self.image_file_edit.text())
 
     def on_main_color_button_clicked(self):
         """
@@ -481,6 +624,11 @@
         if not self.update_theme_allowed:
             return
         log.debug('update_theme')
+        # background page
+        if self.theme.background_media_type == BackgroundMediaType.to_string(BackgroundMediaType.Image):
+            if self.theme.background_media_scale == MediaScaleType.to_string(MediaScaleType.Fixed):
+                self.theme.background_media_width = int(self.field('image_width'))
+                self.theme.background_media_height = int(self.field('image_height'))
         # main page
         self.theme.font_main_name = self.main_font_combo_box.currentFont().family()
         self.theme.font_main_size = self.field('main_size_spin_box')
@@ -497,10 +645,17 @@
         self.theme.font_main_y = self.field('main_position_y')
         self.theme.font_main_height = self.field('main_position_height')
         self.theme.font_main_width = self.field('main_position_width')
+        self.theme.font_main_left = self.field('main_position_left')
+        self.theme.font_main_right = self.field('main_position_right')
+        self.theme.font_main_top = self.field('main_position_top')
+        self.theme.font_main_bottom = self.field('main_position_bottom')
         self.theme.font_footer_x = self.field('footer_position_x')
         self.theme.font_footer_y = self.field('footer_position_y')
+        self.theme.font_footer_width = self.field('footer_position_width')
+        self.theme.font_footer_left = self.field('footer_position_left')
+        self.theme.font_footer_right = self.field('footer_position_right')
+        self.theme.font_footer_bottom = self.field('footer_position_bottom')
         self.theme.font_footer_height = self.field('footer_position_height')
-        self.theme.font_footer_width = self.field('footer_position_width')
         # position page
         self.theme.display_horizontal_align = self.horizontal_combo_box.currentIndex()
         self.theme.display_vertical_align = self.vertical_combo_box.currentIndex()
@@ -524,10 +679,10 @@
             return
         save_from = None
         save_to = None
-        if self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
-            filename = os.path.split(str(self.theme.background_filename))[1]
+        if self.theme.background_media_type != BackgroundMediaType.to_string(BackgroundMediaType.Nothing):
+            filename = os.path.split(str(self.theme.background_media_filename ))[1]
             save_to = os.path.join(self.path, self.theme.theme_name, filename)
-            save_from = self.theme.background_filename
+            save_from = self.theme.background_media_filename
         if not self.edit_mode and not self.theme_manager.check_if_theme_exists(self.theme.theme_name):
             return
         self.theme_manager.save_theme(self.theme, save_from, save_to)

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2014-08-04 17:12:03 +0000
+++ openlp/core/ui/thememanager.py	2014-10-24 02:22:21 +0000
@@ -40,7 +40,7 @@
     check_directory_exists, UiStrings, translate
 from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, get_text_file_string, build_icon, \
     check_item_selected, create_thumb, validate_thumb
-from openlp.core.lib.theme import ThemeXML, BackgroundType
+from openlp.core.lib.theme import ThemeXML, BackgroundColorType, BackgroundMediaType
 from openlp.core.lib.ui import critical_error_message_box, create_widget_action
 from openlp.core.ui import FileRenameForm, ThemeForm
 from openlp.core.utils import delete_file, get_locale_key, get_filesystem_encoding
@@ -306,9 +306,9 @@
         """
         save_to = None
         save_from = None
-        if theme_data.background_type == 'image':
-            save_to = os.path.join(self.path, new_theme_name, os.path.split(str(theme_data.background_filename))[1])
-            save_from = theme_data.background_filename
+        if theme_data.background_media_type == 'image':
+            save_to = os.path.join(self.path, new_theme_name, os.path.split(str(theme_data.background_media_filename ))[1])
+            save_from = theme_data.background_media_filename
         theme_data.theme_name = new_theme_name
         theme_data.extend_image_filename(self.path)
         self.save_theme(theme_data, save_from, save_to)
@@ -324,11 +324,9 @@
                                translate('OpenLP.ThemeManager', 'You must select a theme to edit.')):
             item = self.theme_list_widget.currentItem()
             theme = self.get_theme_data(item.data(QtCore.Qt.UserRole))
-            if theme.background_type == 'image':
-                self.old_background_image = theme.background_filename
+            self.old_background_image = os.path.split(str(theme.background_media_filename))[1]
             self.theme_form.theme = theme
             self.theme_form.exec_(True)
-            self.old_background_image = None
             self.renderer.update_theme(theme.theme_name)
             self.load_themes()
 
@@ -630,10 +628,12 @@
         :param image_to: Where the Theme Image is to be saved to
         """
         self._write_theme(theme, image_from, image_to)
-        if theme.background_type == BackgroundType.to_string(BackgroundType.Image):
-            self.image_manager.update_image_border(theme.background_filename,
-                                                   ImageSource.Theme,
-                                                   QtGui.QColor(theme.background_border_color))
+        if theme.background_media_type == BackgroundMediaType.to_string(BackgroundMediaType.Image):
+            theme_background_color = QtCore.Qt.transparent
+            if theme.background_color_type == BackgroundColorType.to_string(BackgroundColorType.Solid):
+                theme_background_color = QtGui.QColor(theme.background_color)
+            self.image_manager.update_images_border(ImageSource.Theme,
+                                                    theme_background_color)
             self.image_manager.process_updates()
 
     def _write_theme(self, theme, image_from, image_to):
@@ -646,12 +646,14 @@
         """
         name = theme.theme_name
         theme_pretty_xml = theme.extract_formatted_xml()
+        filename = os.path.split(str(theme.background_media_filename))[1]
         theme_dir = os.path.join(self.path, name)
         check_directory_exists(theme_dir)
         theme_file = os.path.join(theme_dir, name + '.xml')
-        if self.old_background_image and image_to != self.old_background_image:
-            delete_file(self.old_background_image)
         out_file = None
+        if self.old_background_image:
+            if self.old_background_image != filename:
+                delete_file(os.path.join(self.path, name, self.old_background_image))
         try:
             out_file = open(theme_file, 'w')
             out_file.write(theme_pretty_xml.decode('UTF-8'))
@@ -722,7 +724,11 @@
         """
         theme = ThemeXML()
         theme.parse(theme_xml)
-        theme.extend_image_filename(image_path)
+        if theme.background_media_filename:
+            theme.extend_image_filename(image_path)
+        if not os.path.isfile(theme.background_media_filename):
+            theme.background_media_type = None
+            theme.background_media_filename = None
         return theme
 
     def _validate_theme_action(self, select_text, confirm_title, confirm_text, test_plugin=True, confirm=True):

=== modified file 'openlp/core/ui/themewizard.py'
--- openlp/core/ui/themewizard.py	2014-10-08 19:42:30 +0000
+++ openlp/core/ui/themewizard.py	2014-10-24 02:22:21 +0000
@@ -33,7 +33,8 @@
 
 from openlp.core.common import UiStrings, translate, is_macosx
 from openlp.core.lib import build_icon
-from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
+from openlp.core.lib.theme import HorizontalType, BackgroundColorType, BackgroundGradientType, \
+    BackgroundMediaType, MediaScaleType, MediaAlignType
 from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
 
 
@@ -47,12 +48,15 @@
         """
         theme_wizard.setObjectName('OpenLP.ThemeWizard')
         theme_wizard.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
+        theme_wizard.setMinimumSize(0, 420)
         theme_wizard.setModal(True)
         theme_wizard.setOptions(QtGui.QWizard.IndependentPages |
-                                QtGui.QWizard.NoBackButtonOnStartPage | QtGui.QWizard.HaveCustomButton1)
+                                QtGui.QWizard.NoBackButtonOnStartPage |
+                                QtGui.QWizard.HaveCustomButton1 |
+                                QtGui.QWizard.HaveCustomButton2 )
         if is_macosx():
             theme_wizard.setPixmap(QtGui.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
-            theme_wizard.resize(646, 400)
+            theme_wizard.resize(646, 420)
         else:
             theme_wizard.setWizardStyle(QtGui.QWizard.ModernStyle)
         self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
@@ -63,18 +67,18 @@
         self.background_page.setObjectName('background_page')
         self.background_layout = QtGui.QVBoxLayout(self.background_page)
         self.background_layout.setObjectName('background_layout')
-        self.background_type_layout = QtGui.QFormLayout()
-        self.background_type_layout.setObjectName('background_type_layout')
-        self.background_label = QtGui.QLabel(self.background_page)
-        self.background_label.setObjectName('background_label')
-        self.background_combo_box = QtGui.QComboBox(self.background_page)
-        self.background_combo_box.addItems(['', '', '', ''])
-        self.background_combo_box.setObjectName('background_combo_box')
-        self.background_type_layout.addRow(self.background_label, self.background_combo_box)
-        self.background_type_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
-        self.background_layout.addLayout(self.background_type_layout)
-        self.background_stack = QtGui.QStackedLayout()
-        self.background_stack.setObjectName('background_stack')
+        self.color_type_layout = QtGui.QFormLayout()
+        self.color_type_layout.setObjectName('color_type_layout')
+        self.color_type_label = QtGui.QLabel(self.background_page)
+        self.color_type_label.setObjectName('color_type_label')
+        self.color_type_combo_box = QtGui.QComboBox(self.background_page)
+        self.color_type_combo_box.addItems(['', '', ''])
+        self.color_type_combo_box.setObjectName('color_type_combo_box')
+        self.color_type_layout.addRow(self.color_type_label, self.color_type_combo_box)
+        self.color_type_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.background_layout.addLayout(self.color_type_layout)
+        self.color_stack = QtGui.QStackedLayout()
+        self.color_stack.setObjectName('color_stack')
         self.color_widget = QtGui.QWidget(self.background_page)
         self.color_widget.setObjectName('color_widget')
         self.color_layout = QtGui.QFormLayout(self.color_widget)
@@ -86,7 +90,7 @@
         self.color_button.setObjectName('color_button')
         self.color_layout.addRow(self.color_label, self.color_button)
         self.color_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
-        self.background_stack.addWidget(self.color_widget)
+        self.color_stack.addWidget(self.color_widget)
         self.gradient_widget = QtGui.QWidget(self.background_page)
         self.gradient_widget.setObjectName('Gradient_widget')
         self.gradient_layout = QtGui.QFormLayout(self.gradient_widget)
@@ -109,20 +113,87 @@
         self.gradient_combo_box.addItems(['', '', '', '', ''])
         self.gradient_layout.addRow(self.gradient_type_label, self.gradient_combo_box)
         self.gradient_layout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer)
-        self.background_stack.addWidget(self.gradient_widget)
+        self.color_stack.addWidget(self.gradient_widget)
+        self.transparent_widget = QtGui.QWidget(self.background_page)
+        self.transparent_widget.setObjectName('TransparentWidget')
+        self.transparent_layout = QtGui.QFormLayout(self.transparent_widget)
+        self.transparent_layout.setMargin(0)
+        self.transparent_layout.setObjectName('Transparent_layout')
+        self.color_stack.addWidget(self.transparent_widget)
+        self.background_layout.addLayout(self.color_stack)
+        self.media_type_layout = QtGui.QFormLayout()
+        self.media_type_layout.setObjectName('media_type_layout')
+        self.media_type_label = QtGui.QLabel(self.background_page)
+        self.media_type_label.setObjectName('media_type_label')
+        self.media_type_combo_box = QtGui.QComboBox(self.background_page)
+        self.media_type_combo_box.addItems(['', ''])
+        self.media_type_combo_box.setObjectName('media_type_combo_box')
+        self.media_type_layout.addRow(self.media_type_label, self.media_type_combo_box)
+        self.media_type_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.background_layout.addLayout(self.media_type_layout)
+        self.media_stack = QtGui.QStackedLayout()
+        self.media_stack.setObjectName('media_stack')
+        self.nothing_widget = QtGui.QWidget(self.background_page)
+        self.nothing_widget.setObjectName('nothing_widget')
+        self.media_stack.addWidget(self.nothing_widget)
         self.image_widget = QtGui.QWidget(self.background_page)
         self.image_widget.setObjectName('image_widget')
         self.image_layout = QtGui.QFormLayout(self.image_widget)
         self.image_layout.setMargin(0)
         self.image_layout.setObjectName('image_layout')
-        self.image_color_label = QtGui.QLabel(self.color_widget)
-        self.image_color_label.setObjectName('image_color_label')
-        self.image_color_button = QtGui.QPushButton(self.color_widget)
-        self.image_color_button.setObjectName('image_color_button')
-        self.image_layout.addRow(self.image_color_label, self.image_color_button)
-        self.image_label = QtGui.QLabel(self.image_widget)
-        self.image_label.setObjectName('image_label')
+        self.image_scale_label = QtGui.QLabel(self.image_widget)
+        self.image_scale_label.setObjectName('image_scale_label')
+        self.image_scale_layout = QtGui.QHBoxLayout()
+        self.image_scale_layout.setMargin(0)
+        self.image_scale_layout.setObjectName('image_scale_layout')
+        self.image_scale_combo_box = QtGui.QComboBox(self.image_widget)
+        self.image_scale_combo_box.addItems(['', '', ''])
+        self.image_scale_combo_box.setObjectName('image_scale_combo_box')
+        self.image_scale_layout.addWidget(self.image_scale_combo_box)
+        self.image_fixed_widget = QtGui.QWidget(self.background_page)
+        self.image_fixed_widget.setObjectName('image_fixed_widget')
+        self.image_fixed_layout = QtGui.QHBoxLayout(self.image_fixed_widget)
+        self.image_fixed_layout.setMargin(0)
+        self.image_fixed_layout.setObjectName('image_fixed_layout')
+        self.image_width_label = QtGui.QLabel(self.image_fixed_widget)
+        self.image_width_label.setObjectName('image_width_label')
+        self.image_fixed_layout.addWidget(self.image_width_label)
+        self.image_width_spin_box = QtGui.QSpinBox(self.image_widget)
+        self.image_width_spin_box.setMaximum(9999)
+        self.image_width_spin_box.setValue(0)
+        self.image_width_spin_box.setObjectName('image_width_spin_box')
+        self.image_fixed_layout.addWidget(self.image_width_spin_box)
+        self.image_height_label = QtGui.QLabel(self.image_widget)
+        self.image_height_label.setObjectName('image_height_label')
+        self.image_fixed_layout.addWidget(self.image_height_label)
+        self.image_height_spin_box = QtGui.QSpinBox(self.image_widget)
+        self.image_height_spin_box.setMaximum(9999)
+        self.image_height_spin_box.setValue(0)
+        self.image_height_spin_box.setObjectName('image_height_spin_box')
+        self.image_fixed_layout.addWidget(self.image_height_spin_box)
+        self.image_scale_layout.addWidget(self.image_fixed_widget)
+        self.image_layout.addRow(self.image_scale_label, self.image_scale_layout)
+        self.image_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.image_align_label = QtGui.QLabel(self.image_widget)
+        self.image_align_label.setObjectName('image_align_label')
+        self.image_align_widget = QtGui.QWidget(self.image_widget)
+        self.image_align_widget.setObjectName('image_align_widget')
+        self.image_align_layout = QtGui.QHBoxLayout(self.image_align_widget)
+        self.image_align_layout.setMargin(0)
+        self.image_align_layout.setObjectName('image_align_layout')
+        self.image_valign_combo_box = QtGui.QComboBox(self.image_align_widget)
+        self.image_valign_combo_box.addItems(['', '', ''])
+        self.image_valign_combo_box.setObjectName('image_valign_combo_box')
+        self.image_halign_combo_box = QtGui.QComboBox(self.image_align_widget)
+        self.image_halign_combo_box.addItems(['', '', ''])
+        self.image_halign_combo_box.setObjectName('image_halign_combo_box')
+        self.image_align_layout.addWidget(self.image_valign_combo_box)
+        self.image_align_layout.addWidget(self.image_halign_combo_box)
+        self.image_layout.addRow(self.image_align_label, self.image_align_widget)
+        self.image_file_label = QtGui.QLabel(self.image_widget)
+        self.image_file_label.setObjectName('image_file_label')
         self.image_file_layout = QtGui.QHBoxLayout()
+        self.image_file_layout.setMargin(0)
         self.image_file_layout.setObjectName('image_file_layout')
         self.image_file_edit = QtGui.QLineEdit(self.image_widget)
         self.image_file_edit.setObjectName('image_file_edit')
@@ -131,16 +202,9 @@
         self.image_browse_button.setObjectName('image_browse_button')
         self.image_browse_button.setIcon(build_icon(':/general/general_open.png'))
         self.image_file_layout.addWidget(self.image_browse_button)
-        self.image_layout.addRow(self.image_label, self.image_file_layout)
-        self.image_layout.setItem(2, QtGui.QFormLayout.LabelRole, self.spacer)
-        self.background_stack.addWidget(self.image_widget)
-        self.transparent_widget = QtGui.QWidget(self.background_page)
-        self.transparent_widget.setObjectName('TransparentWidget')
-        self.transparent_layout = QtGui.QFormLayout(self.transparent_widget)
-        self.transparent_layout.setMargin(0)
-        self.transparent_layout.setObjectName('Transparent_layout')
-        self.background_stack.addWidget(self.transparent_widget)
-        self.background_layout.addLayout(self.background_stack)
+        self.image_layout.addRow(self.image_file_label, self.image_file_layout)
+        self.media_stack.addWidget(self.image_widget)
+        self.background_layout.addLayout(self.media_stack)
         theme_wizard.addPage(self.background_page)
         # Main Area Page
         self.main_area_page = QtGui.QWizardPage()
@@ -274,69 +338,164 @@
         self.area_position_page.setObjectName('area_position_page')
         self.area_position_layout = QtGui.QHBoxLayout(self.area_position_page)
         self.area_position_layout.setObjectName('area_position_layout')
+        # main
         self.main_position_group_box = QtGui.QGroupBox(self.area_position_page)
         self.main_position_group_box.setObjectName('main_position_group_box')
         self.main_position_layout = QtGui.QFormLayout(self.main_position_group_box)
         self.main_position_layout.setObjectName('main_position_layout')
-        self.main_position_check_box = QtGui.QCheckBox(self.main_position_group_box)
-        self.main_position_check_box.setObjectName('main_position_check_box')
-        self.main_position_layout.addRow(self.main_position_check_box)
-        self.main_x_label = QtGui.QLabel(self.main_position_group_box)
+        self.main_position_combo_box = QtGui.QComboBox(self.main_position_group_box)
+        self.main_position_combo_box.addItems(['', '', '', ''])
+        self.main_position_combo_box.setObjectName('main_position_combo_box')
+        self.main_position_layout.addRow(self.main_position_combo_box)
+        self.main_position_stack = QtGui.QStackedLayout()
+        self.main_position_stack.setObjectName('main_position_stack')
+        # main location
+        self.main_location_widget = QtGui.QWidget(self.main_position_group_box)
+        self.main_location_widget.setObjectName('main_location_widget')
+        self.main_location_layout = QtGui.QFormLayout(self.main_location_widget)
+        self.main_location_layout.setObjectName('main_location_layout')
+        self.main_x_label = QtGui.QLabel()
         self.main_x_label.setObjectName('main_x_label')
-        self.main_x_spin_box = QtGui.QSpinBox(self.main_position_group_box)
+        self.main_x_spin_box = QtGui.QSpinBox(self.main_location_widget)
         self.main_x_spin_box.setMaximum(9999)
         self.main_x_spin_box.setObjectName('main_x_spin_box')
-        self.main_position_layout.addRow(self.main_x_label, self.main_x_spin_box)
-        self.main_y_label = QtGui.QLabel(self.main_position_group_box)
+        self.main_location_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.main_location_layout.addRow(self.main_x_label, self.main_x_spin_box)
+        self.main_y_label = QtGui.QLabel(self.main_location_widget)
         self.main_y_label.setObjectName('main_y_label')
-        self.main_y_spin_box = QtGui.QSpinBox(self.main_position_group_box)
+        self.main_y_spin_box = QtGui.QSpinBox(self.main_location_widget)
         self.main_y_spin_box.setMaximum(9999)
         self.main_y_spin_box.setObjectName('main_y_spin_box')
-        self.main_position_layout.addRow(self.main_y_label, self.main_y_spin_box)
-        self.main_width_label = QtGui.QLabel(self.main_position_group_box)
+        self.main_location_layout.addRow(self.main_y_label, self.main_y_spin_box)
+        self.main_width_label = QtGui.QLabel(self.main_location_widget)
         self.main_width_label.setObjectName('main_width_label')
-        self.main_width_spin_box = QtGui.QSpinBox(self.main_position_group_box)
+        self.main_width_spin_box = QtGui.QSpinBox(self.main_location_widget)
         self.main_width_spin_box.setMaximum(9999)
         self.main_width_spin_box.setObjectName('main_width_spin_box')
-        self.main_position_layout.addRow(self.main_width_label, self.main_width_spin_box)
-        self.main_height_label = QtGui.QLabel(self.main_position_group_box)
+        self.main_location_layout.addRow(self.main_width_label, self.main_width_spin_box)
+        self.main_height_label = QtGui.QLabel(self.main_location_widget)
         self.main_height_label.setObjectName('main_height_label')
-        self.main_height_spin_box = QtGui.QSpinBox(self.main_position_group_box)
+        self.main_height_spin_box = QtGui.QSpinBox(self.main_location_widget)
         self.main_height_spin_box.setMaximum(9999)
         self.main_height_spin_box.setObjectName('main_height_spin_box')
-        self.main_position_layout.addRow(self.main_height_label, self.main_height_spin_box)
+        self.main_location_layout.addRow(self.main_height_label, self.main_height_spin_box)
+        # main margin
+        self.main_margin_widget = QtGui.QWidget(self.main_position_group_box)
+        self.main_margin_widget.setObjectName('main_margin_widget')
+        self.main_margin_layout = QtGui.QFormLayout(self.main_margin_widget)
+        self.main_margin_layout.setObjectName('main_margin_layout')
+        self.main_left_label = QtGui.QLabel()
+        self.main_left_label.setObjectName('main_left_label')
+        self.main_left_spin_box = QtGui.QSpinBox(self.main_margin_widget)
+        self.main_left_spin_box.setMaximum(9999)
+        self.main_left_spin_box.setObjectName('main_left_spin_box')
+        self.main_margin_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.main_margin_layout.addRow(self.main_left_label, self.main_left_spin_box)
+        self.main_right_label = QtGui.QLabel(self.main_margin_widget)
+        self.main_right_label.setObjectName('main_right_label')
+        self.main_right_spin_box = QtGui.QSpinBox(self.main_margin_widget)
+        self.main_right_spin_box.setMaximum(9999)
+        self.main_right_spin_box.setObjectName('main_right_spin_box')
+        self.main_margin_layout.addRow(self.main_right_label, self.main_right_spin_box)
+        self.main_top_label = QtGui.QLabel(self.main_margin_widget)
+        self.main_top_label.setObjectName('main_top_label')
+        self.main_top_spin_box = QtGui.QSpinBox(self.main_margin_widget)
+        self.main_top_spin_box.setMaximum(9999)
+        self.main_top_spin_box.setObjectName('main_top_spin_box')
+        self.main_margin_layout.addRow(self.main_top_label, self.main_top_spin_box)
+        self.main_bottom_label = QtGui.QLabel(self.main_margin_widget)
+        self.main_bottom_label.setObjectName('main_bottom_label')
+        self.main_bottom_spin_box = QtGui.QSpinBox(self.main_margin_widget)
+        self.main_bottom_spin_box.setMaximum(9999)
+        self.main_bottom_spin_box.setObjectName('main_bottom_spin_box')
+        self.main_margin_layout.addRow(self.main_bottom_label, self.main_bottom_spin_box)
+        self.main_position_stack.addWidget(self.main_location_widget)
+        self.main_position_stack.addWidget(self.main_margin_widget)
+        self.main_position_layout.addRow(self.main_position_stack)
         self.area_position_layout.addWidget(self.main_position_group_box)
+        # footer
         self.footer_position_group_box = QtGui.QGroupBox(self.area_position_page)
         self.footer_position_group_box.setObjectName('footer_position_group_box')
         self.footer_position_layout = QtGui.QFormLayout(self.footer_position_group_box)
+        self.footer_position_layout.setVerticalSpacing(0)
+        self.footer_position_layout.setContentsMargins(0,4,0,0)
         self.footer_position_layout.setObjectName('footer_position_layout')
-        self.footer_position_check_box = QtGui.QCheckBox(self.footer_position_group_box)
-        self.footer_position_check_box.setObjectName('footer_position_check_box')
-        self.footer_position_layout.addRow(self.footer_position_check_box)
-        self.footer_x_label = QtGui.QLabel(self.footer_position_group_box)
+        self.footer_position_combo_box = QtGui.QComboBox(self.footer_position_group_box)
+        self.footer_position_combo_box.addItems(['', '', '', ''])
+        self.footer_position_combo_box.setObjectName('footer_position_combo_box')
+        self.footer_position_layout.addRow(self.footer_position_combo_box)
+        self.footer_position_stack = QtGui.QStackedLayout()
+        self.footer_position_stack.setObjectName('footer_position_stack')
+        # footer location
+        self.footer_location_widget = QtGui.QWidget(self.footer_position_group_box)
+        self.footer_location_widget.setObjectName('footer_location_widget')
+        self.footer_location_layout = QtGui.QFormLayout(self.footer_location_widget)
+        self.footer_location_layout.setVerticalSpacing(4)
+        self.footer_location_layout.setContentsMargins(4,8,0,4)
+        self.footer_location_layout.setObjectName('footer_location_layout')
+        self.footer_x_label = QtGui.QLabel(self.footer_location_widget)
         self.footer_x_label.setObjectName('footer_x_label')
-        self.footer_x_spin_box = QtGui.QSpinBox(self.footer_position_group_box)
+        self.footer_x_spin_box = QtGui.QSpinBox(self.footer_location_widget)
         self.footer_x_spin_box.setMaximum(9999)
         self.footer_x_spin_box.setObjectName('footer_x_spin_box')
-        self.footer_position_layout.addRow(self.footer_x_label, self.footer_x_spin_box)
-        self.footer_y_label = QtGui.QLabel(self.footer_position_group_box)
+        self.footer_location_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.footer_location_layout.addRow(self.footer_x_label, self.footer_x_spin_box)
+        self.footer_y_label = QtGui.QLabel(self.footer_location_widget)
         self.footer_y_label.setObjectName('footer_y_label')
-        self.footer_y_spin_box = QtGui.QSpinBox(self.footer_position_group_box)
+        self.footer_y_spin_box = QtGui.QSpinBox(self.footer_location_widget)
         self.footer_y_spin_box.setMaximum(9999)
         self.footer_y_spin_box.setObjectName('footer_y_spin_box')
-        self.footer_position_layout.addRow(self.footer_y_label, self.footer_y_spin_box)
-        self.footer_width_label = QtGui.QLabel(self.footer_position_group_box)
+        self.footer_location_layout.addRow(self.footer_y_label, self.footer_y_spin_box)
+        self.footer_width_label = QtGui.QLabel(self.footer_location_widget)
         self.footer_width_label.setObjectName('footer_width_label')
-        self.footer_width_spin_box = QtGui.QSpinBox(self.footer_position_group_box)
+        self.footer_width_spin_box = QtGui.QSpinBox(self.footer_location_widget)
         self.footer_width_spin_box.setMaximum(9999)
         self.footer_width_spin_box.setObjectName('footer_width_spin_box')
-        self.footer_position_layout.addRow(self.footer_width_label, self.footer_width_spin_box)
-        self.footer_height_label = QtGui.QLabel(self.footer_position_group_box)
+        self.footer_location_layout.addRow(self.footer_width_label, self.footer_width_spin_box)
+        self.footer_position_stack.addWidget(self.footer_location_widget)
+        # footer margin
+        self.footer_margin_widget = QtGui.QWidget(self.footer_position_group_box)
+        self.footer_margin_widget.setObjectName('footer_margin_widget')
+        self.footer_margin_layout = QtGui.QFormLayout(self.footer_margin_widget)
+        self.footer_margin_layout.setVerticalSpacing(4)
+        self.footer_margin_layout.setContentsMargins(4,8,0,4)
+        self.footer_margin_layout.setObjectName('footer_margin_layout')
+        self.footer_left_label = QtGui.QLabel(self.footer_margin_widget)
+        self.footer_left_label.setObjectName('footer_left_label')
+        self.footer_left_spin_box = QtGui.QSpinBox(self.footer_margin_widget)
+        self.footer_left_spin_box.setMaximum(9999)
+        self.footer_left_spin_box.setObjectName('footer_left_spin_box')
+        self.footer_margin_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.footer_margin_layout.addRow(self.footer_left_label, self.footer_left_spin_box)
+        self.footer_right_label = QtGui.QLabel(self.footer_margin_widget)
+        self.footer_right_label.setObjectName('footer_right_label')
+        self.footer_right_spin_box = QtGui.QSpinBox(self.footer_margin_widget)
+        self.footer_right_spin_box.setMaximum(9999)
+        self.footer_right_spin_box.setObjectName('footer_right_spin_box')
+        self.footer_margin_layout.addRow(self.footer_right_label, self.footer_right_spin_box)
+        self.footer_bottom_label = QtGui.QLabel(self.footer_margin_widget)
+        self.footer_bottom_label.setObjectName('footer_bottom_label')
+        self.footer_bottom_spin_box = QtGui.QSpinBox(self.footer_margin_widget)
+        self.footer_bottom_spin_box.setMaximum(9999)
+        self.footer_bottom_spin_box.setObjectName('footer_bottom_spin_box')
+        self.footer_margin_layout.addRow(self.footer_bottom_label, self.footer_bottom_spin_box)
+        self.footer_position_stack.addWidget(self.footer_margin_widget)
+        self.footer_position_layout.addRow(self.footer_position_stack)
+        # footer height
+        self.footer_height_widget = QtGui.QWidget(self.footer_position_group_box)
+        self.footer_height_widget.setObjectName('footer_height_widget')
+        self.footer_height_layout = QtGui.QFormLayout(self.footer_height_widget)
+        self.footer_height_layout.setVerticalSpacing(0)
+        self.footer_height_layout.setContentsMargins(0,0,0,0)
+        self.footer_height_layout.setObjectName('footer_height_layout')
+        self.footer_height_label = QtGui.QLabel(self.footer_height_widget)
         self.footer_height_label.setObjectName('footer_height_label')
-        self.footer_height_spin_box = QtGui.QSpinBox(self.footer_position_group_box)
+        self.footer_height_spin_box = QtGui.QSpinBox(self.footer_height_widget)
         self.footer_height_spin_box.setMaximum(9999)
         self.footer_height_spin_box.setObjectName('footer_height_spin_box')
-        self.footer_position_layout.addRow(self.footer_height_label, self.footer_height_spin_box)
+        self.footer_height_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
+        self.footer_height_layout.addRow(self.footer_height_label, self.footer_height_spin_box)
+        self.footer_position_layout.addWidget(self.footer_height_widget)
         self.area_position_layout.addWidget(self.footer_position_group_box)
         theme_wizard.addPage(self.area_position_page)
         # Preview Page
@@ -368,8 +527,10 @@
         self.preview_layout.addWidget(self.preview_area)
         theme_wizard.addPage(self.preview_page)
         self.retranslateUi(theme_wizard)
-        QtCore.QObject.connect(self.background_combo_box, QtCore.SIGNAL('currentIndexChanged(int)'),
-                               self.background_stack, QtCore.SLOT('setCurrentIndex(int)'))
+        QtCore.QObject.connect(self.color_type_combo_box, QtCore.SIGNAL('currentIndexChanged(int)'),
+                               self.color_stack, QtCore.SLOT('setCurrentIndex(int)'))
+        QtCore.QObject.connect(self.media_type_combo_box, QtCore.SIGNAL('currentIndexChanged(int)'),
+                               self.media_stack, QtCore.SLOT('setCurrentIndex(int)'))
         QtCore.QObject.connect(self.outline_check_box, QtCore.SIGNAL('toggled(bool)'), self.outline_color_button,
                                QtCore.SLOT('setEnabled(bool)'))
         QtCore.QObject.connect(self.outline_check_box, QtCore.SIGNAL('toggled(bool)'), self.outline_size_spin_box,
@@ -378,23 +539,6 @@
                                QtCore.SLOT('setEnabled(bool)'))
         QtCore.QObject.connect(self.shadow_check_box, QtCore.SIGNAL('toggled(bool)'), self.shadow_size_spin_box,
                                QtCore.SLOT('setEnabled(bool)'))
-        QtCore.QObject.connect(self.main_position_check_box, QtCore.SIGNAL('toggled(bool)'), self.main_x_spin_box,
-                               QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.main_position_check_box, QtCore.SIGNAL('toggled(bool)'), self.main_y_spin_box,
-                               QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.main_position_check_box, QtCore.SIGNAL('toggled(bool)'), self.main_width_spin_box,
-                               QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.main_position_check_box, QtCore.SIGNAL('toggled(bool)'), self.main_height_spin_box,
-                               QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.footer_position_check_box, QtCore.SIGNAL('toggled(bool)'), self.footer_x_spin_box,
-                               QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.footer_position_check_box, QtCore.SIGNAL('toggled(bool)'), self.footer_y_spin_box,
-                               QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.footer_position_check_box, QtCore.SIGNAL('toggled(bool)'),
-                               self.footer_width_spin_box, QtCore.SLOT('setDisabled(bool)'))
-        QtCore.QObject.connect(self.footer_position_check_box, QtCore.SIGNAL('toggled(bool)'),
-                               self.footer_height_spin_box, QtCore.SLOT('setDisabled(bool)'))
-
     def retranslateUi(self, theme_wizard):
         """
         Translate the UI on the fly
@@ -408,13 +552,12 @@
         self.background_page.setTitle(translate('OpenLP.ThemeWizard', 'Set Up Background'))
         self.background_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Set up your theme\'s background '
                                          'according to the parameters below.'))
-        self.background_label.setText(translate('OpenLP.ThemeWizard', 'Background type:'))
-        self.background_combo_box.setItemText(BackgroundType.Solid,
+        self.color_type_label.setText(translate('OpenLP.ThemeWizard', 'Color type:'))
+        self.color_type_combo_box.setItemText(BackgroundColorType.Solid,
                                               translate('OpenLP.ThemeWizard', 'Solid color'))
-        self.background_combo_box.setItemText(BackgroundType.Gradient,
+        self.color_type_combo_box.setItemText(BackgroundColorType.Gradient,
                                               translate('OpenLP.ThemeWizard', 'Gradient'))
-        self.background_combo_box.setItemText(BackgroundType.Image, UiStrings().Image)
-        self.background_combo_box.setItemText(BackgroundType.Transparent,
+        self.color_type_combo_box.setItemText(BackgroundColorType.Transparent,
                                               translate('OpenLP.ThemeWizard', 'Transparent'))
         self.color_label.setText(translate('OpenLP.ThemeWizard', 'color:'))
         self.gradient_start_label.setText(translate('OpenLP.ThemeWizard', 'Starting color:'))
@@ -430,8 +573,28 @@
                                             translate('OpenLP.ThemeWizard', 'Top Left - Bottom Right'))
         self.gradient_combo_box.setItemText(BackgroundGradientType.LeftBottom,
                                             translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right'))
-        self.image_color_label.setText(translate('OpenLP.ThemeWizard', 'Background color:'))
-        self.image_label.setText('%s:' % UiStrings().Image)
+        self.media_type_label.setText(translate('OpenLP.ThemeWizard', 'Media type:'))
+        self.media_type_combo_box.setItemText(BackgroundMediaType.Nothing,
+                                              translate('OpenLP.ThemeWizard', 'None'))
+        self.media_type_combo_box.setItemText(BackgroundMediaType.Image,
+                                              UiStrings().Image)
+        self.image_align_label.setText(translate('OpenLP.ThemeWizard', 'Alignment:'))
+        self.image_valign_combo_box.setItemText(0, translate('OpenLP.ThemeWizard', 'Top'))
+        self.image_valign_combo_box.setItemText(1, translate('OpenLP.ThemeWizard', 'Middle'))
+        self.image_valign_combo_box.setItemText(2, translate('OpenLP.ThemeWizard', 'Bottom'))
+        self.image_halign_combo_box.setItemText(0, translate('OpenLP.ThemeWizard', 'Left'))
+        self.image_halign_combo_box.setItemText(1, translate('OpenLP.ThemeWizard', 'Center'))
+        self.image_halign_combo_box.setItemText(2, translate('OpenLP.ThemeWizard', 'Right'))
+        self.image_scale_label.setText(translate('OpenLP.ThemeWizard', 'Size:'))
+        self.image_scale_combo_box.setItemText(MediaScaleType.Auto,
+                                              translate('OpenLP.ThemeWizard', 'Auto'))
+        self.image_scale_combo_box.setItemText(MediaScaleType.Fullscreen,
+                                              translate('OpenLP.ThemeWizard', 'Fullscreen'))
+        self.image_scale_combo_box.setItemText(MediaScaleType.Fixed,
+                                              translate('OpenLP.ThemeWizard', 'Fixed'))
+        self.image_width_label.setText(translate('OpenLP.ThemeWizard', 'width:'))
+        self.image_height_label.setText(translate('OpenLP.ThemeWizard', 'height:'))
+        self.image_file_label.setText(translate('OpenLP.ThemeWizard', 'Filename:'))
         self.main_area_page.setTitle(translate('OpenLP.ThemeWizard', 'Main Area Font Details'))
         self.main_area_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Define the font and display '
                                                   'characteristics for the Display text'))
@@ -469,7 +632,14 @@
         self.area_position_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Allows you to change and move the'
                                                       ' Main and Footer areas.'))
         self.main_position_group_box.setTitle(translate('OpenLP.ThemeWizard', '&Main Area'))
-        self.main_position_check_box.setText(translate('OpenLP.ThemeWizard', '&Use default location'))
+        self.main_position_combo_box.setItemText(0,
+                                      translate('OpenLP.ThemeWizard', 'Use default location'))
+        self.main_position_combo_box.setItemText(1,
+                                      translate('OpenLP.ThemeWizard', 'Specify custom location'))
+        self.main_position_combo_box.setItemText(2,
+                                      translate('OpenLP.ThemeWizard', 'Use default margins'))
+        self.main_position_combo_box.setItemText(3,
+                                      translate('OpenLP.ThemeWizard', 'Specify custom margins'))
         self.main_x_label.setText(translate('OpenLP.ThemeWizard', 'X position:'))
         self.main_x_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
         self.main_y_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
@@ -478,7 +648,23 @@
         self.main_width_label.setText(translate('OpenLP.ThemeWizard', 'Width:'))
         self.main_height_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
         self.main_height_label.setText(translate('OpenLP.ThemeWizard', 'Height:'))
+        self.main_left_label.setText(translate('OpenLP.ThemeWizard', 'Left:'))
+        self.main_left_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
+        self.main_right_label.setText(translate('OpenLP.ThemeWizard', 'Right:'))
+        self.main_right_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
+        self.main_top_label.setText(translate('OpenLP.ThemeWizard', 'Top:'))
+        self.main_top_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
+        self.main_bottom_label.setText(translate('OpenLP.ThemeWizard', 'Bottom:'))
+        self.main_bottom_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
         self.footer_position_group_box.setTitle(translate('OpenLP.ThemeWizard', '&Footer Area'))
+        self.footer_position_combo_box.setItemText(0,
+                                      translate('OpenLP.ThemeWizard', 'Use default location'))
+        self.footer_position_combo_box.setItemText(1,
+                                      translate('OpenLP.ThemeWizard', 'Specify custom location'))
+        self.footer_position_combo_box.setItemText(2,
+                                      translate('OpenLP.ThemeWizard', 'Use default margins'))
+        self.footer_position_combo_box.setItemText(3,
+                                      translate('OpenLP.ThemeWizard', 'Specify custom margins'))
         self.footer_x_label.setText(translate('OpenLP.ThemeWizard', 'X position:'))
         self.footer_x_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
         self.footer_y_label.setText(translate('OpenLP.ThemeWizard', 'Y position:'))
@@ -487,13 +673,21 @@
         self.footer_width_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
         self.footer_height_label.setText(translate('OpenLP.ThemeWizard', 'Height:'))
         self.footer_height_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
-        self.footer_position_check_box.setText(translate('OpenLP.ThemeWizard', 'Use default location'))
-        theme_wizard.setOption(QtGui.QWizard.HaveCustomButton1, False)
-        theme_wizard.setButtonText(QtGui.QWizard.CustomButton1, translate('OpenLP.ThemeWizard', 'Layout Preview'))
+        self.footer_left_label.setText(translate('OpenLP.ThemeWizard', 'Left:'))
+        self.footer_left_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
+        self.footer_right_label.setText(translate('OpenLP.ThemeWizard', 'Right:'))
+        self.footer_right_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
+        self.footer_bottom_label.setText(translate('OpenLP.ThemeWizard', 'Bottom:'))
+        self.footer_bottom_spin_box.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
+        theme_wizard.setButtonText(QtGui.QWizard.CustomButton1, translate('OpenLP.ThemeWizard', 'Save'))
+        theme_wizard.setButtonText(QtGui.QWizard.CustomButton2, translate('OpenLP.ThemeWizard', 'Layout Preview'))
+        button_layout = [QtGui.QWizard.CustomButton1, QtGui.QWizard.Stretch, \
+                         QtGui.QWizard.BackButton, QtGui.QWizard.NextButton, QtGui.QWizard.CancelButton]
+        theme_wizard.setButtonLayout(button_layout)
         self.preview_page.setTitle(translate('OpenLP.ThemeWizard', 'Preview and Save'))
         self.preview_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Preview the theme and save it.'))
         self.theme_name_label.setText(translate('OpenLP.ThemeWizard', 'Theme name:'))
         # Align all QFormLayouts towards each other.
-        label_width = max(self.background_label.minimumSizeHint().width(),
+        label_width = max(self.color_type_label.minimumSizeHint().width(),
                           self.horizontal_label.minimumSizeHint().width())
         self.spacer.changeSize(label_width, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2014-10-22 20:47:47 +0000
+++ openlp/core/utils/__init__.py	2014-10-24 02:22:21 +0000
@@ -304,6 +304,7 @@
 
     :param file_name: File name to be checked.
     """
+    #QtGui.QMessageBox.warning(None,"Image File", "filename: %s | e: %d" % (file_name, os.path.exists(file_name)) )
     if not file_name:
         return True
     else:

=== modified file 'tests/functional/openlp_core_lib/test_htmlbuilder.py'
--- tests/functional/openlp_core_lib/test_htmlbuilder.py	2014-07-24 21:57:16 +0000
+++ tests/functional/openlp_core_lib/test_htmlbuilder.py	2014-10-24 02:22:21 +0000
@@ -251,8 +251,8 @@
         """
         # GIVEN: Mocked arguments.
         item = MagicMock()
-        item.theme_data.background_start_color = '#000000'
-        item.theme_data.background_end_color = '#FFFFFF'
+        item.theme_data.background_color_start = '#000000'
+        item.theme_data.background_color_end = '#FFFFFF'
         width = 10
 
         # WHEN: Create the css.

=== modified file 'tests/functional/openlp_core_lib/test_theme.py'
--- tests/functional/openlp_core_lib/test_theme.py	2014-09-07 22:17:20 +0000
+++ tests/functional/openlp_core_lib/test_theme.py	2014-10-24 02:22:21 +0000
@@ -61,8 +61,8 @@
         default_theme = ThemeXML()
 
         # THEN: We should get some default behaviours
-        self.assertTrue(default_theme.background_border_color == '#000000', 'The theme should have a black border')
-        self.assertTrue(default_theme.background_type == 'solid', 'The theme should have a solid backgrounds')
+        self.assertTrue(default_theme.background_color == '#000000', 'The theme should have a black border')
+        self.assertTrue(default_theme.background_color_type == 'solid', 'The theme should have a solid backgrounds')
         self.assertTrue(default_theme.display_vertical_align == 0,
                         'The theme should have a display_vertical_align of 0')
         self.assertTrue(default_theme.font_footer_name == "Arial",


References