openlp/openlp/core/lib/rendermanager.py

300 lines
13 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2009-12-31 12:52:01 +00:00
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
2010-07-24 22:10:47 +00:00
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
2010-01-24 23:16:15 +00:00
from PyQt4 import QtCore
2010-07-23 05:05:34 +00:00
from openlp.core.lib import Renderer, ThemeLevel, ServiceItem
from openlp.core.ui import MainDisplay
2010-04-03 07:10:31 +00:00
2010-02-27 15:31:23 +00:00
log = logging.getLogger(__name__)
2009-07-10 13:16:15 +00:00
class RenderManager(object):
"""
2009-07-10 13:16:15 +00:00
Class to pull all Renderer interactions into one place. The plugins will
call helper methods to do the rendering but this class will provide
display defense code.
2009-09-04 22:50:19 +00:00
``theme_manager``
The ThemeManager instance, used to get the current theme details.
``screens``
Contains information about the Screens.
2009-09-04 22:50:19 +00:00
``screen_number``
Defaults to *0*. The index of the output/display screen.
"""
log.info(u'RenderManager Loaded')
2010-04-02 18:12:54 +00:00
def __init__(self, theme_manager, screens):
2009-07-10 13:16:15 +00:00
"""
Initialise the render manager.
"""
log.debug(u'Initilisation started')
self.screens = screens
2010-07-26 15:51:18 +00:00
self.display = MainDisplay(self, screens, False)
2010-07-23 05:05:34 +00:00
self.display.setup()
self.theme_manager = theme_manager
self.renderer = Renderer()
self.calculate_default(self.screens.current[u'size'])
self.theme = u''
2009-05-20 20:17:20 +00:00
self.service_theme = u''
self.theme_level = u''
self.override_background = None
2009-10-24 07:22:44 +00:00
self.themedata = None
2010-08-05 19:01:24 +00:00
self.alertTab = None
# TODO make external and configurable in alpha 4
self.html_expands = []
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \
u'start html':u'<font color=red>', \
u'end tag':u'{/r}', u'end html':u'</font>', \
u'protected':False})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \
u'start html':u'<font color=black>', \
u'end tag':u'{/b}', u'end html':u'</font>', \
u'protected':False})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \
u'start html':u'<font color=blue>', \
u'end tag':u'{/bl}', u'end html':u'</font>', \
u'protected':False})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \
u'start html':u'<font color=yellow>', \
u'end tag':u'{/y}', u'end html':u'</font>', \
u'protected':False})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \
u'start html':u'<font color=green>', \
u'end tag':u'{/g}', u'end html':u'</font>', \
u'protected':False})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \
u'start html':u'<sup>', \
u'end tag':u'{/su}', u'end html':u'</sup>', \
u'protected':True})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', \
u'start html':u'<sub>', \
u'end tag':u'{/sb}', u'end html':u'</sub>', \
u'protected':True})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', \
u'start html':u'<p>', \
u'end tag':u'{/p}', u'end html':u'</p>', \
u'protected':True})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', \
u'start html':u'<strong>', \
2010-08-21 08:24:14 +00:00
u'end tag':u'{/st}', \
u'end html':u'</strong>', \
u'protected':True})
2010-08-21 08:24:14 +00:00
self.html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', \
u'start html':u'<em>', \
u'end tag':u'{/it}', u'end html':u'</em>', \
u'protected':True})
2010-07-29 17:08:01 +00:00
2010-04-02 18:12:54 +00:00
def update_display(self):
"""
Updates the render manager's information about the current screen.
"""
2009-06-10 15:54:46 +00:00
log.debug(u'Update Display')
self.calculate_default(self.screens.current[u'size'])
2010-08-05 20:26:39 +00:00
self.display = MainDisplay(self, self.screens, False)
self.display.setup()
self.renderer.bg_frame = None
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
2009-07-10 13:16:15 +00:00
"""
Set the global-level theme and the theme level.
``global_theme``
The global-level theme to be set.
``theme_level``
Defaults to *``ThemeLevel.Global``*. The theme level, can be
``ThemeLevel.Global``, ``ThemeLevel.Service`` or
``ThemeLevel.Song``.
2009-07-10 13:16:15 +00:00
"""
self.global_theme = global_theme
self.theme_level = theme_level
def set_service_theme(self, service_theme):
2009-07-10 13:16:15 +00:00
"""
Set the service-level theme.
``service_theme``
The service-level theme to be set.
"""
self.service_theme = service_theme
2010-08-07 08:50:58 +00:00
def set_override_theme(self, theme, overrideLevels=False):
2009-07-10 13:16:15 +00:00
"""
Set the appropriate theme depending on the theme level.
2010-07-12 16:49:38 +00:00
Called by the service item when building a display frame
2009-07-10 13:16:15 +00:00
``theme``
2010-07-12 16:49:38 +00:00
The name of the song-level theme. None means the service
item wants to use the given value.
2009-07-10 13:16:15 +00:00
"""
log.debug(u'set override theme to %s', theme)
2010-08-07 08:50:58 +00:00
theme_level = self.theme_level
if overrideLevels:
theme_level = ThemeLevel.Song
if theme_level == ThemeLevel.Global:
self.theme = self.global_theme
2010-08-07 08:50:58 +00:00
elif theme_level == ThemeLevel.Service:
if self.service_theme == u'':
self.theme = self.global_theme
else:
self.theme = self.service_theme
else:
2009-11-03 18:14:25 +00:00
if theme:
self.theme = theme
2010-08-07 08:50:58 +00:00
elif theme_level == ThemeLevel.Song or \
theme_level == ThemeLevel.Service:
if self.service_theme == u'':
self.theme = self.global_theme
else:
self.theme = self.service_theme
else:
self.theme = self.global_theme
2010-08-07 08:50:58 +00:00
if self.theme != self.renderer.theme_name or self.themedata is None \
or overrideLevels:
2009-09-21 17:56:36 +00:00
log.debug(u'theme is now %s', self.theme)
if overrideLevels:
self.themedata = theme
else:
self.themedata = self.theme_manager.getThemeData(self.theme)
self.calculate_default(self.screens.current[u'size'])
self.renderer.set_theme(self.themedata)
self.build_text_rectangle(self.themedata)
2010-07-14 17:36:48 +00:00
self.renderer.set_frame_dest(self.width, self.height)
2010-07-17 08:59:15 +00:00
return self.renderer._rect, self.renderer._rect_footer
def build_text_rectangle(self, theme):
2009-07-10 13:16:15 +00:00
"""
Builds a text block using the settings in ``theme``
and the size of the display screen.height.
2009-07-10 13:16:15 +00:00
``theme``
The theme to build a text block for.
"""
log.debug(u'build_text_rectangle')
main_rect = None
footer_rect = None
2009-11-03 15:13:52 +00:00
if not theme.font_main_override:
main_rect = QtCore.QRect(10, 0,
2010-03-13 20:50:52 +00:00
self.width - 20, self.footer_start)
else:
2009-11-04 01:16:15 +00:00
main_rect = QtCore.QRect(theme.font_main_x, theme.font_main_y,
theme.font_main_width - 1, theme.font_main_height - 1)
2009-11-03 15:13:52 +00:00
if not theme.font_footer_override:
footer_rect = QtCore.QRect(10, self.footer_start,
2010-03-13 20:50:52 +00:00
self.width - 20, self.height - self.footer_start)
else:
2009-11-04 01:16:15 +00:00
footer_rect = QtCore.QRect(theme.font_footer_x,
theme.font_footer_y, theme.font_footer_width - 1,
theme.font_footer_height - 1)
2009-08-31 06:53:55 +00:00
self.renderer.set_text_rectangle(main_rect, footer_rect)
def generate_preview(self, themedata):
2009-07-10 13:16:15 +00:00
"""
Generate a preview of a theme.
``themedata``
The theme to generated a preview for.
"""
log.debug(u'generate preview')
2010-08-05 19:01:24 +00:00
# set the default image size for previews
self.calculate_default(self.screens.preview[u'size'])
2009-11-15 07:07:40 +00:00
verse = u'Amazing Grace!\n'\
'How sweet the sound\n'\
'To save a wretch like me;\n'\
'I once was lost but now am found,\n'\
'Was blind, but now I see.'
2009-07-10 13:16:15 +00:00
footer = []
footer.append(u'Amazing Grace (John Newton)' )
footer.append(u'Public Domain')
footer.append(u'CCLI 123456')
# Previews do not need the transition switched on!
themedata.display_slideTransition = False
2010-07-25 08:58:08 +00:00
# build a service item to generate preview
2010-07-23 05:05:34 +00:00
serviceItem = ServiceItem()
2010-08-07 08:50:58 +00:00
serviceItem.theme = themedata
2010-07-26 16:42:19 +00:00
serviceItem.add_from_text(u'', verse, footer)
2010-07-23 05:05:34 +00:00
serviceItem.render_manager = self
2010-08-07 08:50:58 +00:00
serviceItem.render(True)
2010-07-23 05:05:34 +00:00
serviceItem.raw_footer = footer
self.display.buildHtml(serviceItem)
2010-07-25 07:21:10 +00:00
frame, raw_html = serviceItem.get_rendered_frame(0)
2010-08-07 08:50:58 +00:00
preview = self.display.text(raw_html)
# Reset the real screen size for subsequent render requests
self.calculate_default(self.screens.current[u'size'])
return preview
2010-08-03 19:23:05 +00:00
def format_slide(self, words, line_break):
2009-07-10 13:16:15 +00:00
"""
2009-08-31 06:53:55 +00:00
Calculate how much text can fit on a slide.
2009-07-10 13:16:15 +00:00
``words``
The words to go on the slides.
"""
log.debug(u'format slide')
2009-05-17 08:13:22 +00:00
self.build_text_rectangle(self.themedata)
2010-08-03 19:23:05 +00:00
return self.renderer.format_slide(words, line_break)
def calculate_default(self, screen):
2009-07-10 13:16:15 +00:00
"""
Calculate the default dimentions of the screen.
``screen``
The QSize of the screen.
2009-07-10 13:16:15 +00:00
"""
log.debug(u'calculate default %s', screen)
self.width = screen.width()
self.height = screen.height()
2009-09-20 07:12:47 +00:00
self.screen_ratio = float(self.height) / float(self.width)
2009-09-21 17:56:36 +00:00
log.debug(u'calculate default %d, %d, %f',
self.width, self.height, self.screen_ratio )
# 90% is start of footer
2010-07-26 15:51:18 +00:00
self.footer_start = int(self.height * 0.90)
2010-07-29 17:08:01 +00:00
def clean(self, text):
"""
Remove Tags from text for display
"""
text = text.replace(u'<br>', u'\n')
for tag in self.html_expands:
text = text.replace(tag[u'start tag'], u'')
text = text.replace(tag[u'end tag'], u'')
2010-07-29 17:08:01 +00:00
return text
def expand(self, text):
"""
2010-08-21 08:24:14 +00:00
Expand tags HTML for display
2010-07-29 17:08:01 +00:00
"""
for tag in self.html_expands:
text = text.replace(tag[u'start tag'], tag[u'start html'])
text = text.replace(tag[u'end tag'], tag[u'end html'])
2010-07-29 17:08:01 +00:00
return text