forked from openlp/openlp
Display and renderer changes
bzr-revno: 997
This commit is contained in:
commit
618813f020
@ -34,7 +34,8 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import Receiver
|
from openlp.core.lib import Receiver
|
||||||
from openlp.core.resources import qInitResources
|
from openlp.core.resources import qInitResources
|
||||||
from openlp.core.ui import MainWindow, SplashScreen, ScreenList
|
from openlp.core.ui.mainwindow import MainWindow
|
||||||
|
from openlp.core.ui import SplashScreen, ScreenList
|
||||||
from openlp.core.utils import AppLocation, LanguageManager, VersionThread
|
from openlp.core.utils import AppLocation, LanguageManager, VersionThread
|
||||||
|
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
|
@ -35,6 +35,67 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# TODO make external and configurable in alpha 4 via a settings dialog
|
||||||
|
html_expands = []
|
||||||
|
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \
|
||||||
|
u'start html':u'<font color=#CC33CC>', \
|
||||||
|
u'end tag':u'{/pk}', u'end html':u'</font>', \
|
||||||
|
u'protected':False})
|
||||||
|
html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \
|
||||||
|
u'start html':u'<font color=#CC0033>', \
|
||||||
|
u'end tag':u'{/o}', u'end html':u'</font>', \
|
||||||
|
u'protected':False})
|
||||||
|
html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \
|
||||||
|
u'start html':u'<font color=#9900FF>', \
|
||||||
|
u'end tag':u'{/pp}', u'end html':u'</font>', \
|
||||||
|
u'protected':False})
|
||||||
|
html_expands.append({u'desc':u'White', u'start tag':u'{w}', \
|
||||||
|
u'start html':u'<font color=white>', \
|
||||||
|
u'end tag':u'{/w}', u'end html':u'</font>', \
|
||||||
|
u'protected':False})
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', \
|
||||||
|
u'start html':u'<strong>', \
|
||||||
|
u'end tag':u'{/st}', \
|
||||||
|
u'end html':u'</strong>', \
|
||||||
|
u'protected':True})
|
||||||
|
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})
|
||||||
|
|
||||||
def translate(context, text, comment=None):
|
def translate(context, text, comment=None):
|
||||||
"""
|
"""
|
||||||
A special shortcut method to wrap around the Qt4 translation functions.
|
A special shortcut method to wrap around the Qt4 translation functions.
|
||||||
@ -166,15 +227,46 @@ def context_menu_separator(base):
|
|||||||
action.setSeparator(True)
|
action.setSeparator(True)
|
||||||
return action
|
return action
|
||||||
|
|
||||||
def resize_image(image, width, height):
|
def image_to_byte(image):
|
||||||
|
"""
|
||||||
|
Resize an image to fit on the current screen for the web and returns
|
||||||
|
it as a byte stream.
|
||||||
|
|
||||||
|
``image``
|
||||||
|
The image to converted.
|
||||||
|
"""
|
||||||
|
byte_array = QtCore.QByteArray()
|
||||||
|
# use buffer to store pixmap into byteArray
|
||||||
|
buffie = QtCore.QBuffer(byte_array)
|
||||||
|
buffie.open(QtCore.QIODevice.WriteOnly)
|
||||||
|
if isinstance(image, QtGui.QImage):
|
||||||
|
pixmap = QtGui.QPixmap.fromImage(image)
|
||||||
|
else:
|
||||||
|
pixmap = QtGui.QPixmap(image)
|
||||||
|
pixmap.save(buffie, "PNG")
|
||||||
|
# convert to base64 encoding so does not get missed!
|
||||||
|
return byte_array.toBase64()
|
||||||
|
|
||||||
|
def resize_image(image, width, height, background=QtCore.Qt.black):
|
||||||
"""
|
"""
|
||||||
Resize an image to fit on the current screen.
|
Resize an image to fit on the current screen.
|
||||||
|
|
||||||
``image``
|
``image``
|
||||||
The image to resize.
|
The image to resize.
|
||||||
|
|
||||||
|
``width``
|
||||||
|
The new image width.
|
||||||
|
|
||||||
|
``height``
|
||||||
|
The new image height.
|
||||||
|
|
||||||
|
``background``
|
||||||
|
The background colour defaults to black.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
preview = QtGui.QImage(image)
|
preview = QtGui.QImage(image)
|
||||||
if not preview.isNull():
|
if not preview.isNull():
|
||||||
|
# Only resize if different size
|
||||||
if preview.width() == width and preview.height == height:
|
if preview.width() == width and preview.height == height:
|
||||||
return preview
|
return preview
|
||||||
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
||||||
@ -184,7 +276,7 @@ def resize_image(image, width, height):
|
|||||||
# and move it to the centre of the preview space
|
# and move it to the centre of the preview space
|
||||||
new_image = QtGui.QImage(width, height,
|
new_image = QtGui.QImage(width, height,
|
||||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
new_image.fill(QtCore.Qt.black)
|
new_image.fill(background)
|
||||||
painter = QtGui.QPainter(new_image)
|
painter = QtGui.QPainter(new_image)
|
||||||
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
|
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
|
||||||
return new_image
|
return new_image
|
||||||
@ -205,6 +297,25 @@ def check_item_selected(list_widget, message):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def clean_tags(text):
|
||||||
|
"""
|
||||||
|
Remove Tags from text for display
|
||||||
|
"""
|
||||||
|
text = text.replace(u'<br>', u'\n')
|
||||||
|
for tag in html_expands:
|
||||||
|
text = text.replace(tag[u'start tag'], u'')
|
||||||
|
text = text.replace(tag[u'end tag'], u'')
|
||||||
|
return text
|
||||||
|
|
||||||
|
def expand_tags(text):
|
||||||
|
"""
|
||||||
|
Expand tags HTML for display
|
||||||
|
"""
|
||||||
|
for tag in html_expands:
|
||||||
|
text = text.replace(tag[u'start tag'], tag[u'start html'])
|
||||||
|
text = text.replace(tag[u'end tag'], tag[u'end html'])
|
||||||
|
return text
|
||||||
|
|
||||||
from eventreceiver import Receiver
|
from eventreceiver import Receiver
|
||||||
from settingsmanager import SettingsManager
|
from settingsmanager import SettingsManager
|
||||||
from plugin import PluginStatus, Plugin
|
from plugin import PluginStatus, Plugin
|
||||||
@ -213,6 +324,7 @@ from settingstab import SettingsTab
|
|||||||
from serviceitem import ServiceItem
|
from serviceitem import ServiceItem
|
||||||
from serviceitem import ServiceItemType
|
from serviceitem import ServiceItemType
|
||||||
from serviceitem import ItemCapabilities
|
from serviceitem import ItemCapabilities
|
||||||
|
from htmlbuilder import build_html
|
||||||
from toolbar import OpenLPToolbar
|
from toolbar import OpenLPToolbar
|
||||||
from dockwidget import OpenLPDockWidget
|
from dockwidget import OpenLPDockWidget
|
||||||
from theme import ThemeLevel, ThemeXML
|
from theme import ThemeLevel, ThemeXML
|
||||||
|
445
openlp/core/lib/htmlbuilder.py
Normal file
445
openlp/core/lib/htmlbuilder.py
Normal file
@ -0,0 +1,445 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
from openlp.core.lib import image_to_byte
|
||||||
|
|
||||||
|
HTMLSRC = u"""
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OpenLP Display</title>
|
||||||
|
<style>
|
||||||
|
*{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
.dim {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
width: %spx;
|
||||||
|
height: %spx;
|
||||||
|
}
|
||||||
|
#black {
|
||||||
|
z-index:8;
|
||||||
|
background-color: black;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#video {
|
||||||
|
z-index:2;
|
||||||
|
}
|
||||||
|
#alert {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
z-index:10;
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
#footer {
|
||||||
|
position: absolute;
|
||||||
|
z-index:5;
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
/* lyric css */
|
||||||
|
%s
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script language="javascript">
|
||||||
|
var timer = null;
|
||||||
|
var transition = %s;
|
||||||
|
|
||||||
|
function show_video(state, path, volume, loop){
|
||||||
|
var vid = document.getElementById('video');
|
||||||
|
if(path != null)
|
||||||
|
vid.src = path;
|
||||||
|
if(loop != null){
|
||||||
|
if(loop)
|
||||||
|
vid.loop = 'loop';
|
||||||
|
else
|
||||||
|
vid.loop = '';
|
||||||
|
}
|
||||||
|
if(volume != null){
|
||||||
|
vid.volume = volume;
|
||||||
|
}
|
||||||
|
switch(state){
|
||||||
|
case 'play':
|
||||||
|
vid.play();
|
||||||
|
vid.style.display = 'block';
|
||||||
|
break;
|
||||||
|
case 'pause':
|
||||||
|
vid.pause();
|
||||||
|
vid.style.display = 'block';
|
||||||
|
break;
|
||||||
|
case 'stop':
|
||||||
|
vid.pause();
|
||||||
|
vid.style.display = 'none';
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
vid.pause();
|
||||||
|
vid.style.display = 'none';
|
||||||
|
vid.src = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_image(src){
|
||||||
|
var img = document.getElementById('image');
|
||||||
|
img.src = src;
|
||||||
|
if(src == '')
|
||||||
|
img.style.display = 'none';
|
||||||
|
else
|
||||||
|
img.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_blank(state){
|
||||||
|
var black = 'none';
|
||||||
|
var lyrics = '';
|
||||||
|
var pause = false;
|
||||||
|
switch(state){
|
||||||
|
case 'theme':
|
||||||
|
lyrics = 'hidden';
|
||||||
|
pause = true;
|
||||||
|
break;
|
||||||
|
case 'black':
|
||||||
|
black = 'block';
|
||||||
|
pause = true;
|
||||||
|
break;
|
||||||
|
case 'desktop':
|
||||||
|
pause = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
document.getElementById('black').style.display = black;
|
||||||
|
document.getElementById('lyricsmain').style.visibility = lyrics;
|
||||||
|
document.getElementById('lyricsoutline').style.visibility = lyrics;
|
||||||
|
document.getElementById('lyricsshadow').style.visibility = lyrics;
|
||||||
|
document.getElementById('footer').style.visibility = lyrics;
|
||||||
|
var vid = document.getElementById('video');
|
||||||
|
if(vid.src != ''){
|
||||||
|
if(pause)
|
||||||
|
vid.pause();
|
||||||
|
else
|
||||||
|
vid.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_alert(alerttext, position){
|
||||||
|
var text = document.getElementById('alert');
|
||||||
|
text.innerHTML = alerttext;
|
||||||
|
if(alerttext == '') {
|
||||||
|
text.style.visibility = 'hidden';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(position == ''){
|
||||||
|
position = window.getComputedStyle(text, '').verticalAlign;
|
||||||
|
}
|
||||||
|
switch(position)
|
||||||
|
{
|
||||||
|
case 'top':
|
||||||
|
text.style.top = '0px';
|
||||||
|
break;
|
||||||
|
case 'middle':
|
||||||
|
text.style.top = ((window.innerHeight - text.clientHeight) / 2)
|
||||||
|
+ 'px';
|
||||||
|
break;
|
||||||
|
case 'bottom':
|
||||||
|
text.style.top = (window.innerHeight - text.clientHeight)
|
||||||
|
+ 'px';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
text.style.visibility = 'visible';
|
||||||
|
return text.clientHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_footer(footertext){
|
||||||
|
document.getElementById('footer').innerHTML = footertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_text(newtext){
|
||||||
|
var text1 = document.getElementById('lyricsmain');
|
||||||
|
var texto1 = document.getElementById('lyricsoutline');
|
||||||
|
var texts1 = document.getElementById('lyricsshadow');
|
||||||
|
if(!transition){
|
||||||
|
text1.innerHTML = newtext;
|
||||||
|
texto1.innerHTML = newtext;
|
||||||
|
texts1.innerHTML = newtext;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var text2 = document.getElementById('lyricsmain2');
|
||||||
|
var texto2 = document.getElementById('lyricsoutline2');
|
||||||
|
var texts2 = document.getElementById('lyricsshadow2');
|
||||||
|
if((text2.style.opacity == '')||(parseFloat(text2.style.opacity) < 0.5))
|
||||||
|
{
|
||||||
|
text2.innerHTML = text1.innerHTML;
|
||||||
|
text2.style.opacity = text1.style.opacity;
|
||||||
|
texto2.innerHTML = text1.innerHTML;
|
||||||
|
texto2.style.opacity = text1.style.opacity;
|
||||||
|
texts2.innerHTML = text1.innerHTML;
|
||||||
|
texts2.style.opacity = text1.style.opacity;
|
||||||
|
}
|
||||||
|
text1.style.opacity = 0;
|
||||||
|
text1.innerHTML = newtext;
|
||||||
|
texto1.style.opacity = 0;
|
||||||
|
texto1.innerHTML = newtext;
|
||||||
|
texts1.style.opacity = 0;
|
||||||
|
texts1.innerHTML = newtext;
|
||||||
|
// For performance reasons, we'll not animate the shadow for now
|
||||||
|
texts2.style.opacity = 0;
|
||||||
|
if(timer != null)
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout('text_fade()', 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function text_fade(){
|
||||||
|
var text1 = document.getElementById('lyricsmain');
|
||||||
|
var texto1 = document.getElementById('lyricsoutline');
|
||||||
|
var texts1 = document.getElementById('lyricsshadow');
|
||||||
|
var text2 = document.getElementById('lyricsmain2');
|
||||||
|
var texto2 = document.getElementById('lyricsoutline2');
|
||||||
|
var texts2 = document.getElementById('lyricsshadow2');
|
||||||
|
if(parseFloat(text1.style.opacity) < 1){
|
||||||
|
text1.style.opacity = parseFloat(text1.style.opacity) + 0.1;
|
||||||
|
texto1.style.opacity = parseFloat(texto1.style.opacity) + 0.1;
|
||||||
|
// Don't animate shadow (performance)
|
||||||
|
//texts1.style.opacity = parseFloat(texts1.style.opacity) + 0.1;
|
||||||
|
}
|
||||||
|
if(parseFloat(text2.style.opacity) > 0){
|
||||||
|
text2.style.opacity = parseFloat(text2.style.opacity) - 0.1;
|
||||||
|
texto2.style.opacity = parseFloat(texto2.style.opacity) - 0.1;
|
||||||
|
// Don't animate shadow (performance)
|
||||||
|
//texts2.style.opacity = parseFloat(texts2.style.opacity) - 0.1;
|
||||||
|
}
|
||||||
|
if((parseFloat(text1.style.opacity) < 1) ||
|
||||||
|
(parseFloat(text2.style.opacity) > 0)){
|
||||||
|
t = setTimeout('text_fade()', 50);
|
||||||
|
} else {
|
||||||
|
text1.style.opacity = 1;
|
||||||
|
texto1.style.opacity = 1;
|
||||||
|
texts1.style.opacity = 1;
|
||||||
|
text2.style.opacity = 0;
|
||||||
|
texto2.style.opacity = 0;
|
||||||
|
texts2.style.opacity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_text_complete(){
|
||||||
|
return (document.getElementById('lyricsmain').style.opacity == 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--
|
||||||
|
Using tables, rather than div's to make use of the vertical-align style that
|
||||||
|
doesn't work on div's. This avoids the need to do positioning manually which
|
||||||
|
could get messy when changing verses esp. with transitions
|
||||||
|
|
||||||
|
Would prefer to use a single table and make use of -webkit-text-fill-color
|
||||||
|
-webkit-text-stroke and text-shadow styles, but they have problems working/
|
||||||
|
co-operating in qwebkit. https://bugs.webkit.org/show_bug.cgi?id=43187
|
||||||
|
Therefore one table for text, one for outline and one for shadow.
|
||||||
|
-->
|
||||||
|
<table class="lyricstable lyricscommon">
|
||||||
|
<tr><td id="lyricsmain" class="lyrics"></td></tr>
|
||||||
|
</table>
|
||||||
|
<table class="lyricsoutlinetable lyricscommon">
|
||||||
|
<tr><td id="lyricsoutline" class="lyricsoutline lyrics"></td></tr>
|
||||||
|
</table>
|
||||||
|
<table class="lyricsshadowtable lyricscommon">
|
||||||
|
<tr><td id="lyricsshadow" class="lyricsshadow lyrics"></td></tr>
|
||||||
|
</table>
|
||||||
|
<table class="lyricstable lyricscommon">
|
||||||
|
<tr><td id="lyricsmain2" class="lyrics"></td></tr>
|
||||||
|
</table>
|
||||||
|
<table class="lyricsoutlinetable lyricscommon">
|
||||||
|
<tr><td id="lyricsoutline2" class="lyricsoutline lyrics"></td></tr>
|
||||||
|
</table>
|
||||||
|
<table class="lyricsshadowtable lyricscommon">
|
||||||
|
<tr><td id="lyricsshadow2" class="lyricsshadow lyrics"></td></tr>
|
||||||
|
</table>
|
||||||
|
<div id="alert" style="visibility:hidden;"></div>
|
||||||
|
<div id="footer" class="footer"></div>
|
||||||
|
<video class="dim" id="video"></video>
|
||||||
|
<div class="dim" id="black"></div>
|
||||||
|
<img class="dim" id="image" src="%s" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def build_html(item, screen, alert):
|
||||||
|
"""
|
||||||
|
Build the full web paged structure for display
|
||||||
|
|
||||||
|
`item`
|
||||||
|
Service Item to be displayed
|
||||||
|
`screen`
|
||||||
|
Current display information
|
||||||
|
`alert`
|
||||||
|
Alert display display information
|
||||||
|
"""
|
||||||
|
width = screen[u'size'].width()
|
||||||
|
height = screen[u'size'].height()
|
||||||
|
theme = item.themedata
|
||||||
|
if item.bg_frame:
|
||||||
|
image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame)
|
||||||
|
else:
|
||||||
|
image = u''
|
||||||
|
html = HTMLSRC % (width, height,
|
||||||
|
build_alert(alert, width),
|
||||||
|
build_footer(item),
|
||||||
|
build_lyrics(item),
|
||||||
|
u'true' if theme and theme.display_slideTransition \
|
||||||
|
else u'false',
|
||||||
|
image)
|
||||||
|
return html
|
||||||
|
|
||||||
|
def build_lyrics(item):
|
||||||
|
"""
|
||||||
|
Build the video display div
|
||||||
|
|
||||||
|
`item`
|
||||||
|
Service Item containing theme and location information
|
||||||
|
"""
|
||||||
|
style = """
|
||||||
|
.lyricscommon { position: absolute; %s }
|
||||||
|
.lyricstable { z-index:4; %s }
|
||||||
|
.lyricsoutlinetable { z-index:3; %s }
|
||||||
|
.lyricsshadowtable { z-index:2; %s }
|
||||||
|
.lyrics { %s }
|
||||||
|
.lyricsoutline { %s }
|
||||||
|
.lyricsshadow { %s }
|
||||||
|
"""
|
||||||
|
theme = item.themedata
|
||||||
|
lyricscommon = u''
|
||||||
|
lyricstable = u''
|
||||||
|
outlinetable = u''
|
||||||
|
shadowtable = u''
|
||||||
|
lyrics = u''
|
||||||
|
outline = u'display: none;'
|
||||||
|
shadow = u'display: none;'
|
||||||
|
if theme:
|
||||||
|
lyricscommon = u'width: %spx; height: %spx; word-wrap: break-word; ' \
|
||||||
|
u'font-family: %s; font-size: %spx; color: %s; line-height: %d%%;' % \
|
||||||
|
(item.main.width(), item.main.height(),
|
||||||
|
theme.font_main_name, theme.font_main_proportion,
|
||||||
|
theme.font_main_color, 100 + int(theme.font_main_line_adjustment))
|
||||||
|
lyricstable = u'left: %spx; top: %spx;' % \
|
||||||
|
(item.main.x(), item.main.y())
|
||||||
|
outlinetable = u'left: %spx; top: %spx;' % \
|
||||||
|
(item.main.x(), item.main.y())
|
||||||
|
shadowtable = u'left: %spx; top: %spx;' % \
|
||||||
|
(item.main.x() + float(theme.display_shadow_size),
|
||||||
|
item.main.y() + float(theme.display_shadow_size))
|
||||||
|
align = u''
|
||||||
|
if theme.display_horizontalAlign == 2:
|
||||||
|
align = u'text-align:center;'
|
||||||
|
elif theme.display_horizontalAlign == 1:
|
||||||
|
align = u'text-align:right;'
|
||||||
|
else:
|
||||||
|
align = u'text-align:left;'
|
||||||
|
if theme.display_verticalAlign == 2:
|
||||||
|
valign = u'vertical-align:bottom;'
|
||||||
|
elif theme.display_verticalAlign == 1:
|
||||||
|
valign = u'vertical-align:middle;'
|
||||||
|
else:
|
||||||
|
valign = u'vertical-align:top;'
|
||||||
|
lyrics = u'%s %s' % (align, valign)
|
||||||
|
if theme.display_outline:
|
||||||
|
lyricscommon += u' letter-spacing: 1px;'
|
||||||
|
outline = u'-webkit-text-stroke: %sem %s; ' % \
|
||||||
|
(float(theme.display_outline_size) / 16,
|
||||||
|
theme.display_outline_color)
|
||||||
|
if theme.display_shadow:
|
||||||
|
shadow = u'-webkit-text-stroke: %sem %s; ' \
|
||||||
|
u'-webkit-text-fill-color: %s; '% \
|
||||||
|
(float(theme.display_outline_size) / 16,
|
||||||
|
theme.display_shadow_color, theme.display_shadow_color)
|
||||||
|
else:
|
||||||
|
if theme.display_shadow:
|
||||||
|
shadow = u'color: %s;' % (theme.display_shadow_color)
|
||||||
|
lyrics_html = style % (lyricscommon, lyricstable, outlinetable,
|
||||||
|
shadowtable, lyrics, outline, shadow)
|
||||||
|
return lyrics_html
|
||||||
|
|
||||||
|
def build_footer(item):
|
||||||
|
"""
|
||||||
|
Build the display of the item footer
|
||||||
|
|
||||||
|
`item`
|
||||||
|
Service Item to be processed.
|
||||||
|
"""
|
||||||
|
style = """
|
||||||
|
left: %spx;
|
||||||
|
top: %spx;
|
||||||
|
width: %spx;
|
||||||
|
height: %spx;
|
||||||
|
font-family: %s;
|
||||||
|
font-size: %spx;
|
||||||
|
color: %s;
|
||||||
|
text-align: %s;
|
||||||
|
"""
|
||||||
|
theme = item.themedata
|
||||||
|
if not theme:
|
||||||
|
return u''
|
||||||
|
if theme.display_horizontalAlign == 2:
|
||||||
|
align = u'center'
|
||||||
|
elif theme.display_horizontalAlign == 1:
|
||||||
|
align = u'right'
|
||||||
|
else:
|
||||||
|
align = u'left'
|
||||||
|
lyrics_html = style % (item.footer.x(), item.footer.y(),
|
||||||
|
item.footer.width(), item.footer.height(), theme.font_footer_name,
|
||||||
|
theme.font_footer_proportion, theme.font_footer_color, align)
|
||||||
|
return lyrics_html
|
||||||
|
|
||||||
|
def build_alert(alertTab, width):
|
||||||
|
"""
|
||||||
|
Build the display of the footer
|
||||||
|
|
||||||
|
`alertTab`
|
||||||
|
Details from the Alert tab for fonts etc
|
||||||
|
"""
|
||||||
|
style = """
|
||||||
|
width: %s;
|
||||||
|
vertical-align: %s;
|
||||||
|
font-family: %s;
|
||||||
|
font-size: %spx;
|
||||||
|
color: %s;
|
||||||
|
background-color: %s;
|
||||||
|
"""
|
||||||
|
if not alertTab:
|
||||||
|
return u''
|
||||||
|
align = u''
|
||||||
|
if alertTab.location == 2:
|
||||||
|
align = u'bottom'
|
||||||
|
elif alertTab.location == 1:
|
||||||
|
align = u'middle'
|
||||||
|
else:
|
||||||
|
align = u'top'
|
||||||
|
alert = style % (width, align, alertTab.font_face, alertTab.font_size,
|
||||||
|
alertTab.font_color, alertTab.bg_color)
|
||||||
|
return alert
|
@ -131,7 +131,6 @@ class Plugin(QtCore.QObject):
|
|||||||
self.serviceManager = plugin_helpers[u'service']
|
self.serviceManager = plugin_helpers[u'service']
|
||||||
self.settingsForm = plugin_helpers[u'settings form']
|
self.settingsForm = plugin_helpers[u'settings form']
|
||||||
self.mediadock = plugin_helpers[u'toolbox']
|
self.mediadock = plugin_helpers[u'toolbox']
|
||||||
self.displayManager = plugin_helpers[u'displaymanager']
|
|
||||||
self.pluginManager = plugin_helpers[u'pluginmanager']
|
self.pluginManager = plugin_helpers[u'pluginmanager']
|
||||||
self.formparent = plugin_helpers[u'formparent']
|
self.formparent = plugin_helpers[u'formparent']
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
|
@ -31,7 +31,7 @@ import logging
|
|||||||
|
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
|
|
||||||
from openlp.core.lib import resize_image
|
from openlp.core.lib import resize_image, expand_tags
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -80,7 +80,6 @@ class Renderer(object):
|
|||||||
self.bg_image = None
|
self.bg_image = None
|
||||||
self._bg_image_filename = None
|
self._bg_image_filename = None
|
||||||
self.theme_name = theme.theme_name
|
self.theme_name = theme.theme_name
|
||||||
self._set_theme_font()
|
|
||||||
if theme.background_type == u'image':
|
if theme.background_type == u'image':
|
||||||
if theme.background_filename:
|
if theme.background_filename:
|
||||||
self.set_bg_image(theme.background_filename)
|
self.set_bg_image(theme.background_filename)
|
||||||
@ -99,6 +98,20 @@ class Renderer(object):
|
|||||||
self.frame.width(),
|
self.frame.width(),
|
||||||
self.frame.height())
|
self.frame.height())
|
||||||
|
|
||||||
|
def set_text_rectangle(self, rect_main, rect_footer):
|
||||||
|
"""
|
||||||
|
Sets the rectangle within which text should be rendered.
|
||||||
|
|
||||||
|
``rect_main``
|
||||||
|
The main text block.
|
||||||
|
|
||||||
|
``rect_footer``
|
||||||
|
The footer text block.
|
||||||
|
"""
|
||||||
|
log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer))
|
||||||
|
self._rect = rect_main
|
||||||
|
self._rect_footer = rect_footer
|
||||||
|
|
||||||
def set_frame_dest(self, frame_width, frame_height, preview=False):
|
def set_frame_dest(self, frame_width, frame_height, preview=False):
|
||||||
"""
|
"""
|
||||||
Set the size of the slide.
|
Set the size of the slide.
|
||||||
@ -118,26 +131,24 @@ class Renderer(object):
|
|||||||
frame_height)
|
frame_height)
|
||||||
self.frame = QtGui.QImage(frame_width, frame_height,
|
self.frame = QtGui.QImage(frame_width, frame_height,
|
||||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
self.frame_opaque = QtGui.QImage(frame_width, frame_height,
|
|
||||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
|
||||||
if self._bg_image_filename and not self.bg_image:
|
if self._bg_image_filename and not self.bg_image:
|
||||||
self.bg_image = resize_image(self._bg_image_filename,
|
self.bg_image = resize_image(self._bg_image_filename,
|
||||||
self.frame.width(), self.frame.height())
|
self.frame.width(), self.frame.height())
|
||||||
if self.bg_frame is None:
|
if self.bg_frame is None:
|
||||||
self._generate_background_frame()
|
self._generate_background_frame()
|
||||||
|
|
||||||
def format_slide(self, words, footer):
|
def format_slide(self, words, line_break):
|
||||||
"""
|
"""
|
||||||
Figure out how much text can appear on a slide, using the current
|
Figure out how much text can appear on a slide, using the current
|
||||||
theme settings.
|
theme settings.
|
||||||
|
|
||||||
``words``
|
``words``
|
||||||
The words to be fitted on the slide.
|
The words to be fitted on the slide.
|
||||||
|
|
||||||
``footer``
|
|
||||||
The footer of the slide.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'format_slide - Start')
|
log.debug(u'format_slide - Start')
|
||||||
|
line_end = u''
|
||||||
|
if line_break:
|
||||||
|
line_end = u'<br>'
|
||||||
words = words.replace(u'\r\n', u'\n')
|
words = words.replace(u'\r\n', u'\n')
|
||||||
verses_text = words.split(u'\n')
|
verses_text = words.split(u'\n')
|
||||||
text = []
|
text = []
|
||||||
@ -145,124 +156,43 @@ class Renderer(object):
|
|||||||
lines = verse.split(u'\n')
|
lines = verse.split(u'\n')
|
||||||
for line in lines:
|
for line in lines:
|
||||||
text.append(line)
|
text.append(line)
|
||||||
split_text = self.pre_render_text(text)
|
doc = QtGui.QTextDocument()
|
||||||
log.debug(u'format_slide - End')
|
doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height()))
|
||||||
return split_text
|
df = doc.defaultFont()
|
||||||
|
df.setPixelSize(self._theme.font_main_proportion)
|
||||||
def pre_render_text(self, text):
|
df.setFamily(self._theme.font_main_name)
|
||||||
metrics = QtGui.QFontMetrics(self.main_font)
|
main_weight = 50
|
||||||
#work out line width
|
if self._theme.font_main_weight == u'Bold':
|
||||||
line_width = self._rect.width()
|
main_weight = 75
|
||||||
#number of lines on a page - adjust for rounding up.
|
df.setWeight(main_weight)
|
||||||
line_height = metrics.height()
|
doc.setDefaultFont(df)
|
||||||
if self._theme.display_shadow:
|
layout = doc.documentLayout()
|
||||||
line_height += int(self._theme.display_shadow_size)
|
formatted = []
|
||||||
if self._theme.display_outline:
|
if self._theme.font_main_weight == u'Bold' and \
|
||||||
# pixels top/bottom
|
self._theme.font_main_italics:
|
||||||
line_height += 2 * int(self._theme.display_outline_size)
|
shell = u'{p}{st}{it}%s{/it}{/st}{/p}'
|
||||||
page_length = int(self._rect.height() / line_height )
|
elif self._theme.font_main_weight == u'Bold' and \
|
||||||
#Average number of characters in line
|
not self._theme.font_main_italics:
|
||||||
ave_line_width = line_width / metrics.averageCharWidth()
|
shell = u'{p}{st}%s{/st}{/p}'
|
||||||
#Maximum size of a character
|
elif self._theme.font_main_italics:
|
||||||
max_char_width = metrics.maxWidth()
|
shell = u'{p}{it}%s{/it}{/p}'
|
||||||
#Max characters pre line based on min size of a character
|
else:
|
||||||
char_per_line = line_width / metrics.width(u'i')
|
shell = u'{p}%s{/p}'
|
||||||
log.debug(u'Page Length area height %s , metrics %s , lines %s' %
|
temp_text = u''
|
||||||
(int(self._rect.height()), metrics.height(), page_length ))
|
old_html_text = u''
|
||||||
split_pages = []
|
|
||||||
page = []
|
|
||||||
split_lines = []
|
|
||||||
count = 0
|
|
||||||
for line in text:
|
for line in text:
|
||||||
#Must be a blank line so keep it.
|
# mark line ends
|
||||||
if len(line) == 0:
|
temp_text = temp_text + line + line_end
|
||||||
line = u' '
|
html_text = shell % expand_tags(temp_text)
|
||||||
while line:
|
doc.setHtml(html_text)
|
||||||
pos = char_per_line
|
# Text too long so gone to next mage
|
||||||
split_text = line[:pos]
|
if layout.pageCount() != 1:
|
||||||
#line needs splitting
|
formatted.append(shell % old_html_text)
|
||||||
if metrics.width(split_text, -1) > line_width:
|
temp_text = line
|
||||||
#We have no spaces
|
old_html_text = temp_text
|
||||||
if split_text.find(u' ') == -1:
|
formatted.append(shell % old_html_text)
|
||||||
#Move back 1 char at a time till it fits
|
log.debug(u'format_slide - End')
|
||||||
while metrics.width(split_text, -1) > line_width:
|
return formatted
|
||||||
split_text = split_text[:-1]
|
|
||||||
pos = len(split_text)
|
|
||||||
else:
|
|
||||||
#We have spaces so split at previous one
|
|
||||||
while metrics.width(split_text, -1) > line_width:
|
|
||||||
pos = split_text.rfind(u' ')
|
|
||||||
#no more spaces and we are still too long
|
|
||||||
if pos == -1:
|
|
||||||
while \
|
|
||||||
metrics.width(split_text, -1) > line_width:
|
|
||||||
split_text = split_text[:-1]
|
|
||||||
pos = len(split_text)
|
|
||||||
else:
|
|
||||||
split_text = line[:pos]
|
|
||||||
split_lines.append(split_text)
|
|
||||||
line = line[pos:].lstrip()
|
|
||||||
#if we have more text add up to 10 spaces on the front.
|
|
||||||
if line and self._theme.font_main_indentation > 0:
|
|
||||||
line = u'%s%s' % \
|
|
||||||
(u' '[:int(self._theme.font_main_indentation)],
|
|
||||||
line)
|
|
||||||
#Text fits in a line now
|
|
||||||
for count, line in enumerate(split_lines):
|
|
||||||
page.append(line)
|
|
||||||
#last but one line and only 2 lines to go or end of page
|
|
||||||
if (len(page) == page_length - 1 and
|
|
||||||
len(split_lines) - 3 == count) or \
|
|
||||||
len(page) == page_length:
|
|
||||||
split_pages.append(page)
|
|
||||||
page = []
|
|
||||||
if page and page != u' ':
|
|
||||||
split_pages.append(page)
|
|
||||||
return split_pages
|
|
||||||
|
|
||||||
def set_text_rectangle(self, rect_main, rect_footer):
|
|
||||||
"""
|
|
||||||
Sets the rectangle within which text should be rendered.
|
|
||||||
|
|
||||||
``rect_main``
|
|
||||||
The main text block.
|
|
||||||
|
|
||||||
``rect_footer``
|
|
||||||
The footer text block.
|
|
||||||
"""
|
|
||||||
log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer))
|
|
||||||
self._rect = rect_main
|
|
||||||
self._rect_footer = rect_footer
|
|
||||||
|
|
||||||
def generate_frame_from_lines(self, lines, footer_lines=None):
|
|
||||||
"""
|
|
||||||
Render a set of lines according to the theme, and return the block
|
|
||||||
dimensions.
|
|
||||||
|
|
||||||
``lines``
|
|
||||||
The lines to be rendered.
|
|
||||||
|
|
||||||
``footer_lines``
|
|
||||||
Defaults to *None*. The footer to render.
|
|
||||||
"""
|
|
||||||
log.debug(u'generate_frame_from_lines - Start')
|
|
||||||
bbox = self._render_lines_unaligned(lines, False)
|
|
||||||
if footer_lines:
|
|
||||||
bbox1 = self._render_lines_unaligned(footer_lines, True)
|
|
||||||
# reset the frame. first time do not worry about what you paint on.
|
|
||||||
self.frame = QtGui.QImage(self.bg_frame)
|
|
||||||
if self._theme.display_slideTransition:
|
|
||||||
self.frame_opaque = QtGui.QImage(self.bg_frame)
|
|
||||||
x, y = self._correct_alignment(self._rect, bbox)
|
|
||||||
bbox = self._render_lines_unaligned(lines, False, (x, y), True)
|
|
||||||
if footer_lines:
|
|
||||||
bbox = self._render_lines_unaligned(footer_lines, True,
|
|
||||||
(self._rect_footer.left(), self._rect_footer.top()), True)
|
|
||||||
log.debug(u'generate_frame_from_lines - Finish')
|
|
||||||
if self._theme.display_slideTransition:
|
|
||||||
return {u'main':self.frame, u'trans':self.frame_opaque}
|
|
||||||
else:
|
|
||||||
return {u'main':self.frame, u'trans':None}
|
|
||||||
|
|
||||||
def _generate_background_frame(self):
|
def _generate_background_frame(self):
|
||||||
"""
|
"""
|
||||||
@ -270,19 +200,11 @@ class Renderer(object):
|
|||||||
Results are cached for performance reasons.
|
Results are cached for performance reasons.
|
||||||
"""
|
"""
|
||||||
assert(self._theme)
|
assert(self._theme)
|
||||||
if self._theme.background_mode == u'transparent':
|
|
||||||
self.bg_frame = \
|
|
||||||
QtGui.QPixmap(self.frame.width(), self.frame.height())
|
|
||||||
self.bg_frame.fill(QtCore.Qt.transparent)
|
|
||||||
else:
|
|
||||||
self.bg_frame = QtGui.QImage(self.frame.width(),
|
self.bg_frame = QtGui.QImage(self.frame.width(),
|
||||||
self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
|
self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
log.debug(u'render background %s start', self._theme.background_type)
|
log.debug(u'render background %s start', self._theme.background_type)
|
||||||
painter = QtGui.QPainter()
|
painter = QtGui.QPainter()
|
||||||
painter.begin(self.bg_frame)
|
painter.begin(self.bg_frame)
|
||||||
if self._theme.background_mode == u'transparent':
|
|
||||||
painter.fillRect(self.frame.rect(), QtCore.Qt.transparent)
|
|
||||||
else:
|
|
||||||
if self._theme.background_type == u'solid':
|
if self._theme.background_type == u'solid':
|
||||||
painter.fillRect(self.frame.rect(),
|
painter.fillRect(self.frame.rect(),
|
||||||
QtGui.QColor(self._theme.background_color))
|
QtGui.QColor(self._theme.background_color))
|
||||||
@ -292,13 +214,11 @@ class Renderer(object):
|
|||||||
if self._theme.background_direction == u'horizontal':
|
if self._theme.background_direction == u'horizontal':
|
||||||
w = int(self.frame.width()) / 2
|
w = int(self.frame.width()) / 2
|
||||||
# vertical
|
# vertical
|
||||||
gradient = QtGui.QLinearGradient(w, 0, w,
|
gradient = QtGui.QLinearGradient(w, 0, w, self.frame.height())
|
||||||
self.frame.height())
|
|
||||||
elif self._theme.background_direction == u'vertical':
|
elif self._theme.background_direction == u'vertical':
|
||||||
h = int(self.frame.height()) / 2
|
h = int(self.frame.height()) / 2
|
||||||
# Horizontal
|
# Horizontal
|
||||||
gradient = QtGui.QLinearGradient(0, h, self.frame.width(),
|
gradient = QtGui.QLinearGradient(0, h, self.frame.width(), h)
|
||||||
h)
|
|
||||||
else:
|
else:
|
||||||
w = int(self.frame.width()) / 2
|
w = int(self.frame.width()) / 2
|
||||||
h = int(self.frame.height()) / 2
|
h = int(self.frame.height()) / 2
|
||||||
@ -324,273 +244,3 @@ class Renderer(object):
|
|||||||
if self.bg_image:
|
if self.bg_image:
|
||||||
painter.drawImage(0, 0, self.bg_image)
|
painter.drawImage(0, 0, self.bg_image)
|
||||||
painter.end()
|
painter.end()
|
||||||
log.debug(u'render background End')
|
|
||||||
|
|
||||||
def _correct_alignment(self, rect, bbox):
|
|
||||||
"""
|
|
||||||
Corrects the vertical alignment of text.
|
|
||||||
|
|
||||||
``rect``
|
|
||||||
The block dimentions.
|
|
||||||
|
|
||||||
``bbox``
|
|
||||||
Footer dimensions?
|
|
||||||
"""
|
|
||||||
x = rect.left()
|
|
||||||
if self._theme.display_verticalAlign == 0:
|
|
||||||
# top align
|
|
||||||
y = rect.top()
|
|
||||||
elif self._theme.display_verticalAlign == 2:
|
|
||||||
# bottom align
|
|
||||||
y = rect.bottom() - bbox.height()
|
|
||||||
elif self._theme.display_verticalAlign == 1:
|
|
||||||
# centre align
|
|
||||||
y = rect.top() + (rect.height() - bbox.height()) / 2
|
|
||||||
else:
|
|
||||||
log.error(u'Invalid value for theme.VerticalAlign:%s',
|
|
||||||
self._theme.display_verticalAlign)
|
|
||||||
return x, y
|
|
||||||
|
|
||||||
def _render_lines_unaligned(self, lines, footer, tlcorner=(0, 0),
|
|
||||||
live=False):
|
|
||||||
"""
|
|
||||||
Given a list of lines to render, render each one in turn (using the
|
|
||||||
``_render_single_line`` fn - which may result in going off the bottom).
|
|
||||||
They are expected to be pre-arranged to less than a screenful (eg. by
|
|
||||||
using split_set_of_lines).
|
|
||||||
|
|
||||||
Returns the bounding box of the text as QRect.
|
|
||||||
|
|
||||||
``lines``
|
|
||||||
The lines of text to render.
|
|
||||||
|
|
||||||
``footer``
|
|
||||||
The slide footer.
|
|
||||||
|
|
||||||
``tlcorner``
|
|
||||||
Defaults to *``(0, 0)``*. Co-ordinates of the top left corner.
|
|
||||||
|
|
||||||
``live``
|
|
||||||
Defaults to *False*. Whether or not this is a live screen.
|
|
||||||
"""
|
|
||||||
x, y = tlcorner
|
|
||||||
brx = x
|
|
||||||
bry = y
|
|
||||||
for line in lines:
|
|
||||||
# render after current bottom, but at original left edge
|
|
||||||
# keep track of right edge to see which is biggest
|
|
||||||
(thisx, bry) = self._render_and_wrap_single_line(line, footer,
|
|
||||||
(x, bry), live)
|
|
||||||
if (thisx > brx):
|
|
||||||
brx = thisx
|
|
||||||
retval = QtCore.QRect(x, y, brx - x, bry - y)
|
|
||||||
if self._debug:
|
|
||||||
painter = QtGui.QPainter()
|
|
||||||
painter.begin(self.frame)
|
|
||||||
painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 255)))
|
|
||||||
painter.drawRect(retval)
|
|
||||||
painter.end()
|
|
||||||
return retval
|
|
||||||
|
|
||||||
def _render_and_wrap_single_line(self, line, footer, tlcorner=(0, 0),
|
|
||||||
live=False):
|
|
||||||
"""
|
|
||||||
Render a single line of words onto the DC, top left corner specified.
|
|
||||||
If the line is too wide for the context, it wraps, but right-aligns
|
|
||||||
the surplus words in the manner of song lyrics.
|
|
||||||
|
|
||||||
Returns the bottom-right corner (of what was rendered) as a tuple(x, y).
|
|
||||||
|
|
||||||
``line``
|
|
||||||
Line of text to be rendered.
|
|
||||||
|
|
||||||
``footer``
|
|
||||||
The footer of the slide.
|
|
||||||
|
|
||||||
``tlcorner``
|
|
||||||
Defaults to *``(0, 0)``*. The top left corner.
|
|
||||||
|
|
||||||
``live``
|
|
||||||
Defaults to *False*. Whether or not this is a live screen.
|
|
||||||
"""
|
|
||||||
x, y = tlcorner
|
|
||||||
maxx = self._rect.width()
|
|
||||||
maxy = self._rect.height()
|
|
||||||
lines = []
|
|
||||||
lines.append(line)
|
|
||||||
startx = x
|
|
||||||
starty = y
|
|
||||||
rightextent = None
|
|
||||||
self.painter = QtGui.QPainter()
|
|
||||||
self.painter.begin(self.frame)
|
|
||||||
self.painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
||||||
if self._theme.display_slideTransition:
|
|
||||||
self.painter2 = QtGui.QPainter()
|
|
||||||
self.painter2.begin(self.frame_opaque)
|
|
||||||
self.painter2.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
||||||
self.painter2.setOpacity(0.7)
|
|
||||||
# dont allow alignment messing with footers
|
|
||||||
if footer:
|
|
||||||
align = 0
|
|
||||||
display_shadow_size = self._display_shadow_size_footer
|
|
||||||
display_outline_size = self._display_outline_size_footer
|
|
||||||
else:
|
|
||||||
align = self._theme.display_horizontalAlign
|
|
||||||
display_shadow_size = int(self._theme.display_shadow_size)
|
|
||||||
display_outline_size = int(self._theme.display_outline_size)
|
|
||||||
for linenum in range(len(lines)):
|
|
||||||
line = lines[linenum]
|
|
||||||
#find out how wide line is
|
|
||||||
w, h = self._get_extent_and_render(line, footer, tlcorner=(x, y),
|
|
||||||
draw=False)
|
|
||||||
if self._theme.display_shadow:
|
|
||||||
w += display_shadow_size
|
|
||||||
h += display_shadow_size
|
|
||||||
if self._theme.display_outline:
|
|
||||||
# pixels either side
|
|
||||||
w += 2 * display_outline_size
|
|
||||||
# pixels top/bottom
|
|
||||||
h += 2 * display_outline_size
|
|
||||||
if align == 0: # left align
|
|
||||||
rightextent = x + w
|
|
||||||
# shift right from last line's rh edge
|
|
||||||
if self._theme.display_wrapStyle == 1 and linenum != 0:
|
|
||||||
rightextent = self._first_line_right_extent
|
|
||||||
if rightextent > maxx:
|
|
||||||
rightextent = maxx
|
|
||||||
x = rightextent - w
|
|
||||||
# right align
|
|
||||||
elif align == 1:
|
|
||||||
rightextent = maxx
|
|
||||||
x = maxx - w
|
|
||||||
# centre
|
|
||||||
elif align == 2:
|
|
||||||
x = (maxx - w) / 2
|
|
||||||
rightextent = x + w
|
|
||||||
if live:
|
|
||||||
# now draw the text, and any outlines/shadows
|
|
||||||
if self._theme.display_shadow:
|
|
||||||
self._get_extent_and_render(line, footer,
|
|
||||||
tlcorner=(x + display_shadow_size,
|
|
||||||
y + display_shadow_size),
|
|
||||||
draw=True, color=self._theme.display_shadow_color)
|
|
||||||
self._get_extent_and_render(line, footer, tlcorner=(x, y),
|
|
||||||
draw=True, outline_size=display_outline_size)
|
|
||||||
y += h
|
|
||||||
if linenum == 0:
|
|
||||||
self._first_line_right_extent = rightextent
|
|
||||||
# draw a box around the text - debug only
|
|
||||||
|
|
||||||
if self._debug:
|
|
||||||
self.painter.setPen(QtGui.QPen(QtGui.QColor(0, 255, 0)))
|
|
||||||
self.painter.drawRect(startx, starty, rightextent-startx, y-starty)
|
|
||||||
brcorner = (rightextent, y)
|
|
||||||
self.painter.end()
|
|
||||||
if self._theme.display_slideTransition:
|
|
||||||
self.painter2.end()
|
|
||||||
return brcorner
|
|
||||||
|
|
||||||
def _set_theme_font(self):
|
|
||||||
"""
|
|
||||||
Set the fonts from the current theme settings.
|
|
||||||
"""
|
|
||||||
footer_weight = 50
|
|
||||||
if self._theme.font_footer_weight == u'Bold':
|
|
||||||
footer_weight = 75
|
|
||||||
#TODO Add myfont.setPixelSize((screen_height / 100) * font_size)
|
|
||||||
self.footer_font = QtGui.QFont(self._theme.font_footer_name,
|
|
||||||
self._theme.font_footer_proportion, # size
|
|
||||||
footer_weight, # weight
|
|
||||||
self._theme.font_footer_italics) # italic
|
|
||||||
self.footer_font.setPixelSize(self._theme.font_footer_proportion)
|
|
||||||
main_weight = 50
|
|
||||||
if self._theme.font_main_weight == u'Bold':
|
|
||||||
main_weight = 75
|
|
||||||
self.main_font = QtGui.QFont(self._theme.font_main_name,
|
|
||||||
self._theme.font_main_proportion, # size
|
|
||||||
main_weight, # weight
|
|
||||||
self._theme.font_main_italics)# italic
|
|
||||||
self.main_font.setPixelSize(self._theme.font_main_proportion)
|
|
||||||
|
|
||||||
def _get_extent_and_render(self, line, footer, tlcorner=(0, 0), draw=False,
|
|
||||||
color=None, outline_size=0):
|
|
||||||
"""
|
|
||||||
Find bounding box of text - as render_single_line. If draw is set,
|
|
||||||
actually draw the text to the current DC as well return width and
|
|
||||||
height of text as a tuple (w, h).
|
|
||||||
|
|
||||||
``line``
|
|
||||||
The line of text to render.
|
|
||||||
|
|
||||||
``footer``
|
|
||||||
The footer text.
|
|
||||||
|
|
||||||
``tlcorner``
|
|
||||||
Defaults to *``(0, 0)``*. The top left corner co-ordinates.
|
|
||||||
|
|
||||||
``draw``
|
|
||||||
Defaults to *False*. Draw the text to the current surface.
|
|
||||||
|
|
||||||
``color``
|
|
||||||
Defaults to *None*. The colour to draw with.
|
|
||||||
"""
|
|
||||||
# setup defaults
|
|
||||||
if footer:
|
|
||||||
font = self.footer_font
|
|
||||||
else:
|
|
||||||
font = self.main_font
|
|
||||||
metrics = QtGui.QFontMetrics(font)
|
|
||||||
w = metrics.width(line)
|
|
||||||
if footer:
|
|
||||||
h = metrics.height()
|
|
||||||
else:
|
|
||||||
h = metrics.height() + int(self._theme.font_main_line_adjustment)
|
|
||||||
if draw:
|
|
||||||
self.painter.setFont(font)
|
|
||||||
if color is None:
|
|
||||||
if footer:
|
|
||||||
pen = QtGui.QColor(self._theme.font_footer_color)
|
|
||||||
else:
|
|
||||||
pen = QtGui.QColor(self._theme.font_main_color)
|
|
||||||
else:
|
|
||||||
pen = QtGui.QColor(color)
|
|
||||||
x, y = tlcorner
|
|
||||||
rowpos = y + metrics.ascent()
|
|
||||||
if self._theme.display_outline and outline_size != 0 and not footer:
|
|
||||||
path = QtGui.QPainterPath()
|
|
||||||
path.addText(QtCore.QPointF(x, rowpos), font, line)
|
|
||||||
self.painter.setBrush(self.painter.pen().brush())
|
|
||||||
self.painter.setPen(QtGui.QPen(QtGui.QColor(
|
|
||||||
self._theme.display_outline_color), outline_size))
|
|
||||||
self.painter.drawPath(path)
|
|
||||||
self.painter.setPen(pen)
|
|
||||||
self.painter.drawText(x, rowpos, line)
|
|
||||||
if self._theme.display_slideTransition:
|
|
||||||
# Print 2nd image with 70% weight
|
|
||||||
if self._theme.display_outline and outline_size != 0 and \
|
|
||||||
not footer:
|
|
||||||
path = QtGui.QPainterPath()
|
|
||||||
path.addText(QtCore.QPointF(x, rowpos), font, line)
|
|
||||||
self.painter2.setBrush(self.painter2.pen().brush())
|
|
||||||
self.painter2.setPen(QtGui.QPen(
|
|
||||||
QtGui.QColor(self._theme.display_outline_color),
|
|
||||||
outline_size))
|
|
||||||
self.painter2.drawPath(path)
|
|
||||||
self.painter2.setFont(font)
|
|
||||||
self.painter2.setPen(pen)
|
|
||||||
self.painter2.drawText(x, rowpos, line)
|
|
||||||
return (w, h)
|
|
||||||
|
|
||||||
def snoop_image(self, image, image2=None):
|
|
||||||
"""
|
|
||||||
Debugging method to allow images to be viewed.
|
|
||||||
|
|
||||||
``image``
|
|
||||||
An image to save to disk.
|
|
||||||
|
|
||||||
``image2``
|
|
||||||
Defaults to *None*. Another image to save to disk.
|
|
||||||
"""
|
|
||||||
image.save(u'renderer.png', u'png')
|
|
||||||
if image2:
|
|
||||||
image2.save(u'renderer2.png', u'png')
|
|
||||||
|
@ -28,7 +28,8 @@ import logging
|
|||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
from openlp.core.lib import Renderer, ThemeLevel
|
from openlp.core.lib import Renderer, ThemeLevel, ServiceItem
|
||||||
|
from openlp.core.ui import MainDisplay
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -55,6 +56,8 @@ class RenderManager(object):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'Initilisation started')
|
log.debug(u'Initilisation started')
|
||||||
self.screens = screens
|
self.screens = screens
|
||||||
|
self.display = MainDisplay(self, screens, False)
|
||||||
|
self.display.setup()
|
||||||
self.theme_manager = theme_manager
|
self.theme_manager = theme_manager
|
||||||
self.renderer = Renderer()
|
self.renderer = Renderer()
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
self.calculate_default(self.screens.current[u'size'])
|
||||||
@ -63,6 +66,7 @@ class RenderManager(object):
|
|||||||
self.theme_level = u''
|
self.theme_level = u''
|
||||||
self.override_background = None
|
self.override_background = None
|
||||||
self.themedata = None
|
self.themedata = None
|
||||||
|
self.alertTab = None
|
||||||
|
|
||||||
def update_display(self):
|
def update_display(self):
|
||||||
"""
|
"""
|
||||||
@ -70,7 +74,10 @@ class RenderManager(object):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'Update Display')
|
log.debug(u'Update Display')
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
self.calculate_default(self.screens.current[u'size'])
|
||||||
|
self.display = MainDisplay(self, self.screens, False)
|
||||||
|
self.display.setup()
|
||||||
self.renderer.bg_frame = None
|
self.renderer.bg_frame = None
|
||||||
|
self.themedata = None
|
||||||
|
|
||||||
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
|
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
|
||||||
"""
|
"""
|
||||||
@ -96,17 +103,22 @@ class RenderManager(object):
|
|||||||
"""
|
"""
|
||||||
self.service_theme = service_theme
|
self.service_theme = service_theme
|
||||||
|
|
||||||
def set_override_theme(self, theme):
|
def set_override_theme(self, theme, overrideLevels=False):
|
||||||
"""
|
"""
|
||||||
Set the appropriate theme depending on the theme level.
|
Set the appropriate theme depending on the theme level.
|
||||||
|
Called by the service item when building a display frame
|
||||||
|
|
||||||
``theme``
|
``theme``
|
||||||
The name of the song-level theme.
|
The name of the song-level theme. None means the service
|
||||||
|
item wants to use the given value.
|
||||||
"""
|
"""
|
||||||
log.debug(u'set override theme to %s', theme)
|
log.debug(u'set override theme to %s', theme)
|
||||||
if self.theme_level == ThemeLevel.Global:
|
theme_level = self.theme_level
|
||||||
|
if overrideLevels:
|
||||||
|
theme_level = ThemeLevel.Song
|
||||||
|
if theme_level == ThemeLevel.Global:
|
||||||
self.theme = self.global_theme
|
self.theme = self.global_theme
|
||||||
elif self.theme_level == ThemeLevel.Service:
|
elif theme_level == ThemeLevel.Service:
|
||||||
if self.service_theme == u'':
|
if self.service_theme == u'':
|
||||||
self.theme = self.global_theme
|
self.theme = self.global_theme
|
||||||
else:
|
else:
|
||||||
@ -114,20 +126,26 @@ class RenderManager(object):
|
|||||||
else:
|
else:
|
||||||
if theme:
|
if theme:
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
elif self.theme_level == ThemeLevel.Song or \
|
elif theme_level == ThemeLevel.Song or \
|
||||||
self.theme_level == ThemeLevel.Service:
|
theme_level == ThemeLevel.Service:
|
||||||
if self.service_theme == u'':
|
if self.service_theme == u'':
|
||||||
self.theme = self.global_theme
|
self.theme = self.global_theme
|
||||||
else:
|
else:
|
||||||
self.theme = self.service_theme
|
self.theme = self.service_theme
|
||||||
else:
|
else:
|
||||||
self.theme = self.global_theme
|
self.theme = self.global_theme
|
||||||
if self.theme != self.renderer.theme_name or self.themedata is None:
|
if self.theme != self.renderer.theme_name or self.themedata is None \
|
||||||
|
or overrideLevels:
|
||||||
log.debug(u'theme is now %s', self.theme)
|
log.debug(u'theme is now %s', self.theme)
|
||||||
|
if overrideLevels:
|
||||||
|
self.themedata = theme
|
||||||
|
else:
|
||||||
self.themedata = self.theme_manager.getThemeData(self.theme)
|
self.themedata = self.theme_manager.getThemeData(self.theme)
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
self.calculate_default(self.screens.current[u'size'])
|
||||||
self.renderer.set_theme(self.themedata)
|
self.renderer.set_theme(self.themedata)
|
||||||
self.build_text_rectangle(self.themedata)
|
self.build_text_rectangle(self.themedata)
|
||||||
|
self.renderer.set_frame_dest(self.width, self.height)
|
||||||
|
return self.renderer._rect, self.renderer._rect_footer
|
||||||
|
|
||||||
def build_text_rectangle(self, theme):
|
def build_text_rectangle(self, theme):
|
||||||
"""
|
"""
|
||||||
@ -163,13 +181,8 @@ class RenderManager(object):
|
|||||||
The theme to generated a preview for.
|
The theme to generated a preview for.
|
||||||
"""
|
"""
|
||||||
log.debug(u'generate preview')
|
log.debug(u'generate preview')
|
||||||
#set the default image size for previews
|
# set the default image size for previews
|
||||||
self.calculate_default(self.screens.preview[u'size'])
|
self.calculate_default(self.screens.preview[u'size'])
|
||||||
self.renderer.set_theme(themedata)
|
|
||||||
self.build_text_rectangle(themedata)
|
|
||||||
self.renderer.set_frame_dest(self.width, self.height, True)
|
|
||||||
#Reset the real screen size for subsequent render requests
|
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
|
||||||
verse = u'Amazing Grace!\n'\
|
verse = u'Amazing Grace!\n'\
|
||||||
'How sweet the sound\n'\
|
'How sweet the sound\n'\
|
||||||
'To save a wretch like me;\n'\
|
'To save a wretch like me;\n'\
|
||||||
@ -179,12 +192,21 @@ class RenderManager(object):
|
|||||||
footer.append(u'Amazing Grace (John Newton)' )
|
footer.append(u'Amazing Grace (John Newton)' )
|
||||||
footer.append(u'Public Domain')
|
footer.append(u'Public Domain')
|
||||||
footer.append(u'CCLI 123456')
|
footer.append(u'CCLI 123456')
|
||||||
formatted = self.renderer.format_slide(verse, False)
|
# build a service item to generate preview
|
||||||
#Only Render the first slide page returned
|
serviceItem = ServiceItem()
|
||||||
return self.renderer.generate_frame_from_lines(formatted[0],
|
serviceItem.theme = themedata
|
||||||
footer)[u'main']
|
serviceItem.add_from_text(u'', verse, footer)
|
||||||
|
serviceItem.render_manager = self
|
||||||
|
serviceItem.raw_footer = footer
|
||||||
|
serviceItem.render(True)
|
||||||
|
self.display.buildHtml(serviceItem)
|
||||||
|
frame, raw_html = serviceItem.get_rendered_frame(0)
|
||||||
|
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
|
||||||
|
|
||||||
def format_slide(self, words):
|
def format_slide(self, words, line_break):
|
||||||
"""
|
"""
|
||||||
Calculate how much text can fit on a slide.
|
Calculate how much text can fit on a slide.
|
||||||
|
|
||||||
@ -193,22 +215,7 @@ class RenderManager(object):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'format slide')
|
log.debug(u'format slide')
|
||||||
self.build_text_rectangle(self.themedata)
|
self.build_text_rectangle(self.themedata)
|
||||||
return self.renderer.format_slide(words, False)
|
return self.renderer.format_slide(words, line_break)
|
||||||
|
|
||||||
def generate_slide(self, main_text, footer_text):
|
|
||||||
"""
|
|
||||||
Generate the actual slide image.
|
|
||||||
|
|
||||||
``main_text``
|
|
||||||
The text for the main area of the slide.
|
|
||||||
|
|
||||||
``footer_text``
|
|
||||||
The text for the slide footer.
|
|
||||||
"""
|
|
||||||
log.debug(u'generate slide')
|
|
||||||
self.build_text_rectangle(self.themedata)
|
|
||||||
self.renderer.set_frame_dest(self.width, self.height)
|
|
||||||
return self.renderer.generate_frame_from_lines(main_text, footer_text)
|
|
||||||
|
|
||||||
def calculate_default(self, screen):
|
def calculate_default(self, screen):
|
||||||
"""
|
"""
|
||||||
|
@ -35,7 +35,7 @@ import uuid
|
|||||||
|
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
from openlp.core.lib import build_icon, resize_image
|
from openlp.core.lib import build_icon, resize_image, clean_tags, expand_tags
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ class ItemCapabilities(object):
|
|||||||
RequiresMedia = 4
|
RequiresMedia = 4
|
||||||
AllowsLoop = 5
|
AllowsLoop = 5
|
||||||
AllowsAdditions = 6
|
AllowsAdditions = 6
|
||||||
|
NoLineBreaks = 7
|
||||||
|
|
||||||
class ServiceItem(object):
|
class ServiceItem(object):
|
||||||
"""
|
"""
|
||||||
@ -82,6 +83,7 @@ class ServiceItem(object):
|
|||||||
self.items = []
|
self.items = []
|
||||||
self.iconic_representation = None
|
self.iconic_representation = None
|
||||||
self.raw_footer = None
|
self.raw_footer = None
|
||||||
|
self.foot_text = None
|
||||||
self.theme = None
|
self.theme = None
|
||||||
self.service_item_type = None
|
self.service_item_type = None
|
||||||
self._raw_frames = []
|
self._raw_frames = []
|
||||||
@ -91,10 +93,18 @@ class ServiceItem(object):
|
|||||||
self.from_plugin = False
|
self.from_plugin = False
|
||||||
self.capabilities = []
|
self.capabilities = []
|
||||||
self.is_valid = True
|
self.is_valid = True
|
||||||
self.cache = {}
|
|
||||||
self.icon = None
|
self.icon = None
|
||||||
|
self.themedata = None
|
||||||
|
self.main = None
|
||||||
|
self.footer = None
|
||||||
|
self.bg_frame = None
|
||||||
|
|
||||||
def _new_item(self):
|
def _new_item(self):
|
||||||
|
"""
|
||||||
|
Method to set the internal id of the item
|
||||||
|
This is used to compare service items to see if they are
|
||||||
|
the same
|
||||||
|
"""
|
||||||
self._uuid = unicode(uuid.uuid1())
|
self._uuid = unicode(uuid.uuid1())
|
||||||
|
|
||||||
def add_capability(self, capability):
|
def add_capability(self, capability):
|
||||||
@ -126,34 +136,38 @@ class ServiceItem(object):
|
|||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.iconic_representation = build_icon(icon)
|
self.iconic_representation = build_icon(icon)
|
||||||
|
|
||||||
def render(self):
|
def render(self, useOverride=False):
|
||||||
"""
|
"""
|
||||||
The render method is what generates the frames for the screen.
|
The render method is what generates the frames for the screen and
|
||||||
|
obtains the display information from the renderemanager.
|
||||||
|
At this point all the slides are build for the given
|
||||||
|
display size.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Render called')
|
log.debug(u'Render called')
|
||||||
self._display_frames = []
|
self._display_frames = []
|
||||||
self.clear_cache()
|
self.bg_frame = None
|
||||||
|
line_break = True
|
||||||
|
if self.is_capable(ItemCapabilities.NoLineBreaks):
|
||||||
|
line_break = False
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
log.debug(u'Formatting slides')
|
log.debug(u'Formatting slides')
|
||||||
if self.theme is None:
|
theme = None
|
||||||
self.render_manager.set_override_theme(None)
|
if self.theme:
|
||||||
else:
|
theme = self.theme
|
||||||
self.render_manager.set_override_theme(self.theme)
|
self.main, self.footer = \
|
||||||
|
self.render_manager.set_override_theme(theme, useOverride)
|
||||||
|
self.bg_frame = self.render_manager.renderer.bg_frame
|
||||||
|
self.themedata = self.render_manager.renderer._theme
|
||||||
for slide in self._raw_frames:
|
for slide in self._raw_frames:
|
||||||
before = time.time()
|
before = time.time()
|
||||||
formated = self.render_manager.format_slide(slide[u'raw_slide'])
|
formated = self.render_manager \
|
||||||
for format in formated:
|
.format_slide(slide[u'raw_slide'], line_break)
|
||||||
lines = u''
|
for page in formated:
|
||||||
title = u''
|
self._display_frames.append(
|
||||||
for line in format:
|
{u'title': clean_tags(page),
|
||||||
if title == u'':
|
u'text': clean_tags(page.rstrip()),
|
||||||
title = line
|
u'html': expand_tags(page.rstrip()),
|
||||||
lines += line + u'\n'
|
|
||||||
self._display_frames.append({u'title': title,
|
|
||||||
u'text': lines.rstrip(),
|
|
||||||
u'verseTag': slide[u'verseTag'] })
|
u'verseTag': slide[u'verseTag'] })
|
||||||
if len(self._display_frames) in self.cache.keys():
|
|
||||||
del self.cache[len(self._display_frames)]
|
|
||||||
log.log(15, u'Formatting took %4s' % (time.time() - before))
|
log.log(15, u'Formatting took %4s' % (time.time() - before))
|
||||||
elif self.service_item_type == ServiceItemType.Image:
|
elif self.service_item_type == ServiceItemType.Image:
|
||||||
for slide in self._raw_frames:
|
for slide in self._raw_frames:
|
||||||
@ -163,29 +177,14 @@ class ServiceItem(object):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
log.error(u'Invalid value renderer :%s' % self.service_item_type)
|
log.error(u'Invalid value renderer :%s' % self.service_item_type)
|
||||||
|
self.title = clean_tags(self.title)
|
||||||
def render_individual(self, row):
|
self.foot_text = None
|
||||||
"""
|
if self.raw_footer:
|
||||||
Takes an array of text and generates an Image from the
|
for foot in self.raw_footer:
|
||||||
theme. It assumes the text will fit on the screen as it
|
if not self.foot_text:
|
||||||
has generated by the render method above.
|
self.foot_text = foot
|
||||||
"""
|
|
||||||
log.debug(u'render individual')
|
|
||||||
if self.theme is None:
|
|
||||||
self.render_manager.set_override_theme(None)
|
|
||||||
else:
|
else:
|
||||||
self.render_manager.set_override_theme(self.theme)
|
self.foot_text = u'%s<br>%s' % (self.foot_text, foot)
|
||||||
format = self._display_frames[row][u'text'].split(u'\n')
|
|
||||||
if self.cache.get(row):
|
|
||||||
frame = self.cache[row]
|
|
||||||
else:
|
|
||||||
if format[0]:
|
|
||||||
frame = self.render_manager.generate_slide(format,
|
|
||||||
self.raw_footer)
|
|
||||||
else:
|
|
||||||
frame = self.render_manager.generate_slide(format, u'')
|
|
||||||
self.cache[row] = frame
|
|
||||||
return frame
|
|
||||||
|
|
||||||
def add_from_image(self, path, title, image):
|
def add_from_image(self, path, title, image):
|
||||||
"""
|
"""
|
||||||
@ -375,9 +374,9 @@ class ServiceItem(object):
|
|||||||
renders it if required.
|
renders it if required.
|
||||||
"""
|
"""
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
return self.render_individual(row)
|
return None, self._display_frames[row][u'html'].split(u'\n')[0]
|
||||||
else:
|
else:
|
||||||
return {u'main':self._raw_frames[row][u'image'], u'trans':None}
|
return self._raw_frames[row][u'image'], u''
|
||||||
|
|
||||||
def get_frame_title(self, row=0):
|
def get_frame_title(self, row=0):
|
||||||
"""
|
"""
|
||||||
@ -390,9 +389,3 @@ class ServiceItem(object):
|
|||||||
Returns the title of the raw frame
|
Returns the title of the raw frame
|
||||||
"""
|
"""
|
||||||
return self._raw_frames[row][u'path']
|
return self._raw_frames[row][u'path']
|
||||||
|
|
||||||
def clear_cache(self):
|
|
||||||
"""
|
|
||||||
Clear's the service item's cache.
|
|
||||||
"""
|
|
||||||
self.cache = {}
|
|
||||||
|
@ -55,7 +55,6 @@ BLANK_THEME_XML = \
|
|||||||
<proportion>30</proportion>
|
<proportion>30</proportion>
|
||||||
<weight>Normal</weight>
|
<weight>Normal</weight>
|
||||||
<italics>False</italics>
|
<italics>False</italics>
|
||||||
<indentation>0</indentation>
|
|
||||||
<line_adjustment>0</line_adjustment>
|
<line_adjustment>0</line_adjustment>
|
||||||
<location override="False" x="10" y="10" width="1004" height="730"/>
|
<location override="False" x="10" y="10" width="1004" height="730"/>
|
||||||
</font>
|
</font>
|
||||||
@ -65,7 +64,6 @@ BLANK_THEME_XML = \
|
|||||||
<proportion>12</proportion>
|
<proportion>12</proportion>
|
||||||
<weight>Normal</weight>
|
<weight>Normal</weight>
|
||||||
<italics>False</italics>
|
<italics>False</italics>
|
||||||
<indentation>0</indentation>
|
|
||||||
<line_adjustment>0</line_adjustment>
|
<line_adjustment>0</line_adjustment>
|
||||||
<location override="False" x="10" y="730" width="1004" height="38"/>
|
<location override="False" x="10" y="730" width="1004" height="38"/>
|
||||||
</font>
|
</font>
|
||||||
@ -184,7 +182,7 @@ class ThemeXML(object):
|
|||||||
self.child_element(background, u'filename', filename)
|
self.child_element(background, u'filename', filename)
|
||||||
|
|
||||||
def add_font(self, name, color, proportion, override, fonttype=u'main',
|
def add_font(self, name, color, proportion, override, fonttype=u'main',
|
||||||
weight=u'Normal', italics=u'False', indentation=0, line_adjustment=0,
|
weight=u'Normal', italics=u'False', line_adjustment=0,
|
||||||
xpos=0, ypos=0, width=0, height=0):
|
xpos=0, ypos=0, width=0, height=0):
|
||||||
"""
|
"""
|
||||||
Add a Font.
|
Add a Font.
|
||||||
@ -210,9 +208,6 @@ class ThemeXML(object):
|
|||||||
``italics``
|
``italics``
|
||||||
Does the font render to italics Defaults to 0 Normal
|
Does the font render to italics Defaults to 0 Normal
|
||||||
|
|
||||||
``indentation``
|
|
||||||
Number of characters the wrap line is indented
|
|
||||||
|
|
||||||
``xpos``
|
``xpos``
|
||||||
The X position of the text block.
|
The X position of the text block.
|
||||||
|
|
||||||
@ -239,8 +234,6 @@ class ThemeXML(object):
|
|||||||
#Create italics name element
|
#Create italics name element
|
||||||
self.child_element(background, u'italics', italics)
|
self.child_element(background, u'italics', italics)
|
||||||
#Create indentation name element
|
#Create indentation name element
|
||||||
self.child_element(background, u'indentation', unicode(indentation))
|
|
||||||
#Create indentation name element
|
|
||||||
self.child_element(
|
self.child_element(
|
||||||
background, u'line_adjustment', unicode(line_adjustment))
|
background, u'line_adjustment', unicode(line_adjustment))
|
||||||
|
|
||||||
|
@ -27,6 +27,143 @@
|
|||||||
The :mod:`ui` module provides the core user interface for OpenLP
|
The :mod:`ui` module provides the core user interface for OpenLP
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
import enchant
|
||||||
|
enchant_available = True
|
||||||
|
except ImportError:
|
||||||
|
enchant_available = False
|
||||||
|
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
from openlp.core.lib import html_expands, translate, context_menu_action
|
||||||
|
|
||||||
|
class SpellTextEdit(QtGui.QPlainTextEdit):
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
QtGui.QPlainTextEdit.__init__(self, *args)
|
||||||
|
# Default dictionary based on the current locale.
|
||||||
|
if enchant_available:
|
||||||
|
self.dict = enchant.Dict()
|
||||||
|
self.highlighter = Highlighter(self.document())
|
||||||
|
self.highlighter.setDict(self.dict)
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
if event.button() == QtCore.Qt.RightButton:
|
||||||
|
# Rewrite the mouse event to a left button event so the cursor is
|
||||||
|
# moved to the location of the pointer.
|
||||||
|
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, event.pos(),
|
||||||
|
QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
|
||||||
|
QtGui.QPlainTextEdit.mousePressEvent(self, event)
|
||||||
|
|
||||||
|
def contextMenuEvent(self, event):
|
||||||
|
popup_menu = self.createStandardContextMenu()
|
||||||
|
|
||||||
|
# Select the word under the cursor.
|
||||||
|
cursor = self.textCursor()
|
||||||
|
cursor.select(QtGui.QTextCursor.WordUnderCursor)
|
||||||
|
self.setTextCursor(cursor)
|
||||||
|
|
||||||
|
# Check if the selected word is misspelled and offer spelling
|
||||||
|
# suggestions if it is.
|
||||||
|
if enchant_available and self.textCursor().hasSelection():
|
||||||
|
text = unicode(self.textCursor().selectedText())
|
||||||
|
if not self.dict.check(text):
|
||||||
|
spell_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
|
||||||
|
'Spelling Suggestions'))
|
||||||
|
for word in self.dict.suggest(text):
|
||||||
|
action = SpellAction(word, spell_menu)
|
||||||
|
action.correct.connect(self.correctWord)
|
||||||
|
spell_menu.addAction(action)
|
||||||
|
# Only add the spelling suggests to the menu if there are
|
||||||
|
# suggestions.
|
||||||
|
if len(spell_menu.actions()) != 0:
|
||||||
|
popup_menu.insertSeparator(popup_menu.actions()[0])
|
||||||
|
popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)
|
||||||
|
tag_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
|
||||||
|
'Formatting Tags'))
|
||||||
|
for html in html_expands:
|
||||||
|
action = SpellAction( html[u'desc'], tag_menu)
|
||||||
|
action.correct.connect(self.htmlTag)
|
||||||
|
tag_menu.addAction(action)
|
||||||
|
popup_menu.insertSeparator(popup_menu.actions()[0])
|
||||||
|
popup_menu.insertMenu(popup_menu.actions()[0], tag_menu)
|
||||||
|
|
||||||
|
popup_menu.exec_(event.globalPos())
|
||||||
|
|
||||||
|
def correctWord(self, word):
|
||||||
|
'''
|
||||||
|
Replaces the selected text with word.
|
||||||
|
'''
|
||||||
|
cursor = self.textCursor()
|
||||||
|
cursor.beginEditBlock()
|
||||||
|
|
||||||
|
cursor.removeSelectedText()
|
||||||
|
cursor.insertText(word)
|
||||||
|
|
||||||
|
cursor.endEditBlock()
|
||||||
|
|
||||||
|
def htmlTag(self, tag):
|
||||||
|
'''
|
||||||
|
Replaces the selected text with word.
|
||||||
|
'''
|
||||||
|
for html in html_expands:
|
||||||
|
if tag == html[u'desc']:
|
||||||
|
cursor = self.textCursor()
|
||||||
|
if self.textCursor().hasSelection():
|
||||||
|
text = cursor.selectedText()
|
||||||
|
cursor.beginEditBlock()
|
||||||
|
cursor.removeSelectedText()
|
||||||
|
cursor.insertText(html[u'start tag'])
|
||||||
|
cursor.insertText(text)
|
||||||
|
cursor.insertText(html[u'end tag'])
|
||||||
|
cursor.endEditBlock()
|
||||||
|
else:
|
||||||
|
cursor = self.textCursor()
|
||||||
|
cursor.insertText(html[u'start tag'])
|
||||||
|
cursor.insertText(html[u'end tag'])
|
||||||
|
|
||||||
|
class Highlighter(QtGui.QSyntaxHighlighter):
|
||||||
|
|
||||||
|
WORDS = u'(?iu)[\w\']+'
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
QtGui.QSyntaxHighlighter.__init__(self, *args)
|
||||||
|
|
||||||
|
self.dict = None
|
||||||
|
|
||||||
|
def setDict(self, dict):
|
||||||
|
self.dict = dict
|
||||||
|
|
||||||
|
def highlightBlock(self, text):
|
||||||
|
if not self.dict:
|
||||||
|
return
|
||||||
|
|
||||||
|
text = unicode(text)
|
||||||
|
|
||||||
|
format = QtGui.QTextCharFormat()
|
||||||
|
format.setUnderlineColor(QtCore.Qt.red)
|
||||||
|
format.setUnderlineStyle(QtGui.QTextCharFormat.SpellCheckUnderline)
|
||||||
|
|
||||||
|
for word_object in re.finditer(self.WORDS, text):
|
||||||
|
if not self.dict.check(word_object.group()):
|
||||||
|
self.setFormat(word_object.start(),
|
||||||
|
word_object.end() - word_object.start(), format)
|
||||||
|
|
||||||
|
class SpellAction(QtGui.QAction):
|
||||||
|
'''
|
||||||
|
A special QAction that returns the text in a signal.
|
||||||
|
'''
|
||||||
|
correct = QtCore.pyqtSignal(unicode)
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
QtGui.QAction.__init__(self, *args)
|
||||||
|
|
||||||
|
self.triggered.connect(lambda x: self.correct.emit(
|
||||||
|
unicode(self.text())))
|
||||||
|
|
||||||
class HideMode(object):
|
class HideMode(object):
|
||||||
"""
|
"""
|
||||||
This is basically an enumeration class which specifies the mode of a Bible.
|
This is basically an enumeration class which specifies the mode of a Bible.
|
||||||
@ -37,13 +174,11 @@ class HideMode(object):
|
|||||||
Theme = 2
|
Theme = 2
|
||||||
Screen = 3
|
Screen = 3
|
||||||
|
|
||||||
|
from maindisplay import MainDisplay
|
||||||
from slidecontroller import HideMode
|
from slidecontroller import HideMode
|
||||||
from servicenoteform import ServiceNoteForm
|
from servicenoteform import ServiceNoteForm
|
||||||
from serviceitemeditform import ServiceItemEditForm
|
from serviceitemeditform import ServiceItemEditForm
|
||||||
from screen import ScreenList
|
from screen import ScreenList
|
||||||
from maindisplay import MainDisplay
|
|
||||||
from maindisplay import VideoDisplay
|
|
||||||
from maindisplay import DisplayManager
|
|
||||||
from amendthemeform import AmendThemeForm
|
from amendthemeform import AmendThemeForm
|
||||||
from slidecontroller import SlideController
|
from slidecontroller import SlideController
|
||||||
from splashscreen import SplashScreen
|
from splashscreen import SplashScreen
|
||||||
@ -56,8 +191,7 @@ from settingsform import SettingsForm
|
|||||||
from mediadockmanager import MediaDockManager
|
from mediadockmanager import MediaDockManager
|
||||||
from servicemanager import ServiceManager
|
from servicemanager import ServiceManager
|
||||||
from thememanager import ThemeManager
|
from thememanager import ThemeManager
|
||||||
from mainwindow import MainWindow
|
|
||||||
|
|
||||||
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainWindow',
|
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm',
|
||||||
'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
|
'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
|
||||||
'AmendThemeForm', 'MediaDockManager', 'ServiceItemEditForm']
|
'AmendThemeForm', 'MediaDockManager', 'ServiceItemEditForm']
|
||||||
|
@ -68,17 +68,6 @@ class Ui_AmendThemeDialog(object):
|
|||||||
self.backgroundLayout.setMargin(8)
|
self.backgroundLayout.setMargin(8)
|
||||||
self.backgroundLayout.setSpacing(8)
|
self.backgroundLayout.setSpacing(8)
|
||||||
self.backgroundLayout.setObjectName(u'backgroundLayout')
|
self.backgroundLayout.setObjectName(u'backgroundLayout')
|
||||||
self.backgroundLabel = QtGui.QLabel(self.backgroundTab)
|
|
||||||
self.backgroundLabel.setObjectName(u'backgroundLabel')
|
|
||||||
self.backgroundLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
|
|
||||||
self.backgroundLabel)
|
|
||||||
self.backgroundComboBox = QtGui.QComboBox(self.backgroundTab)
|
|
||||||
self.backgroundComboBox.setObjectName(u'backgroundComboBox')
|
|
||||||
self.backgroundLabel.setBuddy(self.backgroundComboBox)
|
|
||||||
self.backgroundComboBox.addItem(QtCore.QString())
|
|
||||||
self.backgroundComboBox.addItem(QtCore.QString())
|
|
||||||
self.backgroundLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
|
|
||||||
self.backgroundComboBox)
|
|
||||||
self.backgroundTypeLabel = QtGui.QLabel(self.backgroundTab)
|
self.backgroundTypeLabel = QtGui.QLabel(self.backgroundTab)
|
||||||
self.backgroundTypeLabel.setObjectName(u'backgroundTypeLabel')
|
self.backgroundTypeLabel.setObjectName(u'backgroundTypeLabel')
|
||||||
self.backgroundLayout.setWidget(1, QtGui.QFormLayout.LabelRole,
|
self.backgroundLayout.setWidget(1, QtGui.QFormLayout.LabelRole,
|
||||||
@ -216,17 +205,6 @@ class Ui_AmendThemeDialog(object):
|
|||||||
self.fontMainLineAdjustmentSpinBox.setMinimum(-99)
|
self.fontMainLineAdjustmentSpinBox.setMinimum(-99)
|
||||||
self.mainFontLayout.setWidget(4, QtGui.QFormLayout.FieldRole,
|
self.mainFontLayout.setWidget(4, QtGui.QFormLayout.FieldRole,
|
||||||
self.fontMainLineAdjustmentSpinBox)
|
self.fontMainLineAdjustmentSpinBox)
|
||||||
self.fontMainWrapIndentationLabel = QtGui.QLabel(self.fontMainGroupBox)
|
|
||||||
self.fontMainWrapIndentationLabel.setObjectName(
|
|
||||||
u'fontMainWrapIndentationLabel')
|
|
||||||
self.mainFontLayout.setWidget(5, QtGui.QFormLayout.LabelRole,
|
|
||||||
self.fontMainWrapIndentationLabel)
|
|
||||||
self.fontMainLineSpacingSpinBox = QtGui.QSpinBox(self.fontMainGroupBox)
|
|
||||||
self.fontMainLineSpacingSpinBox.setObjectName(
|
|
||||||
u'fontMainLineSpacingSpinBox')
|
|
||||||
self.fontMainLineSpacingSpinBox.setMaximum(10)
|
|
||||||
self.mainFontLayout.setWidget(5, QtGui.QFormLayout.FieldRole,
|
|
||||||
self.fontMainLineSpacingSpinBox)
|
|
||||||
self.fontMainLinesPageLabel = QtGui.QLabel(self.fontMainGroupBox)
|
self.fontMainLinesPageLabel = QtGui.QLabel(self.fontMainGroupBox)
|
||||||
self.fontMainLinesPageLabel.setObjectName(u'fontMainLinesPageLabel')
|
self.fontMainLinesPageLabel.setObjectName(u'fontMainLinesPageLabel')
|
||||||
self.mainFontLayout.addRow(self.fontMainLinesPageLabel)
|
self.mainFontLayout.addRow(self.fontMainLinesPageLabel)
|
||||||
@ -661,12 +639,6 @@ class Ui_AmendThemeDialog(object):
|
|||||||
translate('OpenLP.AmendThemeForm', 'Theme Maintenance'))
|
translate('OpenLP.AmendThemeForm', 'Theme Maintenance'))
|
||||||
self.themeNameLabel.setText(
|
self.themeNameLabel.setText(
|
||||||
translate('OpenLP.AmendThemeForm', 'Theme &name:'))
|
translate('OpenLP.AmendThemeForm', 'Theme &name:'))
|
||||||
self.backgroundLabel.setText(
|
|
||||||
translate('OpenLP.AmendThemeForm', '&Visibility:'))
|
|
||||||
self.backgroundComboBox.setItemText(0,
|
|
||||||
translate('OpenLP.AmendThemeForm', 'Opaque'))
|
|
||||||
self.backgroundComboBox.setItemText(1,
|
|
||||||
translate('OpenLP.AmendThemeForm', 'Transparent'))
|
|
||||||
self.backgroundTypeLabel.setText(
|
self.backgroundTypeLabel.setText(
|
||||||
translate('OpenLP.AmendThemeForm', 'Type:'))
|
translate('OpenLP.AmendThemeForm', 'Type:'))
|
||||||
self.backgroundTypeComboBox.setItemText(0,
|
self.backgroundTypeComboBox.setItemText(0,
|
||||||
@ -700,8 +672,6 @@ class Ui_AmendThemeDialog(object):
|
|||||||
translate('OpenLP.AmendThemeForm', 'Size:'))
|
translate('OpenLP.AmendThemeForm', 'Size:'))
|
||||||
self.fontMainSizeSpinBox.setSuffix(
|
self.fontMainSizeSpinBox.setSuffix(
|
||||||
translate('OpenLP.AmendThemeForm', 'pt'))
|
translate('OpenLP.AmendThemeForm', 'pt'))
|
||||||
self.fontMainWrapIndentationLabel.setText(
|
|
||||||
translate('OpenLP.AmendThemeForm', 'Wrap indentation:'))
|
|
||||||
self.fontMainWrapLineAdjustmentLabel.setText(
|
self.fontMainWrapLineAdjustmentLabel.setText(
|
||||||
translate('OpenLP.AmendThemeForm', 'Adjust line spacing:'))
|
translate('OpenLP.AmendThemeForm', 'Adjust line spacing:'))
|
||||||
self.fontMainWeightComboBox.setItemText(0,
|
self.fontMainWeightComboBox.setItemText(0,
|
||||||
|
@ -50,7 +50,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.path = None
|
self.path = None
|
||||||
self.theme = ThemeXML()
|
self.theme = ThemeXML()
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
# define signals
|
|
||||||
# Buttons
|
# Buttons
|
||||||
QtCore.QObject.connect(self.color1PushButton,
|
QtCore.QObject.connect(self.color1PushButton,
|
||||||
QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked)
|
QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked)
|
||||||
@ -68,8 +67,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
QtCore.QObject.connect(self.imageToolButton,
|
QtCore.QObject.connect(self.imageToolButton,
|
||||||
QtCore.SIGNAL(u'clicked()'), self.onImageToolButtonClicked)
|
QtCore.SIGNAL(u'clicked()'), self.onImageToolButtonClicked)
|
||||||
# Combo boxes
|
# Combo boxes
|
||||||
QtCore.QObject.connect(self.backgroundComboBox,
|
|
||||||
QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected)
|
|
||||||
QtCore.QObject.connect(self.backgroundTypeComboBox,
|
QtCore.QObject.connect(self.backgroundTypeComboBox,
|
||||||
QtCore.SIGNAL(u'activated(int)'),
|
QtCore.SIGNAL(u'activated(int)'),
|
||||||
self.onBackgroundTypeComboBoxSelected)
|
self.onBackgroundTypeComboBoxSelected)
|
||||||
@ -109,9 +106,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
QtCore.QObject.connect(self.fontMainLineAdjustmentSpinBox,
|
QtCore.QObject.connect(self.fontMainLineAdjustmentSpinBox,
|
||||||
QtCore.SIGNAL(u'editingFinished()'),
|
QtCore.SIGNAL(u'editingFinished()'),
|
||||||
self.onFontMainLineAdjustmentSpinBoxChanged)
|
self.onFontMainLineAdjustmentSpinBoxChanged)
|
||||||
QtCore.QObject.connect(self.fontMainLineSpacingSpinBox,
|
|
||||||
QtCore.SIGNAL(u'editingFinished()'),
|
|
||||||
self.onFontMainLineSpacingSpinBoxChanged)
|
|
||||||
QtCore.QObject.connect(self.fontFooterXSpinBox,
|
QtCore.QObject.connect(self.fontFooterXSpinBox,
|
||||||
QtCore.SIGNAL(u'editingFinished()'),
|
QtCore.SIGNAL(u'editingFinished()'),
|
||||||
self.onFontFooterXSpinBoxChanged)
|
self.onFontFooterXSpinBoxChanged)
|
||||||
@ -151,9 +145,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
new_theme.new_document(theme_name)
|
new_theme.new_document(theme_name)
|
||||||
save_from = None
|
save_from = None
|
||||||
save_to = None
|
save_to = None
|
||||||
if self.theme.background_mode == u'transparent':
|
|
||||||
new_theme.add_background_transparent()
|
|
||||||
else:
|
|
||||||
if self.theme.background_type == u'solid':
|
if self.theme.background_type == u'solid':
|
||||||
new_theme.add_background_solid(
|
new_theme.add_background_solid(
|
||||||
unicode(self.theme.background_color))
|
unicode(self.theme.background_color))
|
||||||
@ -174,7 +165,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
unicode(self.theme.font_main_override), u'main',
|
unicode(self.theme.font_main_override), u'main',
|
||||||
unicode(self.theme.font_main_weight),
|
unicode(self.theme.font_main_weight),
|
||||||
unicode(self.theme.font_main_italics),
|
unicode(self.theme.font_main_italics),
|
||||||
unicode(self.theme.font_main_indentation),
|
|
||||||
unicode(self.theme.font_main_line_adjustment),
|
unicode(self.theme.font_main_line_adjustment),
|
||||||
unicode(self.theme.font_main_x),
|
unicode(self.theme.font_main_x),
|
||||||
unicode(self.theme.font_main_y),
|
unicode(self.theme.font_main_y),
|
||||||
@ -186,7 +176,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
unicode(self.theme.font_footer_override), u'footer',
|
unicode(self.theme.font_footer_override), u'footer',
|
||||||
unicode(self.theme.font_footer_weight),
|
unicode(self.theme.font_footer_weight),
|
||||||
unicode(self.theme.font_footer_italics),
|
unicode(self.theme.font_footer_italics),
|
||||||
0, # indentation
|
|
||||||
0, # line adjustment
|
0, # line adjustment
|
||||||
unicode(self.theme.font_footer_x),
|
unicode(self.theme.font_footer_x),
|
||||||
unicode(self.theme.font_footer_y),
|
unicode(self.theme.font_footer_y),
|
||||||
@ -230,7 +219,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
#
|
#
|
||||||
#Main Font Tab
|
# Main Font Tab
|
||||||
#
|
#
|
||||||
def onFontMainComboBoxSelected(self):
|
def onFontMainComboBoxSelected(self):
|
||||||
self.theme.font_main_name = self.fontMainComboBox.currentFont().family()
|
self.theme.font_main_name = self.fontMainComboBox.currentFont().family()
|
||||||
@ -283,8 +272,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.fontMainHeightSpinBox.setValue(self.theme.font_main_height)
|
self.fontMainHeightSpinBox.setValue(self.theme.font_main_height)
|
||||||
self.fontMainLineAdjustmentSpinBox.setValue(
|
self.fontMainLineAdjustmentSpinBox.setValue(
|
||||||
self.theme.font_main_line_adjustment)
|
self.theme.font_main_line_adjustment)
|
||||||
self.fontMainLineSpacingSpinBox.setValue(
|
|
||||||
self.theme.font_main_indentation)
|
|
||||||
self.stateChanging(self.theme)
|
self.stateChanging(self.theme)
|
||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
@ -310,20 +297,13 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.fontMainLineAdjustmentSpinBox.value()
|
self.fontMainLineAdjustmentSpinBox.value()
|
||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
def onFontMainLineSpacingSpinBoxChanged(self):
|
|
||||||
if self.theme.font_main_indentation != \
|
|
||||||
self.fontMainLineSpacingSpinBox.value():
|
|
||||||
self.theme.font_main_indentation = \
|
|
||||||
self.fontMainLineSpacingSpinBox.value()
|
|
||||||
self.previewTheme()
|
|
||||||
|
|
||||||
def onFontMainHeightSpinBoxChanged(self):
|
def onFontMainHeightSpinBoxChanged(self):
|
||||||
if self.theme.font_main_height != self.fontMainHeightSpinBox.value():
|
if self.theme.font_main_height != self.fontMainHeightSpinBox.value():
|
||||||
self.theme.font_main_height = self.fontMainHeightSpinBox.value()
|
self.theme.font_main_height = self.fontMainHeightSpinBox.value()
|
||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
#
|
#
|
||||||
#Footer Font Tab
|
# Footer Font Tab
|
||||||
#
|
#
|
||||||
def onFontFooterComboBoxSelected(self):
|
def onFontFooterComboBoxSelected(self):
|
||||||
self.theme.font_footer_name = \
|
self.theme.font_footer_name = \
|
||||||
@ -404,20 +384,12 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
#
|
#
|
||||||
#Background Tab
|
# Background Tab
|
||||||
#
|
#
|
||||||
def onGradientComboBoxSelected(self, currentIndex):
|
def onGradientComboBoxSelected(self, currentIndex):
|
||||||
self.setBackground(self.backgroundTypeComboBox.currentIndex(),
|
self.setBackground(self.backgroundTypeComboBox.currentIndex(),
|
||||||
currentIndex)
|
currentIndex)
|
||||||
|
|
||||||
def onBackgroundComboBoxSelected(self, currentIndex):
|
|
||||||
if currentIndex == 0: # Opaque
|
|
||||||
self.theme.background_mode = u'opaque'
|
|
||||||
else:
|
|
||||||
self.theme.background_mode = u'transparent'
|
|
||||||
self.stateChanging(self.theme)
|
|
||||||
self.previewTheme()
|
|
||||||
|
|
||||||
def onBackgroundTypeComboBoxSelected(self, currentIndex):
|
def onBackgroundTypeComboBoxSelected(self, currentIndex):
|
||||||
self.setBackground(currentIndex, self.gradientComboBox.currentIndex())
|
self.setBackground(currentIndex, self.gradientComboBox.currentIndex())
|
||||||
|
|
||||||
@ -472,7 +444,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
#
|
#
|
||||||
#Other Tab
|
# Other Tab
|
||||||
#
|
#
|
||||||
def onOutlineCheckBoxChanged(self, value):
|
def onOutlineCheckBoxChanged(self, value):
|
||||||
if value == 2: # checked
|
if value == 2: # checked
|
||||||
@ -537,16 +509,12 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.previewTheme()
|
self.previewTheme()
|
||||||
|
|
||||||
#
|
#
|
||||||
#Local Methods
|
# Local Methods
|
||||||
#
|
#
|
||||||
def paintUi(self, theme):
|
def paintUi(self, theme):
|
||||||
self.stateChanging(theme)
|
self.stateChanging(theme)
|
||||||
self.themeNameEdit.setText(self.theme.theme_name)
|
self.themeNameEdit.setText(self.theme.theme_name)
|
||||||
# Background Tab
|
# Background Tab
|
||||||
if self.theme.background_mode == u'opaque':
|
|
||||||
self.backgroundComboBox.setCurrentIndex(0)
|
|
||||||
else:
|
|
||||||
self.backgroundComboBox.setCurrentIndex(1)
|
|
||||||
self.imageLineEdit.setText(u'')
|
self.imageLineEdit.setText(u'')
|
||||||
if theme.background_type == u'solid':
|
if theme.background_type == u'solid':
|
||||||
self.backgroundTypeComboBox.setCurrentIndex(0)
|
self.backgroundTypeComboBox.setCurrentIndex(0)
|
||||||
@ -576,8 +544,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.fontMainWeightComboBox.setCurrentIndex(2)
|
self.fontMainWeightComboBox.setCurrentIndex(2)
|
||||||
else:
|
else:
|
||||||
self.fontMainWeightComboBox.setCurrentIndex(3)
|
self.fontMainWeightComboBox.setCurrentIndex(3)
|
||||||
self.fontMainLineSpacingSpinBox.setValue(
|
|
||||||
self.theme.font_main_indentation)
|
|
||||||
self.fontMainXSpinBox.setValue(self.theme.font_main_x)
|
self.fontMainXSpinBox.setValue(self.theme.font_main_x)
|
||||||
self.fontMainYSpinBox.setValue(self.theme.font_main_y)
|
self.fontMainYSpinBox.setValue(self.theme.font_main_y)
|
||||||
self.fontMainWidthSpinBox.setValue(self.theme.font_main_width)
|
self.fontMainWidthSpinBox.setValue(self.theme.font_main_width)
|
||||||
@ -641,19 +607,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||||||
self.verticalComboBox.setCurrentIndex(self.theme.display_verticalAlign)
|
self.verticalComboBox.setCurrentIndex(self.theme.display_verticalAlign)
|
||||||
|
|
||||||
def stateChanging(self, theme):
|
def stateChanging(self, theme):
|
||||||
if theme.background_mode == u'transparent':
|
|
||||||
self.color1Label.setVisible(False)
|
|
||||||
self.color1PushButton.setVisible(False)
|
|
||||||
self.color2Label.setVisible(False)
|
|
||||||
self.color2PushButton.setVisible(False)
|
|
||||||
self.imageLabel.setVisible(False)
|
|
||||||
self.imageLineEdit.setVisible(False)
|
|
||||||
self.imageFilenameWidget.setVisible(False)
|
|
||||||
self.gradientLabel.setVisible(False)
|
|
||||||
self.gradientComboBox.setVisible(False)
|
|
||||||
self.backgroundTypeComboBox.setVisible(False)
|
|
||||||
self.backgroundTypeLabel.setVisible(False)
|
|
||||||
else:
|
|
||||||
self.backgroundTypeComboBox.setVisible(True)
|
self.backgroundTypeComboBox.setVisible(True)
|
||||||
self.backgroundTypeLabel.setVisible(True)
|
self.backgroundTypeLabel.setVisible(True)
|
||||||
if theme.background_type == u'solid':
|
if theme.background_type == u'solid':
|
||||||
|
@ -390,7 +390,6 @@ class GeneralTab(SettingsTab):
|
|||||||
unicode(self.screens.current[u'size'].width()))
|
unicode(self.screens.current[u'size'].width()))
|
||||||
self.overrideCheckBox.setChecked(settings.value(u'override position',
|
self.overrideCheckBox.setChecked(settings.value(u'override position',
|
||||||
QtCore.QVariant(False)).toBool())
|
QtCore.QVariant(False)).toBool())
|
||||||
if self.overrideCheckBox.isChecked():
|
|
||||||
self.customXValueEdit.setText(settings.value(u'x position',
|
self.customXValueEdit.setText(settings.value(u'x position',
|
||||||
QtCore.QVariant(self.screens.current[u'size'].x())).toString())
|
QtCore.QVariant(self.screens.current[u'size'].x())).toString())
|
||||||
self.customYValueEdit.setText(settings.value(u'y position',
|
self.customYValueEdit.setText(settings.value(u'y position',
|
||||||
@ -401,15 +400,6 @@ class GeneralTab(SettingsTab):
|
|||||||
self.customWidthValueEdit.setText(
|
self.customWidthValueEdit.setText(
|
||||||
settings.value(u'width', QtCore.QVariant(
|
settings.value(u'width', QtCore.QVariant(
|
||||||
self.screens.current[u'size'].width())).toString())
|
self.screens.current[u'size'].width())).toString())
|
||||||
else:
|
|
||||||
self.customXValueEdit.setText(
|
|
||||||
unicode(self.screens.current[u'size'].x()))
|
|
||||||
self.customYValueEdit.setText(
|
|
||||||
unicode(self.screens.current[u'size'].y()))
|
|
||||||
self.customHeightValueEdit.setText(
|
|
||||||
unicode(self.screens.current[u'size'].height()))
|
|
||||||
self.customWidthValueEdit.setText(
|
|
||||||
unicode(self.screens.current[u'size'].width()))
|
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked())
|
self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked())
|
||||||
self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked())
|
self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked())
|
||||||
@ -438,8 +428,6 @@ class GeneralTab(SettingsTab):
|
|||||||
QtCore.QVariant(self.autoPreviewCheckBox.isChecked()))
|
QtCore.QVariant(self.autoPreviewCheckBox.isChecked()))
|
||||||
settings.setValue(u'loop delay',
|
settings.setValue(u'loop delay',
|
||||||
QtCore.QVariant(self.timeoutSpinBox.value()))
|
QtCore.QVariant(self.timeoutSpinBox.value()))
|
||||||
Receiver.send_message(u'slidecontroller_live_spin_delay',
|
|
||||||
self.timeoutSpinBox.value())
|
|
||||||
settings.setValue(u'ccli number',
|
settings.setValue(u'ccli number',
|
||||||
QtCore.QVariant(self.numberEdit.displayText()))
|
QtCore.QVariant(self.numberEdit.displayText()))
|
||||||
settings.setValue(u'songselect username',
|
settings.setValue(u'songselect username',
|
||||||
@ -459,17 +447,18 @@ class GeneralTab(SettingsTab):
|
|||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
self.screens.display = self.displayOnMonitorCheck.isChecked()
|
self.screens.display = self.displayOnMonitorCheck.isChecked()
|
||||||
# Monitor Number has changed.
|
# Monitor Number has changed.
|
||||||
|
postUpdate = False
|
||||||
if self.screens.monitor_number != self.monitorNumber:
|
if self.screens.monitor_number != self.monitorNumber:
|
||||||
self.screens.monitor_number = self.monitorNumber
|
self.screens.monitor_number = self.monitorNumber
|
||||||
self.screens.set_current_display(self.monitorNumber)
|
self.screens.set_current_display(self.monitorNumber)
|
||||||
Receiver.send_message(u'config_screen_changed')
|
postUpdate = True
|
||||||
Receiver.send_message(u'config_updated')
|
|
||||||
# On save update the screens as well
|
# On save update the screens as well
|
||||||
self.postSetUp()
|
self.postSetUp(postUpdate)
|
||||||
|
|
||||||
def postSetUp(self):
|
def postSetUp(self, postUpdate=False):
|
||||||
"""
|
"""
|
||||||
Apply settings after settings tab has loaded
|
Apply settings after settings tab has loaded and most of the
|
||||||
|
system so must be delayed
|
||||||
"""
|
"""
|
||||||
Receiver.send_message(u'slidecontroller_live_spin_delay',
|
Receiver.send_message(u'slidecontroller_live_spin_delay',
|
||||||
self.timeoutSpinBox.value())
|
self.timeoutSpinBox.value())
|
||||||
@ -482,10 +471,13 @@ class GeneralTab(SettingsTab):
|
|||||||
int(self.customHeightValueEdit.text()))
|
int(self.customHeightValueEdit.text()))
|
||||||
if self.overrideCheckBox.isChecked():
|
if self.overrideCheckBox.isChecked():
|
||||||
self.screens.set_override_display()
|
self.screens.set_override_display()
|
||||||
Receiver.send_message(u'config_screen_changed')
|
|
||||||
else:
|
else:
|
||||||
self.screens.reset_current_display()
|
self.screens.reset_current_display()
|
||||||
|
# Order is important so be careful if you change
|
||||||
|
if self.overrideChanged or postUpdate:
|
||||||
Receiver.send_message(u'config_screen_changed')
|
Receiver.send_message(u'config_screen_changed')
|
||||||
|
Receiver.send_message(u'config_updated')
|
||||||
|
self.overrideChanged = False
|
||||||
|
|
||||||
def onOverrideCheckBoxToggled(self, checked):
|
def onOverrideCheckBoxToggled(self, checked):
|
||||||
"""
|
"""
|
||||||
|
@ -26,149 +26,46 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui, QtWebKit
|
from PyQt4 import QtCore, QtGui, QtWebKit
|
||||||
from PyQt4.phonon import Phonon
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.lib import Receiver, resize_image
|
from openlp.core.lib import Receiver, resize_image, build_html, ServiceItem, \
|
||||||
|
image_to_byte
|
||||||
from openlp.core.ui import HideMode
|
from openlp.core.ui import HideMode
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
|
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
|
||||||
HTMLVIDEO = u"""<html>
|
|
||||||
<head>
|
|
||||||
<style>
|
|
||||||
*{
|
|
||||||
margin: 0;
|
|
||||||
padding:0
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="text/javascript" charset="utf-8">
|
|
||||||
var video;
|
|
||||||
var bodyLoaded = function(){
|
|
||||||
video = document.getElementById("video");
|
|
||||||
video.volume = 0;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body id="body" onload="bodyLoaded();">
|
|
||||||
<video id="video" src="%s" autoplay="autoplay" loop="loop"
|
|
||||||
width="%s" height="%s" autobuffer="autobuffer" preload="preload" />
|
|
||||||
</body></html>
|
|
||||||
"""
|
|
||||||
|
|
||||||
class DisplayManager(QtGui.QWidget):
|
|
||||||
"""
|
|
||||||
Wrapper class to hold the display widgets.
|
|
||||||
I will provide API's in future to access the screens allow for
|
|
||||||
extra displays to be added.
|
|
||||||
RenderManager is poked in by MainWindow
|
|
||||||
"""
|
|
||||||
def __init__(self, screens):
|
|
||||||
QtGui.QWidget.__init__(self)
|
|
||||||
self.screens = screens
|
|
||||||
self.videoDisplay = VideoDisplay(self, screens)
|
|
||||||
self.audioPlayer = AudioPlayer(self)
|
|
||||||
self.mainDisplay = MainDisplay(self, screens)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'videodisplay_start'), self.onStartVideo)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'videodisplay_stop'), self.onStopVideo)
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
self.videoDisplay.setup()
|
|
||||||
self.mainDisplay.setup()
|
|
||||||
|
|
||||||
def hideDisplay(self, message):
|
|
||||||
"""
|
|
||||||
Hide the output displays
|
|
||||||
"""
|
|
||||||
self.videoDisplay.mediaHide(message)
|
|
||||||
self.mainDisplay.hideDisplay(message)
|
|
||||||
|
|
||||||
def showDisplay(self):
|
|
||||||
"""
|
|
||||||
Hide the output displays
|
|
||||||
"""
|
|
||||||
self.videoDisplay.mediaShow()
|
|
||||||
self.mainDisplay.showDisplay()
|
|
||||||
|
|
||||||
def addAlert(self, alertMessage, location):
|
|
||||||
"""
|
|
||||||
Handles the addition of an Alert Message to the Displays
|
|
||||||
"""
|
|
||||||
self.mainDisplay.addAlert(alertMessage, location)
|
|
||||||
|
|
||||||
def displayImageWithText(self, frame):
|
|
||||||
"""
|
|
||||||
Handles the addition of a background Image to the displays
|
|
||||||
"""
|
|
||||||
self.mainDisplay.addImageWithText(frame)
|
|
||||||
|
|
||||||
def displayImage(self, frame):
|
|
||||||
"""
|
|
||||||
Handles the addition of a background Image to the displays
|
|
||||||
"""
|
|
||||||
self.mainDisplay.displayImage(frame)
|
|
||||||
|
|
||||||
def displayVideo(self, path):
|
|
||||||
"""
|
|
||||||
Handles the addition of a background Video to the displays
|
|
||||||
"""
|
|
||||||
self.mainDisplay.displayVideo(path)
|
|
||||||
|
|
||||||
def onStartVideo(self, item):
|
|
||||||
"""
|
|
||||||
Handles the Starting of a Video and Display Management
|
|
||||||
"""
|
|
||||||
self.videoDisplay.setVisible(True)
|
|
||||||
self.mainDisplay.setVisible(False)
|
|
||||||
self.videoDisplay.onMediaQueue(item)
|
|
||||||
|
|
||||||
def onStopVideo(self):
|
|
||||||
"""
|
|
||||||
Handles the Stopping of a Video and Display Management
|
|
||||||
"""
|
|
||||||
self.mainDisplay.setVisible(True)
|
|
||||||
self.videoDisplay.setVisible(False)
|
|
||||||
self.videoDisplay.onMediaStop()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""
|
|
||||||
Handles the closure of the displays
|
|
||||||
"""
|
|
||||||
self.videoDisplay.close()
|
|
||||||
self.audioPlayer.close()
|
|
||||||
self.mainDisplay.close()
|
|
||||||
|
|
||||||
|
|
||||||
class DisplayWidget(QtGui.QGraphicsView):
|
class DisplayWidget(QtGui.QGraphicsView):
|
||||||
"""
|
"""
|
||||||
Customised version of QTableWidget which can respond to keyboard
|
Customised version of QTableWidget which can respond to keyboard
|
||||||
events.
|
events.
|
||||||
"""
|
"""
|
||||||
log.info(u'MainDisplay loaded')
|
log.info(u'Display Widget loaded')
|
||||||
|
|
||||||
def __init__(self, parent=None, name=None, primary=False):
|
def __init__(self, live, parent=None):
|
||||||
QtGui.QWidget.__init__(self, None)
|
QtGui.QGraphicsView.__init__(self)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.primary = primary
|
self.live = live
|
||||||
self.hotkey_map = {
|
self.hotkey_map = {
|
||||||
QtCore.Qt.Key_Return: 'servicemanager_next_item',
|
QtCore.Qt.Key_Return: 'servicemanager_next_item',
|
||||||
QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop',
|
QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop',
|
||||||
QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop',
|
QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop',
|
||||||
QtCore.Qt.Key_0: 'servicemanager_next_item',
|
QtCore.Qt.Key_0: 'servicemanager_next_item',
|
||||||
QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'}
|
QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'}
|
||||||
|
self.setStyleSheet(u'border: none;')
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
|
"""
|
||||||
|
Handle key events from display screen
|
||||||
|
"""
|
||||||
|
# Key events only needed for live
|
||||||
|
if not self.live:
|
||||||
|
return
|
||||||
if isinstance(event, QtGui.QKeyEvent):
|
if isinstance(event, QtGui.QKeyEvent):
|
||||||
#here accept the event and do something
|
# Here accept the event and do something
|
||||||
if event.key() == QtCore.Qt.Key_Up:
|
if event.key() == QtCore.Qt.Key_Up:
|
||||||
Receiver.send_message(u'slidecontroller_live_previous')
|
Receiver.send_message(u'slidecontroller_live_previous')
|
||||||
event.accept()
|
event.accept()
|
||||||
@ -185,157 +82,269 @@ class DisplayWidget(QtGui.QGraphicsView):
|
|||||||
Receiver.send_message(self.hotkey_map[event.key()])
|
Receiver.send_message(self.hotkey_map[event.key()])
|
||||||
event.accept()
|
event.accept()
|
||||||
elif event.key() == QtCore.Qt.Key_Escape:
|
elif event.key() == QtCore.Qt.Key_Escape:
|
||||||
self.resetDisplay()
|
self.setVisible(False)
|
||||||
|
self.videoStop()
|
||||||
event.accept()
|
event.accept()
|
||||||
event.ignore()
|
event.ignore()
|
||||||
else:
|
else:
|
||||||
event.ignore()
|
event.ignore()
|
||||||
|
|
||||||
def resetDisplay(self):
|
|
||||||
log.debug(u'resetDisplay')
|
|
||||||
Receiver.send_message(u'slidecontroller_live_stop_loop')
|
|
||||||
if self.primary:
|
|
||||||
self.setVisible(False)
|
|
||||||
else:
|
|
||||||
self.setVisible(True)
|
|
||||||
|
|
||||||
class MainDisplay(DisplayWidget):
|
class MainDisplay(DisplayWidget):
|
||||||
"""
|
|
||||||
This is the form that is used to display things on the projector.
|
|
||||||
"""
|
|
||||||
log.info(u'MainDisplay Loaded')
|
|
||||||
|
|
||||||
def __init__(self, parent, screens):
|
def __init__(self, parent, screens, live):
|
||||||
"""
|
DisplayWidget.__init__(self, live, parent=None)
|
||||||
The constructor for the display form.
|
self.parent = parent
|
||||||
|
|
||||||
``parent``
|
|
||||||
The parent widget.
|
|
||||||
|
|
||||||
``screens``
|
|
||||||
The list of screens.
|
|
||||||
"""
|
|
||||||
log.debug(u'Initialisation started')
|
|
||||||
DisplayWidget.__init__(self, parent, primary=True)
|
|
||||||
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
|
|
||||||
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
# WA_TranslucentBackground is not available in QT4.4
|
|
||||||
try:
|
|
||||||
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
self.screens = screens
|
self.screens = screens
|
||||||
self.setupScene()
|
self.isLive = live
|
||||||
self.setupVideo()
|
self.alertTab = None
|
||||||
self.setupImage()
|
self.setWindowTitle(u'OpenLP Display')
|
||||||
self.setupText()
|
self.setWindowFlags(QtCore.Qt.FramelessWindowHint |
|
||||||
self.setupAlert()
|
QtCore.Qt.WindowStaysOnTopHint)
|
||||||
self.setupBlank()
|
if self.isLive:
|
||||||
self.blankFrame = None
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
self.frame = None
|
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
|
||||||
#Hide desktop for now until we know where to put it
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
#and what size it should be.
|
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
|
||||||
self.setVisible(False)
|
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""
|
"""
|
||||||
Sets up the screen on a particular screen.
|
Set up and build the output screen
|
||||||
"""
|
"""
|
||||||
log.debug(u'Setup %s for %s ' % (
|
log.debug(u'Setup live = %s for %s ' % (self.isLive,
|
||||||
self.screens, self.screens.monitor_number))
|
self.screens.monitor_number))
|
||||||
self.setVisible(False)
|
|
||||||
self.screen = self.screens.current
|
self.screen = self.screens.current
|
||||||
#Sort out screen locations and sizes
|
self.setVisible(False)
|
||||||
self.setGeometry(self.screen[u'size'])
|
self.setGeometry(self.screen[u'size'])
|
||||||
self.scene.setSceneRect(0, 0, self.size().width(),
|
self.webView = QtWebKit.QWebView(self)
|
||||||
self.size().height())
|
self.webView.setGeometry(0, 0, self.screen[u'size'].width(), \
|
||||||
self.webView.setGeometry(0, 0, self.size().width(),
|
self.screen[u'size'].height())
|
||||||
self.size().height())
|
self.page = self.webView.page()
|
||||||
self.alertText.setTextWidth(self.size().width())
|
self.frame = self.page.mainFrame()
|
||||||
#Build a custom splash screen
|
QtCore.QObject.connect(self.webView,
|
||||||
self.initialFrame = QtGui.QImage(
|
QtCore.SIGNAL(u'loadFinished(bool)'), self.isLoaded)
|
||||||
self.screen[u'size'].width(),
|
self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
|
||||||
self.screen[u'size'].height(),
|
QtCore.Qt.ScrollBarAlwaysOff)
|
||||||
|
self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
|
||||||
|
QtCore.Qt.ScrollBarAlwaysOff)
|
||||||
|
if self.isLive:
|
||||||
|
# Build the initial frame.
|
||||||
|
self.black = QtGui.QImage(
|
||||||
|
self.screens.current[u'size'].width(),
|
||||||
|
self.screens.current[u'size'].height(),
|
||||||
|
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
|
painter_image = QtGui.QPainter()
|
||||||
|
painter_image.begin(self.black)
|
||||||
|
painter_image.fillRect(self.black.rect(), QtCore.Qt.black)
|
||||||
|
#Build the initial frame.
|
||||||
|
initialFrame = QtGui.QImage(
|
||||||
|
self.screens.current[u'size'].width(),
|
||||||
|
self.screens.current[u'size'].height(),
|
||||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
|
splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
|
||||||
painter_image = QtGui.QPainter()
|
painter_image = QtGui.QPainter()
|
||||||
painter_image.begin(self.initialFrame)
|
painter_image.begin(initialFrame)
|
||||||
painter_image.fillRect(self.initialFrame.rect(), QtCore.Qt.white)
|
painter_image.fillRect(initialFrame.rect(), QtCore.Qt.white)
|
||||||
painter_image.drawImage(
|
painter_image.drawImage(
|
||||||
(self.screen[u'size'].width() - splash_image.width()) / 2,
|
(self.screens.current[u'size'].width() \
|
||||||
(self.screen[u'size'].height() - splash_image.height()) / 2,
|
- splash_image.width()) / 2,
|
||||||
|
(self.screens.current[u'size'].height() \
|
||||||
|
- splash_image.height()) / 2,
|
||||||
splash_image)
|
splash_image)
|
||||||
#build a blank transparent image
|
serviceItem = ServiceItem()
|
||||||
self.transparent = QtGui.QPixmap(
|
serviceItem.bg_frame = initialFrame
|
||||||
self.screen[u'size'].width(), self.screen[u'size'].height())
|
self.webView.setHtml(build_html(serviceItem, self.screen, \
|
||||||
self.transparent.fill(QtCore.Qt.transparent)
|
self.parent.alertTab))
|
||||||
self.displayImage(self.initialFrame)
|
self.initialFrame = True
|
||||||
self.repaint()
|
self.show()
|
||||||
#Build a Black screen
|
|
||||||
painter = QtGui.QPainter()
|
|
||||||
self.blankFrame = QtGui.QImage(
|
|
||||||
self.screen[u'size'].width(),
|
|
||||||
self.screen[u'size'].height(),
|
|
||||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
|
||||||
painter.begin(self.blankFrame)
|
|
||||||
painter.fillRect(self.blankFrame.rect(), QtCore.Qt.black)
|
|
||||||
# To display or not to display?
|
# To display or not to display?
|
||||||
if not self.screen[u'primary']:
|
if not self.screen[u'primary']:
|
||||||
self.setVisible(True)
|
|
||||||
self.primary = False
|
self.primary = False
|
||||||
else:
|
else:
|
||||||
self.setVisible(False)
|
|
||||||
self.primary = True
|
self.primary = True
|
||||||
|
|
||||||
def setupScene(self):
|
def text(self, slide):
|
||||||
self.scene = QtGui.QGraphicsScene(self)
|
"""
|
||||||
self.scene.setSceneRect(0, 0, self.size().width(), self.size().height())
|
Add the slide text from slideController
|
||||||
self.setScene(self.scene)
|
|
||||||
|
|
||||||
def setupVideo(self):
|
`slide`
|
||||||
self.webView = QtWebKit.QWebView()
|
The slide text to be displayed
|
||||||
self.page = self.webView.page()
|
"""
|
||||||
self.videoDisplay = self.page.mainFrame()
|
log.debug(u'text')
|
||||||
self.videoDisplay.setScrollBarPolicy(QtCore.Qt.Vertical,
|
self.frame.evaluateJavaScript(u'show_text("%s")' % \
|
||||||
QtCore.Qt.ScrollBarAlwaysOff)
|
slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
|
||||||
self.videoDisplay.setScrollBarPolicy(QtCore.Qt.Horizontal,
|
return self.preview()
|
||||||
QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
self.proxy = QtGui.QGraphicsProxyWidget()
|
|
||||||
self.proxy.setWidget(self.webView)
|
|
||||||
self.proxy.setWindowFlags(QtCore.Qt.Window |
|
|
||||||
QtCore.Qt.FramelessWindowHint)
|
|
||||||
self.proxy.setZValue(1)
|
|
||||||
self.scene.addItem(self.proxy)
|
|
||||||
|
|
||||||
def setupImage(self):
|
def alert(self, text):
|
||||||
self.imageDisplay = QtGui.QGraphicsPixmapItem()
|
"""
|
||||||
self.imageDisplay.setZValue(2)
|
Add the alert text
|
||||||
self.scene.addItem(self.imageDisplay)
|
|
||||||
|
|
||||||
def setupText(self):
|
`slide`
|
||||||
#self.displayText = QtGui.QGraphicsTextItem()
|
The slide text to be displayed
|
||||||
self.displayText = QtGui.QGraphicsPixmapItem()
|
"""
|
||||||
#self.displayText.setPos(0,0)
|
log.debug(u'alert')
|
||||||
#self.displayText.setTextWidth(self.size().width())
|
if self.height() != self.screen[u'size'].height() \
|
||||||
self.displayText.setZValue(4)
|
or not self.isVisible():
|
||||||
self.scene.addItem(self.displayText)
|
shrink = True
|
||||||
|
else:
|
||||||
|
shrink = False
|
||||||
|
js = u'show_alert("%s", "%s")' % (
|
||||||
|
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
|
||||||
|
u'top' if shrink else u'')
|
||||||
|
height = self.frame.evaluateJavaScript(js)
|
||||||
|
if shrink:
|
||||||
|
if text:
|
||||||
|
self.resize(self.width(), int(height.toString()))
|
||||||
|
self.setVisible(True)
|
||||||
|
else:
|
||||||
|
self.setGeometry(self.screen[u'size'])
|
||||||
|
self.setVisible(False)
|
||||||
|
|
||||||
def setupAlert(self):
|
def image(self, image):
|
||||||
self.alertText = QtGui.QGraphicsTextItem()
|
"""
|
||||||
self.alertText.setZValue(8)
|
Add an image as the background. The image is converted to a
|
||||||
self.scene.addItem(self.alertText)
|
bytestream on route.
|
||||||
|
|
||||||
def setupBlank(self):
|
`Image`
|
||||||
self.displayBlank = QtGui.QGraphicsPixmapItem()
|
The Image to be displayed can be QImage or QPixmap
|
||||||
self.displayBlank.setZValue(10)
|
"""
|
||||||
self.scene.addItem(self.displayBlank)
|
log.debug(u'image')
|
||||||
|
image = resize_image(image, self.screen[u'size'].width(),
|
||||||
|
self.screen[u'size'].height())
|
||||||
|
self.resetVideo()
|
||||||
|
self.displayImage(image)
|
||||||
|
# show screen
|
||||||
|
if self.isLive:
|
||||||
|
self.setVisible(True)
|
||||||
|
|
||||||
# def hideDisplayForVideo(self):
|
def displayImage(self, image):
|
||||||
# """
|
"""
|
||||||
# Hides the main display if for the video to be played
|
Display an image, as is.
|
||||||
# """
|
"""
|
||||||
# self.hideDisplay(HideMode.Screen)
|
if image:
|
||||||
|
js = u'show_image("data:image/png;base64,%s");' % \
|
||||||
|
image_to_byte(image)
|
||||||
|
else:
|
||||||
|
js = u'show_image("");'
|
||||||
|
self.frame.evaluateJavaScript(js)
|
||||||
|
|
||||||
|
def resetImage(self):
|
||||||
|
"""
|
||||||
|
Reset the backgound image to the service item image.
|
||||||
|
Used after Image plugin has changed the background
|
||||||
|
"""
|
||||||
|
log.debug(u'resetImage')
|
||||||
|
self.displayImage(self.serviceItem.bg_frame)
|
||||||
|
|
||||||
|
def resetVideo(self):
|
||||||
|
"""
|
||||||
|
Used after Video plugin has changed the background
|
||||||
|
"""
|
||||||
|
log.debug(u'resetVideo')
|
||||||
|
self.frame.evaluateJavaScript(u'show_video("close");')
|
||||||
|
|
||||||
|
def videoPlay(self):
|
||||||
|
"""
|
||||||
|
Responds to the request to play a loaded video
|
||||||
|
"""
|
||||||
|
log.debug(u'videoPlay')
|
||||||
|
self.frame.evaluateJavaScript(u'show_video("play");')
|
||||||
|
# show screen
|
||||||
|
if self.isLive:
|
||||||
|
self.setVisible(True)
|
||||||
|
|
||||||
|
def videoPause(self):
|
||||||
|
"""
|
||||||
|
Responds to the request to pause a loaded video
|
||||||
|
"""
|
||||||
|
log.debug(u'videoPause')
|
||||||
|
self.frame.evaluateJavaScript(u'show_video("pause");')
|
||||||
|
|
||||||
|
def videoStop(self):
|
||||||
|
"""
|
||||||
|
Responds to the request to stop a loaded video
|
||||||
|
"""
|
||||||
|
log.debug(u'videoStop')
|
||||||
|
self.frame.evaluateJavaScript(u'show_video("stop");')
|
||||||
|
|
||||||
|
def videoVolume(self, volume):
|
||||||
|
"""
|
||||||
|
Changes the volume of a running video
|
||||||
|
"""
|
||||||
|
log.debug(u'videoVolume %d' % volume)
|
||||||
|
self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
|
||||||
|
str(float(volume)/float(10)))
|
||||||
|
|
||||||
|
def video(self, videoPath, volume):
|
||||||
|
"""
|
||||||
|
Loads and starts a video to run with the option of sound
|
||||||
|
"""
|
||||||
|
log.debug(u'video')
|
||||||
|
self.loaded = True
|
||||||
|
js = u'show_video("play", "%s", %s, true);' % \
|
||||||
|
(videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10)))
|
||||||
|
self.frame.evaluateJavaScript(js)
|
||||||
|
return self.preview()
|
||||||
|
|
||||||
|
def isLoaded(self):
|
||||||
|
"""
|
||||||
|
Called by webView event to show display is fully loaded
|
||||||
|
"""
|
||||||
|
log.debug(u'loaded')
|
||||||
|
self.loaded = True
|
||||||
|
|
||||||
|
def preview(self):
|
||||||
|
"""
|
||||||
|
Generates a preview of the image displayed.
|
||||||
|
"""
|
||||||
|
log.debug(u'preview for %s', self.isLive)
|
||||||
|
# Wait for the fade to finish before geting the preview.
|
||||||
|
# Important otherwise preview will have incorrect text if at all !
|
||||||
|
if self.serviceItem.themedata and \
|
||||||
|
self.serviceItem.themedata.display_slideTransition:
|
||||||
|
while self.frame.evaluateJavaScript(u'show_text_complete()') \
|
||||||
|
.toString() == u'false':
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
# Wait for the webview to update before geting the preview.
|
||||||
|
# Important otherwise first preview will miss the background !
|
||||||
|
while not self.loaded:
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
preview = QtGui.QImage(self.screen[u'size'].width(),
|
||||||
|
self.screen[u'size'].height(),
|
||||||
|
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
|
painter = QtGui.QPainter(preview)
|
||||||
|
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
|
self.frame.render(painter)
|
||||||
|
painter.end()
|
||||||
|
# Make display show up if in single screen mode
|
||||||
|
if self.isLive:
|
||||||
|
self.setVisible(True)
|
||||||
|
# save preview for debugging
|
||||||
|
if log.isEnabledFor(logging.DEBUG):
|
||||||
|
preview.save(u'temp.png', u'png')
|
||||||
|
return preview
|
||||||
|
|
||||||
|
def buildHtml(self, serviceItem):
|
||||||
|
"""
|
||||||
|
Store the serviceItem and build the new HTML from it. Add the
|
||||||
|
HTML to the display
|
||||||
|
"""
|
||||||
|
log.debug(u'buildHtml')
|
||||||
|
self.loaded = False
|
||||||
|
self.initialFrame = False
|
||||||
|
self.serviceItem = serviceItem
|
||||||
|
html = build_html(self.serviceItem, self.screen, self.parent.alertTab)
|
||||||
|
self.webView.setHtml(html)
|
||||||
|
if serviceItem.foot_text and serviceItem.foot_text:
|
||||||
|
self.footer(serviceItem.foot_text)
|
||||||
|
|
||||||
|
def footer(self, text):
|
||||||
|
"""
|
||||||
|
Display the Footer
|
||||||
|
"""
|
||||||
|
log.debug(u'footer')
|
||||||
|
js = "show_footer('" + \
|
||||||
|
text.replace("\\", "\\\\").replace("\'", "\\\'") + "')"
|
||||||
|
self.frame.evaluateJavaScript(js)
|
||||||
|
|
||||||
def hideDisplay(self, mode=HideMode.Screen):
|
def hideDisplay(self, mode=HideMode.Screen):
|
||||||
"""
|
"""
|
||||||
@ -343,20 +352,13 @@ class MainDisplay(DisplayWidget):
|
|||||||
Store the images so they can be replaced when required
|
Store the images so they can be replaced when required
|
||||||
"""
|
"""
|
||||||
log.debug(u'hideDisplay mode = %d', mode)
|
log.debug(u'hideDisplay mode = %d', mode)
|
||||||
#self.displayText.setPixmap(self.transparent)
|
|
||||||
if mode == HideMode.Screen:
|
if mode == HideMode.Screen:
|
||||||
#self.display_image.setPixmap(self.transparent)
|
self.frame.evaluateJavaScript(u'show_blank("desktop");')
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
elif mode == HideMode.Blank:
|
elif mode == HideMode.Blank or self.initialFrame:
|
||||||
self.displayBlank.setPixmap(
|
self.frame.evaluateJavaScript(u'show_blank("black");')
|
||||||
QtGui.QPixmap.fromImage(self.blankFrame))
|
|
||||||
else:
|
else:
|
||||||
if self.parent.renderManager.renderer.bg_frame:
|
self.frame.evaluateJavaScript(u'show_blank("theme");')
|
||||||
self.displayBlank.setPixmap(QtGui.QPixmap.fromImage(
|
|
||||||
self.parent.renderManager.renderer.bg_frame))
|
|
||||||
else:
|
|
||||||
self.displayBlank.setPixmap(
|
|
||||||
QtGui.QPixmap.fromImage(self.blankFrame))
|
|
||||||
if mode != HideMode.Screen and self.isHidden():
|
if mode != HideMode.Screen and self.isHidden():
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
|
|
||||||
@ -367,275 +369,16 @@ class MainDisplay(DisplayWidget):
|
|||||||
Make the stored images None to release memory.
|
Make the stored images None to release memory.
|
||||||
"""
|
"""
|
||||||
log.debug(u'showDisplay')
|
log.debug(u'showDisplay')
|
||||||
self.displayBlank.setPixmap(self.transparent)
|
self.frame.evaluateJavaScript('show_blank("show");')
|
||||||
if self.isHidden():
|
if self.isHidden():
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
#Trigger actions when display is active again
|
# Trigger actions when display is active again
|
||||||
Receiver.send_message(u'maindisplay_active')
|
Receiver.send_message(u'maindisplay_active')
|
||||||
|
|
||||||
def addImageWithText(self, frame):
|
|
||||||
log.debug(u'addImageWithText')
|
|
||||||
frame = resize_image(
|
|
||||||
frame, self.screen[u'size'].width(), self.screen[u'size'].height())
|
|
||||||
self.imageDisplay.setPixmap(QtGui.QPixmap.fromImage(frame))
|
|
||||||
self.videoDisplay.setHtml(u'<html></html>')
|
|
||||||
|
|
||||||
def addAlert(self, message, location):
|
|
||||||
"""
|
|
||||||
Places the Alert text on the display at the correct location
|
|
||||||
``message``
|
|
||||||
Text to be displayed
|
|
||||||
``location``
|
|
||||||
Where on the screen the text should be. From the AlertTab
|
|
||||||
Combo box.
|
|
||||||
"""
|
|
||||||
log.debug(u'addAlertImage')
|
|
||||||
if location == 0:
|
|
||||||
self.alertText.setPos(0, 0)
|
|
||||||
elif location == 1:
|
|
||||||
self.alertText.setPos(0, self.size().height() / 2)
|
|
||||||
else:
|
|
||||||
self.alertText.setPos(0, self.size().height() - 76)
|
|
||||||
self.alertText.setHtml(message)
|
|
||||||
|
|
||||||
def displayImage(self, frame):
|
|
||||||
"""
|
|
||||||
Places the Image passed on the display screen
|
|
||||||
``frame``
|
|
||||||
The image to be displayed
|
|
||||||
"""
|
|
||||||
log.debug(u'adddisplayImage')
|
|
||||||
if isinstance(frame, QtGui.QImage):
|
|
||||||
self.imageDisplay.setPixmap(QtGui.QPixmap.fromImage(frame))
|
|
||||||
else:
|
|
||||||
self.imageDisplay.setPixmap(frame)
|
|
||||||
self.frameView(self.transparent)
|
|
||||||
self.videoDisplay.setHtml(u'<html></html>')
|
|
||||||
|
|
||||||
def displayVideo(self, path):
|
|
||||||
"""
|
|
||||||
Places the Video passed on the display screen
|
|
||||||
``path``
|
|
||||||
The path to the image to be displayed
|
|
||||||
"""
|
|
||||||
log.debug(u'adddisplayVideo')
|
|
||||||
self.displayImage(self.transparent)
|
|
||||||
self.videoDisplay.setHtml(HTMLVIDEO %
|
|
||||||
(path, self.screen[u'size'].width(),
|
|
||||||
self.screen[u'size'].height()))
|
|
||||||
|
|
||||||
def frameView(self, frame, transition=False):
|
|
||||||
"""
|
|
||||||
Called from a slide controller to display a frame
|
|
||||||
if the alert is in progress the alert is added on top
|
|
||||||
``frame``
|
|
||||||
Image frame to be rendered
|
|
||||||
``transition``
|
|
||||||
Are transitions required.
|
|
||||||
"""
|
|
||||||
log.debug(u'frameView')
|
|
||||||
if transition:
|
|
||||||
if self.frame is not None:
|
|
||||||
self.displayText.setPixmap(
|
|
||||||
QtGui.QPixmap.fromImage(self.frame))
|
|
||||||
self.repaint()
|
|
||||||
Receiver.send_message(u'openlp_process_events')
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.frame = None
|
|
||||||
if frame[u'trans'] is not None:
|
|
||||||
self.displayText.setPixmap(
|
|
||||||
QtGui.QPixmap.fromImage(frame[u'trans']))
|
|
||||||
self.repaint()
|
|
||||||
Receiver.send_message(u'openlp_process_events')
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.frame = frame[u'trans']
|
|
||||||
self.displayText.setPixmap(
|
|
||||||
QtGui.QPixmap.fromImage(frame[u'main']))
|
|
||||||
else:
|
|
||||||
if isinstance(frame, QtGui.QPixmap):
|
|
||||||
self.displayText.setPixmap(frame)
|
|
||||||
else:
|
|
||||||
self.displayText.setPixmap(QtGui.QPixmap.fromImage(frame))
|
|
||||||
if not self.isVisible() and self.screens.current['primary']:
|
|
||||||
self.setVisible(True)
|
|
||||||
|
|
||||||
class VideoDisplay(Phonon.VideoWidget):
|
|
||||||
"""
|
|
||||||
This is the form that is used to display videos on the projector.
|
|
||||||
"""
|
|
||||||
log.info(u'VideoDisplay Loaded')
|
|
||||||
|
|
||||||
def __init__(self, parent, screens,
|
|
||||||
aspect=Phonon.VideoWidget.AspectRatioWidget):
|
|
||||||
"""
|
|
||||||
The constructor for the display form.
|
|
||||||
|
|
||||||
``parent``
|
|
||||||
The parent widget.
|
|
||||||
|
|
||||||
``screens``
|
|
||||||
The list of screens.
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay Initialisation started')
|
|
||||||
Phonon.VideoWidget.__init__(self)
|
|
||||||
self.setWindowTitle(u'OpenLP Video Display')
|
|
||||||
self.parent = parent
|
|
||||||
self.screens = screens
|
|
||||||
self.hidden = False
|
|
||||||
self.message = None
|
|
||||||
self.mediaActive = False
|
|
||||||
self.mediaObject = Phonon.MediaObject()
|
|
||||||
self.setAspectRatio(aspect)
|
|
||||||
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
|
|
||||||
Phonon.createPath(self.mediaObject, self)
|
|
||||||
Phonon.createPath(self.mediaObject, self.audioObject)
|
|
||||||
flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog
|
|
||||||
## # WindowsStaysOnBottomHint is not available in QT4.4
|
|
||||||
# try:
|
|
||||||
# flags = flags | QtCore.Qt.WindowStaysOnBottomHint
|
|
||||||
# except AttributeError:
|
|
||||||
# pass
|
|
||||||
self.setWindowFlags(flags)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'videodisplay_play'), self.onMediaPlay)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'videodisplay_pause'), self.onMediaPause)
|
|
||||||
# QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
# QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
||||||
QtCore.SIGNAL(u'config_updated'), self.setup)
|
|
||||||
QtCore.QObject.connect(self.mediaObject,
|
|
||||||
QtCore.SIGNAL(u'finished()'), self.onMediaStop)
|
|
||||||
self.setVisible(False)
|
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
|
||||||
if isinstance(event, QtGui.QKeyEvent):
|
|
||||||
#here accept the event and do something
|
|
||||||
if event.key() == QtCore.Qt.Key_Escape:
|
|
||||||
self.onMediaStop()
|
|
||||||
event.accept()
|
|
||||||
event.ignore()
|
|
||||||
else:
|
|
||||||
event.ignore()
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
"""
|
|
||||||
Sets up the screen on a particular screen.
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay Setup %s for %s ' % (self.screens,
|
|
||||||
self.screens.monitor_number))
|
|
||||||
self.screen = self.screens.current
|
|
||||||
#Sort out screen locations and sizes
|
|
||||||
self.setGeometry(self.screen[u'size'])
|
|
||||||
# To display or not to display?
|
|
||||||
if not self.screen[u'primary']: # and self.isVisible():
|
|
||||||
#self.showFullScreen()
|
|
||||||
self.setVisible(False)
|
|
||||||
self.primary = False
|
|
||||||
else:
|
|
||||||
self.setVisible(False)
|
|
||||||
self.primary = True
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
"""
|
|
||||||
Shutting down so clean up connections
|
|
||||||
"""
|
|
||||||
self.onMediaStop()
|
|
||||||
for path in self.outputPaths():
|
|
||||||
path.disconnect()
|
|
||||||
|
|
||||||
# def onMediaBackground(self, message=None):
|
|
||||||
# """
|
|
||||||
# Play a video triggered from the video plugin with the
|
|
||||||
# file name passed in on the event.
|
|
||||||
# Also triggered from the Finish event so the video will loop
|
|
||||||
# if it is triggered from the plugin
|
|
||||||
# """
|
|
||||||
# log.debug(u'VideoDisplay Queue new media message %s' % message)
|
|
||||||
# #If not file take the stored one
|
|
||||||
# if not message:
|
|
||||||
# message = self.message
|
|
||||||
# # still no file name then stop as it was a normal video stopping
|
|
||||||
# if message:
|
|
||||||
# self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
|
|
||||||
# self.message = message
|
|
||||||
# self._play()
|
|
||||||
|
|
||||||
def onMediaQueue(self, message):
|
|
||||||
"""
|
|
||||||
Set up a video to play from the serviceitem.
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay Queue new media message %s' % message)
|
|
||||||
file = os.path.join(message.get_frame_path(),
|
|
||||||
message.get_frame_title())
|
|
||||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
|
|
||||||
self.mediaActive = True
|
|
||||||
self._play()
|
|
||||||
|
|
||||||
def onMediaPlay(self):
|
|
||||||
"""
|
|
||||||
Respond to the Play button on the slide controller unless the display
|
|
||||||
has been hidden by the slidecontroller
|
|
||||||
"""
|
|
||||||
if not self.hidden:
|
|
||||||
log.debug(u'VideoDisplay Play the new media, Live ')
|
|
||||||
self._play()
|
|
||||||
|
|
||||||
def _play(self):
|
|
||||||
"""
|
|
||||||
We want to play the video so start it and display the screen
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay _play called')
|
|
||||||
self.mediaObject.play()
|
|
||||||
self.setVisible(True)
|
|
||||||
|
|
||||||
def onMediaPause(self):
|
|
||||||
"""
|
|
||||||
Pause the video and refresh the screen
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay Media paused by user')
|
|
||||||
self.mediaObject.pause()
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def onMediaStop(self):
|
|
||||||
"""
|
|
||||||
Stop the video and clean up
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay Media stopped by user')
|
|
||||||
self.message = None
|
|
||||||
self.mediaActive = False
|
|
||||||
self.mediaObject.stop()
|
|
||||||
self.onMediaFinish()
|
|
||||||
|
|
||||||
def onMediaFinish(self):
|
|
||||||
"""
|
|
||||||
Clean up the Object queue
|
|
||||||
"""
|
|
||||||
log.debug(u'VideoDisplay Reached end of media playlist')
|
|
||||||
self.mediaObject.clearQueue()
|
|
||||||
self.setVisible(False)
|
|
||||||
|
|
||||||
def mediaHide(self, message=u''):
|
|
||||||
"""
|
|
||||||
Hide the video display
|
|
||||||
"""
|
|
||||||
self.mediaObject.pause()
|
|
||||||
self.hidden = True
|
|
||||||
self.setVisible(False)
|
|
||||||
|
|
||||||
def mediaShow(self):
|
|
||||||
"""
|
|
||||||
Show the video display if it was already hidden
|
|
||||||
"""
|
|
||||||
if self.hidden:
|
|
||||||
self.hidden = False
|
|
||||||
if self.mediaActive:
|
|
||||||
self._play()
|
|
||||||
|
|
||||||
class AudioPlayer(QtCore.QObject):
|
class AudioPlayer(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
This Class will play audio only allowing components to work with a
|
This Class will play audio only allowing components to work with a
|
||||||
soundtrack which does not take over the user interface.
|
soundtrack independent of the user interface.
|
||||||
"""
|
"""
|
||||||
log.info(u'AudioPlayer Loaded')
|
log.info(u'AudioPlayer Loaded')
|
||||||
|
|
||||||
@ -675,9 +418,9 @@ class AudioPlayer(QtCore.QObject):
|
|||||||
Set up a video to play from the serviceitem.
|
Set up a video to play from the serviceitem.
|
||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer Queue new media message %s' % message)
|
log.debug(u'AudioPlayer Queue new media message %s' % message)
|
||||||
file = os.path.join(message[0].get_frame_path(),
|
mfile = os.path.join(message[0].get_frame_path(),
|
||||||
message[0].get_frame_title())
|
message[0].get_frame_title())
|
||||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
|
self.mediaObject.setCurrentSource(Phonon.MediaSource(mfile))
|
||||||
self.onMediaPlay()
|
self.onMediaPlay()
|
||||||
|
|
||||||
def onMediaPlay(self):
|
def onMediaPlay(self):
|
||||||
|
@ -29,7 +29,7 @@ import logging
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
|
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
|
||||||
ThemeManager, SlideController, PluginForm, MediaDockManager, DisplayManager
|
ThemeManager, SlideController, PluginForm, MediaDockManager
|
||||||
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
|
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
|
||||||
SettingsManager, PluginManager, Receiver, translate
|
SettingsManager, PluginManager, Receiver, translate
|
||||||
from openlp.core.utils import AppLocation, add_actions, LanguageManager
|
from openlp.core.utils import AppLocation, add_actions, LanguageManager
|
||||||
@ -94,8 +94,8 @@ class Ui_MainWindow(object):
|
|||||||
self.ControlSplitter.setObjectName(u'ControlSplitter')
|
self.ControlSplitter.setObjectName(u'ControlSplitter')
|
||||||
self.MainContentLayout.addWidget(self.ControlSplitter)
|
self.MainContentLayout.addWidget(self.ControlSplitter)
|
||||||
# Create slide controllers
|
# Create slide controllers
|
||||||
self.PreviewController = SlideController(self, self.settingsmanager)
|
self.PreviewController = SlideController(self, self.settingsmanager, self.screens)
|
||||||
self.LiveController = SlideController(self, self.settingsmanager, True)
|
self.LiveController = SlideController(self, self.settingsmanager, self.screens, True)
|
||||||
# Create menu
|
# Create menu
|
||||||
self.MenuBar = QtGui.QMenuBar(MainWindow)
|
self.MenuBar = QtGui.QMenuBar(MainWindow)
|
||||||
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
|
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
|
||||||
@ -509,7 +509,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.songsSettingsSection = u'songs'
|
self.songsSettingsSection = u'songs'
|
||||||
self.serviceNotSaved = False
|
self.serviceNotSaved = False
|
||||||
self.settingsmanager = SettingsManager(screens)
|
self.settingsmanager = SettingsManager(screens)
|
||||||
self.displayManager = DisplayManager(screens)
|
|
||||||
self.aboutForm = AboutForm(self, applicationVersion)
|
self.aboutForm = AboutForm(self, applicationVersion)
|
||||||
self.settingsForm = SettingsForm(self.screens, self, self)
|
self.settingsForm = SettingsForm(self.screens, self, self)
|
||||||
self.recentFiles = QtCore.QStringList()
|
self.recentFiles = QtCore.QStringList()
|
||||||
@ -594,7 +593,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
#ThemeManager needs to call RenderManager
|
#ThemeManager needs to call RenderManager
|
||||||
self.RenderManager = RenderManager(
|
self.RenderManager = RenderManager(
|
||||||
self.ThemeManagerContents, self.screens)
|
self.ThemeManagerContents, self.screens)
|
||||||
self.displayManager.renderManager = self.RenderManager
|
|
||||||
#Define the media Dock Manager
|
#Define the media Dock Manager
|
||||||
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
|
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
|
||||||
log.info(u'Load Plugins')
|
log.info(u'Load Plugins')
|
||||||
@ -605,7 +603,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.plugin_helpers[u'service'] = self.ServiceManagerContents
|
self.plugin_helpers[u'service'] = self.ServiceManagerContents
|
||||||
self.plugin_helpers[u'settings form'] = self.settingsForm
|
self.plugin_helpers[u'settings form'] = self.settingsForm
|
||||||
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
|
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
|
||||||
self.plugin_helpers[u'displaymanager'] = self.displayManager
|
|
||||||
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager
|
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager
|
||||||
self.plugin_helpers[u'formparent'] = self
|
self.plugin_helpers[u'formparent'] = self
|
||||||
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
|
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
|
||||||
@ -662,9 +659,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
Show the main form, as well as the display form
|
Show the main form, as well as the display form
|
||||||
"""
|
"""
|
||||||
QtGui.QWidget.show(self)
|
QtGui.QWidget.show(self)
|
||||||
self.displayManager.setup()
|
self.LiveController.display.setup()
|
||||||
if self.displayManager.mainDisplay.isVisible():
|
self.PreviewController.display.setup()
|
||||||
self.displayManager.mainDisplay.setFocus()
|
if self.LiveController.display.isVisible():
|
||||||
|
self.LiveController.display.setFocus()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
if QtCore.QSettings().value(
|
if QtCore.QSettings().value(
|
||||||
self.generalSettingsSection + u'/auto open',
|
self.generalSettingsSection + u'/auto open',
|
||||||
@ -744,8 +742,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
The screen has changed to so tell the displays to update_display
|
The screen has changed to so tell the displays to update_display
|
||||||
their locations
|
their locations
|
||||||
"""
|
"""
|
||||||
|
log.debug(u'screenChanged')
|
||||||
self.RenderManager.update_display()
|
self.RenderManager.update_display()
|
||||||
self.displayManager.setup()
|
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
|
|
||||||
@ -791,8 +789,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.plugin_manager.finalise_plugins()
|
self.plugin_manager.finalise_plugins()
|
||||||
# Save settings
|
# Save settings
|
||||||
self.saveSettings()
|
self.saveSettings()
|
||||||
#Close down the displays
|
#Close down the display
|
||||||
self.displayManager.close()
|
self.LiveController.display.close()
|
||||||
|
|
||||||
def serviceChanged(self, reset=False, serviceName=None):
|
def serviceChanged(self, reset=False, serviceName=None):
|
||||||
"""
|
"""
|
||||||
|
@ -44,9 +44,9 @@ class ScreenList(object):
|
|||||||
self.override = None
|
self.override = None
|
||||||
self.screen_list = []
|
self.screen_list = []
|
||||||
self.display_count = 0
|
self.display_count = 0
|
||||||
#actual display number
|
# actual display number
|
||||||
self.current_display = 0
|
self.current_display = 0
|
||||||
#save config display number
|
# save config display number
|
||||||
self.monitor_number = 0
|
self.monitor_number = 0
|
||||||
|
|
||||||
def add_screen(self, screen):
|
def add_screen(self, screen):
|
||||||
|
@ -317,9 +317,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.serviceItemEditForm.setServiceItem(
|
self.serviceItemEditForm.setServiceItem(
|
||||||
self.serviceItems[item][u'service_item'])
|
self.serviceItems[item][u'service_item'])
|
||||||
if self.serviceItemEditForm.exec_():
|
if self.serviceItemEditForm.exec_():
|
||||||
self.serviceItems[item][u'service_item'] = \
|
self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
|
||||||
self.serviceItemEditForm.getServiceItem()
|
replace=True)
|
||||||
self.repaintServiceList(item, 0)
|
|
||||||
|
|
||||||
def nextItem(self):
|
def nextItem(self):
|
||||||
"""
|
"""
|
||||||
@ -780,7 +779,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
Rebuild the service list as things have changed and a
|
Rebuild the service list as things have changed and a
|
||||||
repaint is the easiest way to do this.
|
repaint is the easiest way to do this.
|
||||||
"""
|
"""
|
||||||
#force reset of renderer as theme data has changed
|
# force reset of renderer as theme data has changed
|
||||||
self.parent.RenderManager.themedata = None
|
self.parent.RenderManager.themedata = None
|
||||||
if self.serviceItems:
|
if self.serviceItems:
|
||||||
tempServiceItems = self.serviceItems
|
tempServiceItems = self.serviceItems
|
||||||
@ -790,8 +789,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
for item in tempServiceItems:
|
for item in tempServiceItems:
|
||||||
self.addServiceItem(
|
self.addServiceItem(
|
||||||
item[u'service_item'], False, item[u'expanded'])
|
item[u'service_item'], False, item[u'expanded'])
|
||||||
#Set to False as items may have changed rendering
|
# Set to False as items may have changed rendering
|
||||||
#does not impact the saved song so True may also be valid
|
# does not impact the saved song so True may also be valid
|
||||||
self.parent.serviceChanged(False, self.serviceName)
|
self.parent.serviceChanged(False, self.serviceName)
|
||||||
|
|
||||||
def addServiceItem(self, item, rebuild=False, expand=True, replace=False):
|
def addServiceItem(self, item, rebuild=False, expand=True, replace=False):
|
||||||
@ -873,6 +872,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
ItemCapabilities.AllowsPreview):
|
ItemCapabilities.AllowsPreview):
|
||||||
self.parent.PreviewController.addServiceManagerItem(
|
self.parent.PreviewController.addServiceManagerItem(
|
||||||
self.serviceItems[item][u'service_item'], 0)
|
self.serviceItems[item][u'service_item'], 0)
|
||||||
|
self.parent.LiveController.PreviewListWidget.setFocus()
|
||||||
else:
|
else:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
||||||
|
@ -25,36 +25,17 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from PyQt4.phonon import Phonon
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.ui import HideMode
|
from openlp.core.ui import HideMode, MainDisplay
|
||||||
from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
|
from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
|
||||||
ItemCapabilities, translate
|
ItemCapabilities, translate
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SlideThread(QtCore.QThread):
|
|
||||||
"""
|
|
||||||
A special Qt thread class to speed up the display of text based frames.
|
|
||||||
This is threaded so it loads the frames in background
|
|
||||||
"""
|
|
||||||
def __init__(self, parent, prefix, count):
|
|
||||||
QtCore.QThread.__init__(self, parent)
|
|
||||||
self.prefix = prefix
|
|
||||||
self.count = count
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""
|
|
||||||
Run the thread.
|
|
||||||
"""
|
|
||||||
time.sleep(1)
|
|
||||||
for i in range(0, self.count):
|
|
||||||
Receiver.send_message(u'%s_slide_cache' % self.prefix, i)
|
|
||||||
|
|
||||||
class SlideList(QtGui.QTableWidget):
|
class SlideList(QtGui.QTableWidget):
|
||||||
"""
|
"""
|
||||||
Customised version of QTableWidget which can respond to keyboard
|
Customised version of QTableWidget which can respond to keyboard
|
||||||
@ -97,7 +78,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
SlideController is the slide controller widget. This widget is what the
|
SlideController is the slide controller widget. This widget is what the
|
||||||
user uses to control the displaying of verses/slides/etc on the screen.
|
user uses to control the displaying of verses/slides/etc on the screen.
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, settingsmanager, isLive=False):
|
def __init__(self, parent, settingsmanager, screens, isLive=False):
|
||||||
"""
|
"""
|
||||||
Set up the Slide Controller.
|
Set up the Slide Controller.
|
||||||
"""
|
"""
|
||||||
@ -105,8 +86,10 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.settingsmanager = settingsmanager
|
self.settingsmanager = settingsmanager
|
||||||
self.isLive = isLive
|
self.isLive = isLive
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.mainDisplay = self.parent.displayManager.mainDisplay
|
self.screens = screens
|
||||||
self.displayManager = self.parent.displayManager
|
self.ratio = float(self.screens.current[u'size'].width()) / \
|
||||||
|
float(self.screens.current[u'size'].height())
|
||||||
|
self.display = MainDisplay(self, screens, isLive)
|
||||||
self.loopList = [
|
self.loopList = [
|
||||||
u'Start Loop',
|
u'Start Loop',
|
||||||
u'Loop Separator',
|
u'Loop Separator',
|
||||||
@ -115,13 +98,14 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.songEditList = [
|
self.songEditList = [
|
||||||
u'Edit Song',
|
u'Edit Song',
|
||||||
]
|
]
|
||||||
|
self.volume = 10
|
||||||
self.timer_id = 0
|
self.timer_id = 0
|
||||||
self.songEdit = False
|
self.songEdit = False
|
||||||
self.selectedRow = 0
|
self.selectedRow = 0
|
||||||
self.serviceItem = None
|
self.serviceItem = None
|
||||||
|
self.alertTab = None
|
||||||
self.Panel = QtGui.QWidget(parent.ControlSplitter)
|
self.Panel = QtGui.QWidget(parent.ControlSplitter)
|
||||||
self.slideList = {}
|
self.slideList = {}
|
||||||
self.canDisplay = True
|
|
||||||
# Layout for holding panel
|
# Layout for holding panel
|
||||||
self.PanelLayout = QtGui.QVBoxLayout(self.Panel)
|
self.PanelLayout = QtGui.QVBoxLayout(self.Panel)
|
||||||
self.PanelLayout.setSpacing(0)
|
self.PanelLayout.setSpacing(0)
|
||||||
@ -177,11 +161,11 @@ class SlideController(QtGui.QWidget):
|
|||||||
sizeToolbarPolicy.setHeightForWidth(
|
sizeToolbarPolicy.setHeightForWidth(
|
||||||
self.Toolbar.sizePolicy().hasHeightForWidth())
|
self.Toolbar.sizePolicy().hasHeightForWidth())
|
||||||
self.Toolbar.setSizePolicy(sizeToolbarPolicy)
|
self.Toolbar.setSizePolicy(sizeToolbarPolicy)
|
||||||
if self.isLive:
|
# if self.isLive:
|
||||||
self.Toolbar.addToolbarButton(
|
# self.Toolbar.addToolbarButton(
|
||||||
u'First Slide', u':/slides/slide_first.png',
|
# u'First Slide', u':/slides/slide_first.png',
|
||||||
translate('OpenLP.SlideController', 'Move to first'),
|
# translate('OpenLP.SlideController', 'Move to first'),
|
||||||
self.onSlideSelectedFirst)
|
# self.onSlideSelectedFirst)
|
||||||
self.Toolbar.addToolbarButton(
|
self.Toolbar.addToolbarButton(
|
||||||
u'Previous Slide', u':/slides/slide_previous.png',
|
u'Previous Slide', u':/slides/slide_previous.png',
|
||||||
translate('OpenLP.SlideController', 'Move to previous'),
|
translate('OpenLP.SlideController', 'Move to previous'),
|
||||||
@ -190,11 +174,11 @@ class SlideController(QtGui.QWidget):
|
|||||||
u'Next Slide', u':/slides/slide_next.png',
|
u'Next Slide', u':/slides/slide_next.png',
|
||||||
translate('OpenLP.SlideController', 'Move to next'),
|
translate('OpenLP.SlideController', 'Move to next'),
|
||||||
self.onSlideSelectedNext)
|
self.onSlideSelectedNext)
|
||||||
if self.isLive:
|
# if self.isLive:
|
||||||
self.Toolbar.addToolbarButton(
|
# self.Toolbar.addToolbarButton(
|
||||||
u'Last Slide', u':/slides/slide_last.png',
|
# u'Last Slide', u':/slides/slide_last.png',
|
||||||
translate('OpenLP.SlideController', 'Move to last'),
|
# translate('OpenLP.SlideController', 'Move to last'),
|
||||||
self.onSlideSelectedLast)
|
# self.onSlideSelectedLast)
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
||||||
self.HideMenu = QtGui.QToolButton(self.Toolbar)
|
self.HideMenu = QtGui.QToolButton(self.Toolbar)
|
||||||
@ -213,6 +197,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.ThemeScreen.setCheckable(True)
|
self.ThemeScreen.setCheckable(True)
|
||||||
QtCore.QObject.connect(self.ThemeScreen,
|
QtCore.QObject.connect(self.ThemeScreen,
|
||||||
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
|
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
|
||||||
|
if self.screens.display_count > 1:
|
||||||
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
|
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
|
||||||
u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
|
u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
|
||||||
self.DesktopScreen.setCheckable(True)
|
self.DesktopScreen.setCheckable(True)
|
||||||
@ -221,6 +206,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.HideMenu.setDefaultAction(self.BlankScreen)
|
self.HideMenu.setDefaultAction(self.BlankScreen)
|
||||||
self.HideMenu.menu().addAction(self.BlankScreen)
|
self.HideMenu.menu().addAction(self.BlankScreen)
|
||||||
self.HideMenu.menu().addAction(self.ThemeScreen)
|
self.HideMenu.menu().addAction(self.ThemeScreen)
|
||||||
|
if self.screens.display_count > 1:
|
||||||
self.HideMenu.menu().addAction(self.DesktopScreen)
|
self.HideMenu.menu().addAction(self.DesktopScreen)
|
||||||
if not self.isLive:
|
if not self.isLive:
|
||||||
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
||||||
@ -251,7 +237,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.DelaySpinBox.setToolTip(translate('OpenLP.SlideController',
|
self.DelaySpinBox.setToolTip(translate('OpenLP.SlideController',
|
||||||
'Delay between slides in seconds'))
|
'Delay between slides in seconds'))
|
||||||
self.ControllerLayout.addWidget(self.Toolbar)
|
self.ControllerLayout.addWidget(self.Toolbar)
|
||||||
#Build a Media ToolBar
|
# Build a Media ToolBar
|
||||||
self.Mediabar = OpenLPToolbar(self)
|
self.Mediabar = OpenLPToolbar(self)
|
||||||
self.Mediabar.addToolbarButton(
|
self.Mediabar.addToolbarButton(
|
||||||
u'Media Start', u':/slides/media_playback_start.png',
|
u'Media Start', u':/slides/media_playback_start.png',
|
||||||
@ -275,6 +261,15 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
|
self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
|
||||||
self.volumeSlider.setObjectName(u'volumeSlider')
|
self.volumeSlider.setObjectName(u'volumeSlider')
|
||||||
self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
|
self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
|
||||||
|
else:
|
||||||
|
self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
|
||||||
|
self.volumeSlider.setTickInterval(1)
|
||||||
|
self.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
|
||||||
|
self.volumeSlider.setMinimum(0)
|
||||||
|
self.volumeSlider.setMaximum(10)
|
||||||
|
self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
|
||||||
|
self.volumeSlider.setObjectName(u'volumeSlider')
|
||||||
|
self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
|
||||||
self.ControllerLayout.addWidget(self.Mediabar)
|
self.ControllerLayout.addWidget(self.Mediabar)
|
||||||
# Build the Song Toolbar
|
# Build the Song Toolbar
|
||||||
if isLive:
|
if isLive:
|
||||||
@ -322,7 +317,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.SlidePreview.setSizePolicy(sizePolicy)
|
self.SlidePreview.setSizePolicy(sizePolicy)
|
||||||
self.SlidePreview.setFixedSize(
|
self.SlidePreview.setFixedSize(
|
||||||
QtCore.QSize(self.settingsmanager.slidecontroller_image,
|
QtCore.QSize(self.settingsmanager.slidecontroller_image,
|
||||||
self.settingsmanager.slidecontroller_image / 1.3 ))
|
self.settingsmanager.slidecontroller_image / self.ratio))
|
||||||
self.SlidePreview.setFrameShape(QtGui.QFrame.Box)
|
self.SlidePreview.setFrameShape(QtGui.QFrame.Box)
|
||||||
self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain)
|
self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain)
|
||||||
self.SlidePreview.setLineWidth(1)
|
self.SlidePreview.setLineWidth(1)
|
||||||
@ -390,17 +385,37 @@ class SlideController(QtGui.QWidget):
|
|||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'config_updated'), self.refreshServiceItem)
|
QtCore.SIGNAL(u'config_updated'), self.refreshServiceItem)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'%s_slide_cache' % self.typePrefix), self.slideCache)
|
QtCore.SIGNAL(u'config_screen_changed'), self.screenSizeChanged)
|
||||||
|
if self.isLive:
|
||||||
|
QtCore.QObject.connect(self.volumeSlider,
|
||||||
|
QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
|
||||||
|
|
||||||
|
def screenSizeChanged(self):
|
||||||
|
"""
|
||||||
|
Settings dialog has changed the screen size of adjust output and
|
||||||
|
screen previews
|
||||||
|
"""
|
||||||
|
log.debug(u'screenSizeChanged live = %s' % self.isLive)
|
||||||
|
# rebuild display as screen size changed
|
||||||
|
self.display = MainDisplay(self, self.screens, self.isLive)
|
||||||
|
self.display.alertTab = self.alertTab
|
||||||
|
self.ratio = float(self.screens.current[u'size'].width()) / \
|
||||||
|
float(self.screens.current[u'size'].height())
|
||||||
|
self.display.setup()
|
||||||
|
self.SlidePreview.setFixedSize(
|
||||||
|
QtCore.QSize(self.settingsmanager.slidecontroller_image,
|
||||||
|
self.settingsmanager.slidecontroller_image / self.ratio))
|
||||||
|
|
||||||
def widthChanged(self):
|
def widthChanged(self):
|
||||||
"""
|
"""
|
||||||
Handle changes of width from the splitter between the live and preview
|
Handle changes of width from the splitter between the live and preview
|
||||||
controller. Event only issues when changes have finished
|
controller. Event only issues when changes have finished
|
||||||
"""
|
"""
|
||||||
|
log.debug(u'widthChanged live = %s' % self.isLive)
|
||||||
width = self.parent.ControlSplitter.sizes()[self.split]
|
width = self.parent.ControlSplitter.sizes()[self.split]
|
||||||
height = width * self.parent.RenderManager.screen_ratio
|
height = width * self.parent.RenderManager.screen_ratio
|
||||||
self.PreviewListWidget.setColumnWidth(0, width)
|
self.PreviewListWidget.setColumnWidth(0, width)
|
||||||
#Sort out image heights (Songs, bibles excluded)
|
# Sort out image heights (Songs, bibles excluded)
|
||||||
if self.serviceItem and not self.serviceItem.is_text():
|
if self.serviceItem and not self.serviceItem.is_text():
|
||||||
for framenumber in range(len(self.serviceItem.get_frames())):
|
for framenumber in range(len(self.serviceItem.get_frames())):
|
||||||
self.PreviewListWidget.setRowHeight(framenumber, height)
|
self.PreviewListWidget.setRowHeight(framenumber, height)
|
||||||
@ -453,8 +468,6 @@ class SlideController(QtGui.QWidget):
|
|||||||
if item.is_media():
|
if item.is_media():
|
||||||
self.Toolbar.setVisible(False)
|
self.Toolbar.setVisible(False)
|
||||||
self.Mediabar.setVisible(True)
|
self.Mediabar.setVisible(True)
|
||||||
#self.volumeSlider.setAudioOutput(
|
|
||||||
# self.mainDisplay.videoDisplay.audio)
|
|
||||||
|
|
||||||
def enablePreviewToolBar(self, item):
|
def enablePreviewToolBar(self, item):
|
||||||
"""
|
"""
|
||||||
@ -474,22 +487,20 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
Method to update the service item if the screen has changed
|
Method to update the service item if the screen has changed
|
||||||
"""
|
"""
|
||||||
log.debug(u'refreshServiceItem')
|
log.debug(u'refreshServiceItem live = %s' % self.isLive)
|
||||||
if self.serviceItem:
|
if self.serviceItem:
|
||||||
if self.serviceItem.is_text() or self.serviceItem.is_image():
|
if self.serviceItem.is_text() or self.serviceItem.is_image():
|
||||||
item = self.serviceItem
|
item = self.serviceItem
|
||||||
item.render()
|
item.render()
|
||||||
self.addServiceManagerItem(item, self.selectedRow)
|
self._processItem(item, self.selectedRow)
|
||||||
|
|
||||||
def addServiceItem(self, item):
|
def addServiceItem(self, item):
|
||||||
"""
|
"""
|
||||||
Method to install the service item into the controller
|
Method to install the service item into the controller
|
||||||
Called by plugins
|
Called by plugins
|
||||||
"""
|
"""
|
||||||
log.debug(u'addServiceItem')
|
log.debug(u'addServiceItem live = %s' % self.isLive)
|
||||||
before = time.time()
|
|
||||||
item.render()
|
item.render()
|
||||||
log.log(15, u'Rendering took %4s' % (time.time() - before))
|
|
||||||
slideno = 0
|
slideno = 0
|
||||||
if self.songEdit:
|
if self.songEdit:
|
||||||
slideno = self.selectedRow
|
slideno = self.selectedRow
|
||||||
@ -509,8 +520,8 @@ class SlideController(QtGui.QWidget):
|
|||||||
request the correct toolbar for the plugin.
|
request the correct toolbar for the plugin.
|
||||||
Called by ServiceManager
|
Called by ServiceManager
|
||||||
"""
|
"""
|
||||||
log.debug(u'addServiceManagerItem')
|
log.debug(u'addServiceManagerItem live = %s' % self.isLive)
|
||||||
#If service item is the same as the current on only change slide
|
# If service item is the same as the current on only change slide
|
||||||
if item.__eq__(self.serviceItem):
|
if item.__eq__(self.serviceItem):
|
||||||
self.PreviewListWidget.selectRow(slideno)
|
self.PreviewListWidget.selectRow(slideno)
|
||||||
self.onSlideSelected()
|
self.onSlideSelected()
|
||||||
@ -522,17 +533,15 @@ class SlideController(QtGui.QWidget):
|
|||||||
Loads a ServiceItem into the system from ServiceManager
|
Loads a ServiceItem into the system from ServiceManager
|
||||||
Display the slide number passed
|
Display the slide number passed
|
||||||
"""
|
"""
|
||||||
log.debug(u'processManagerItem')
|
log.debug(u'processManagerItem live = %s' % self.isLive)
|
||||||
self.onStopLoop()
|
self.onStopLoop()
|
||||||
#If old item was a command tell it to stop
|
# If old item was a command tell it to stop
|
||||||
if self.serviceItem:
|
if self.serviceItem:
|
||||||
if self.serviceItem.is_command():
|
if self.serviceItem.is_command():
|
||||||
Receiver.send_message(u'%s_stop' %
|
Receiver.send_message(u'%s_stop' %
|
||||||
self.serviceItem.name.lower(), [serviceItem, self.isLive])
|
self.serviceItem.name.lower(), [serviceItem, self.isLive])
|
||||||
if self.serviceItem.is_media():
|
if self.serviceItem.is_media():
|
||||||
self.onMediaStop()
|
self.onMediaStop()
|
||||||
if serviceItem.is_media():
|
|
||||||
self.onMediaStart(serviceItem)
|
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
blanked = self.BlankScreen.isChecked()
|
blanked = self.BlankScreen.isChecked()
|
||||||
else:
|
else:
|
||||||
@ -541,12 +550,8 @@ class SlideController(QtGui.QWidget):
|
|||||||
[serviceItem, self.isLive, blanked, slideno])
|
[serviceItem, self.isLive, blanked, slideno])
|
||||||
self.slideList = {}
|
self.slideList = {}
|
||||||
width = self.parent.ControlSplitter.sizes()[self.split]
|
width = self.parent.ControlSplitter.sizes()[self.split]
|
||||||
#Set pointing cursor when we have somthing to point at
|
# Set pointing cursor when we have somthing to point at
|
||||||
self.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor)
|
self.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor)
|
||||||
before = time.time()
|
|
||||||
#Clear the old serviceItem cache to release memory
|
|
||||||
if self.serviceItem and self.serviceItem is not serviceItem:
|
|
||||||
self.serviceItem.clear_cache()
|
|
||||||
self.serviceItem = serviceItem
|
self.serviceItem = serviceItem
|
||||||
self.PreviewListWidget.clear()
|
self.PreviewListWidget.clear()
|
||||||
self.PreviewListWidget.setRowCount(0)
|
self.PreviewListWidget.setRowCount(0)
|
||||||
@ -560,20 +565,19 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.PreviewListWidget.rowCount() + 1)
|
self.PreviewListWidget.rowCount() + 1)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtGui.QTableWidgetItem()
|
||||||
slideHeight = 0
|
slideHeight = 0
|
||||||
#It is a based Text Render
|
|
||||||
if self.serviceItem.is_text():
|
if self.serviceItem.is_text():
|
||||||
if frame[u'verseTag']:
|
if frame[u'verseTag']:
|
||||||
bits = frame[u'verseTag'].split(u':')
|
bits = frame[u'verseTag'].split(u':')
|
||||||
tag = u'%s\n%s' % (bits[0][0], bits[1][0:] )
|
tag = u'%s\n%s' % (bits[0][0], bits[1][0:] )
|
||||||
tag1 = u'%s%s' % (bits[0][0], bits[1][0:] )
|
tag1 = u'%s%s' % (bits[0][0], bits[1][0:] )
|
||||||
row = tag
|
row = tag
|
||||||
else:
|
if self.isLive:
|
||||||
row += 1
|
|
||||||
if self.isLive and frame[u'verseTag'] is not None:
|
|
||||||
if tag1 not in self.slideList:
|
if tag1 not in self.slideList:
|
||||||
self.slideList[tag1] = framenumber
|
self.slideList[tag1] = framenumber
|
||||||
self.SongMenu.menu().addAction(tag1,
|
self.SongMenu.menu().addAction(tag1,
|
||||||
self.onSongBarHandler)
|
self.onSongBarHandler)
|
||||||
|
else:
|
||||||
|
row += 1
|
||||||
item.setText(frame[u'text'])
|
item.setText(frame[u'text'])
|
||||||
else:
|
else:
|
||||||
label = QtGui.QLabel()
|
label = QtGui.QLabel()
|
||||||
@ -600,15 +604,14 @@ class SlideController(QtGui.QWidget):
|
|||||||
else:
|
else:
|
||||||
self.PreviewListWidget.selectRow(slideno)
|
self.PreviewListWidget.selectRow(slideno)
|
||||||
self.enableToolBar(serviceItem)
|
self.enableToolBar(serviceItem)
|
||||||
|
# Pass to display for viewing
|
||||||
|
self.display.buildHtml(self.serviceItem)
|
||||||
|
if serviceItem.is_media():
|
||||||
|
self.onMediaStart(serviceItem)
|
||||||
self.onSlideSelected()
|
self.onSlideSelected()
|
||||||
self.PreviewListWidget.setFocus()
|
self.PreviewListWidget.setFocus()
|
||||||
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix,
|
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix,
|
||||||
[serviceItem])
|
[serviceItem])
|
||||||
if self.serviceItem.is_text():
|
|
||||||
st = SlideThread(
|
|
||||||
self, self.typePrefix, len(self.serviceItem.get_frames()))
|
|
||||||
st.start()
|
|
||||||
log.log(15, u'Display Rendering took %4s' % (time.time() - before))
|
|
||||||
|
|
||||||
def onTextRequest(self):
|
def onTextRequest(self):
|
||||||
"""
|
"""
|
||||||
@ -620,7 +623,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
dataItem = {}
|
dataItem = {}
|
||||||
if self.serviceItem.is_text():
|
if self.serviceItem.is_text():
|
||||||
dataItem[u'tag'] = unicode(frame[u'verseTag'])
|
dataItem[u'tag'] = unicode(frame[u'verseTag'])
|
||||||
dataItem[u'text'] = unicode(frame[u'text'])
|
dataItem[u'text'] = unicode(frame[u'html'])
|
||||||
else:
|
else:
|
||||||
dataItem[u'tag'] = unicode(framenumber)
|
dataItem[u'tag'] = unicode(framenumber)
|
||||||
dataItem[u'text'] = u''
|
dataItem[u'text'] = u''
|
||||||
@ -630,7 +633,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
Receiver.send_message(u'slidecontroller_%s_text_response'
|
Receiver.send_message(u'slidecontroller_%s_text_response'
|
||||||
% self.typePrefix, data)
|
% self.typePrefix, data)
|
||||||
|
|
||||||
#Screen event methods
|
# Screen event methods
|
||||||
def onSlideSelectedFirst(self):
|
def onSlideSelectedFirst(self):
|
||||||
"""
|
"""
|
||||||
Go to the first slide.
|
Go to the first slide.
|
||||||
@ -664,9 +667,9 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
Allow the main display to blank the main display at startup time
|
Allow the main display to blank the main display at startup time
|
||||||
"""
|
"""
|
||||||
log.debug(u'mainDisplaySetBackground')
|
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
|
||||||
if not self.mainDisplay.primary:
|
if not self.display.primary:
|
||||||
self.onBlankDisplay(True)
|
self.onHideDisplay(True)
|
||||||
|
|
||||||
def onSlideBlank(self):
|
def onSlideBlank(self):
|
||||||
"""
|
"""
|
||||||
@ -688,6 +691,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.HideMenu.setDefaultAction(self.BlankScreen)
|
self.HideMenu.setDefaultAction(self.BlankScreen)
|
||||||
self.BlankScreen.setChecked(checked)
|
self.BlankScreen.setChecked(checked)
|
||||||
self.ThemeScreen.setChecked(False)
|
self.ThemeScreen.setChecked(False)
|
||||||
|
if self.screens.display_count > 1:
|
||||||
self.DesktopScreen.setChecked(False)
|
self.DesktopScreen.setChecked(False)
|
||||||
QtCore.QSettings().setValue(
|
QtCore.QSettings().setValue(
|
||||||
self.parent.generalSettingsSection + u'/screen blank',
|
self.parent.generalSettingsSection + u'/screen blank',
|
||||||
@ -706,6 +710,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.HideMenu.setDefaultAction(self.ThemeScreen)
|
self.HideMenu.setDefaultAction(self.ThemeScreen)
|
||||||
self.BlankScreen.setChecked(False)
|
self.BlankScreen.setChecked(False)
|
||||||
self.ThemeScreen.setChecked(checked)
|
self.ThemeScreen.setChecked(checked)
|
||||||
|
if self.screens.display_count > 1:
|
||||||
self.DesktopScreen.setChecked(False)
|
self.DesktopScreen.setChecked(False)
|
||||||
if checked:
|
if checked:
|
||||||
Receiver.send_message(u'maindisplay_hide', HideMode.Theme)
|
Receiver.send_message(u'maindisplay_hide', HideMode.Theme)
|
||||||
@ -721,6 +726,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.HideMenu.setDefaultAction(self.DesktopScreen)
|
self.HideMenu.setDefaultAction(self.DesktopScreen)
|
||||||
self.BlankScreen.setChecked(False)
|
self.BlankScreen.setChecked(False)
|
||||||
self.ThemeScreen.setChecked(False)
|
self.ThemeScreen.setChecked(False)
|
||||||
|
if self.screens.display_count > 1:
|
||||||
self.DesktopScreen.setChecked(checked)
|
self.DesktopScreen.setChecked(checked)
|
||||||
if checked:
|
if checked:
|
||||||
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
|
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
|
||||||
@ -758,13 +764,6 @@ class SlideController(QtGui.QWidget):
|
|||||||
% self.serviceItem.name.lower(),
|
% self.serviceItem.name.lower(),
|
||||||
[self.serviceItem, self.isLive])
|
[self.serviceItem, self.isLive])
|
||||||
|
|
||||||
def slideCache(self, slide):
|
|
||||||
"""
|
|
||||||
Generate a slide cache item rendered and ready for use
|
|
||||||
in the background.
|
|
||||||
"""
|
|
||||||
self.serviceItem.get_rendered_frame(int(slide))
|
|
||||||
|
|
||||||
def onSlideSelected(self):
|
def onSlideSelected(self):
|
||||||
"""
|
"""
|
||||||
Generate the preview when you click on a slide.
|
Generate the preview when you click on a slide.
|
||||||
@ -778,24 +777,15 @@ class SlideController(QtGui.QWidget):
|
|||||||
if self.serviceItem.is_command() and self.isLive:
|
if self.serviceItem.is_command() and self.isLive:
|
||||||
self.updatePreview()
|
self.updatePreview()
|
||||||
else:
|
else:
|
||||||
before = time.time()
|
frame, raw_html = self.serviceItem.get_rendered_frame(row)
|
||||||
frame = self.serviceItem.get_rendered_frame(row)
|
if self.serviceItem.is_text():
|
||||||
|
frame = self.display.text(raw_html)
|
||||||
|
else:
|
||||||
|
self.display.image(frame)
|
||||||
if isinstance(frame, QtGui.QImage):
|
if isinstance(frame, QtGui.QImage):
|
||||||
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
|
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||||
else:
|
else:
|
||||||
if isinstance(frame[u'main'], basestring):
|
self.SlidePreview.setPixmap(QtGui.QPixmap(frame))
|
||||||
self.SlidePreview.setPixmap(
|
|
||||||
QtGui.QPixmap(frame[u'main']))
|
|
||||||
else:
|
|
||||||
self.SlidePreview.setPixmap(
|
|
||||||
QtGui.QPixmap.fromImage(frame[u'main']))
|
|
||||||
log.log(
|
|
||||||
15, u'Slide Rendering took %4s' % (time.time() - before))
|
|
||||||
if self.isLive:
|
|
||||||
if self.serviceItem.is_text():
|
|
||||||
self.mainDisplay.frameView(frame, True)
|
|
||||||
else:
|
|
||||||
self.displayManager.displayImage(frame[u'main'])
|
|
||||||
self.selectedRow = row
|
self.selectedRow = row
|
||||||
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
|
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
|
||||||
row)
|
row)
|
||||||
@ -810,8 +800,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
row)
|
row)
|
||||||
|
|
||||||
def updatePreview(self):
|
def updatePreview(self):
|
||||||
rm = self.parent.RenderManager
|
if not self.screens.current[u'primary']:
|
||||||
if not rm.screens.current[u'primary']:
|
|
||||||
# Grab now, but try again in a couple of seconds if slide change
|
# Grab now, but try again in a couple of seconds if slide change
|
||||||
# is slow
|
# is slow
|
||||||
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
|
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
|
||||||
@ -819,12 +808,12 @@ class SlideController(QtGui.QWidget):
|
|||||||
else:
|
else:
|
||||||
label = self.PreviewListWidget.cellWidget(
|
label = self.PreviewListWidget.cellWidget(
|
||||||
self.PreviewListWidget.currentRow(), 1)
|
self.PreviewListWidget.currentRow(), 1)
|
||||||
|
if label:
|
||||||
self.SlidePreview.setPixmap(label.pixmap())
|
self.SlidePreview.setPixmap(label.pixmap())
|
||||||
|
|
||||||
def grabMainDisplay(self):
|
def grabMainDisplay(self):
|
||||||
rm = self.parent.RenderManager
|
|
||||||
winid = QtGui.QApplication.desktop().winId()
|
winid = QtGui.QApplication.desktop().winId()
|
||||||
rect = rm.screens.current[u'size']
|
rect = self.screens.current[u'size']
|
||||||
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(),
|
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(),
|
||||||
rect.y(), rect.width(), rect.height())
|
rect.y(), rect.width(), rect.height())
|
||||||
self.SlidePreview.setPixmap(winimg)
|
self.SlidePreview.setPixmap(winimg)
|
||||||
@ -941,7 +930,9 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaStart')
|
log.debug(u'SlideController onMediaStart')
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
Receiver.send_message(u'videodisplay_start', item)
|
file = os.path.join(item.get_frame_path(), item.get_frame_title())
|
||||||
|
self.display.video(file, self.volume)
|
||||||
|
self.volumeSlider.setValue(self.volume)
|
||||||
else:
|
else:
|
||||||
self.mediaObject.stop()
|
self.mediaObject.stop()
|
||||||
self.mediaObject.clearQueue()
|
self.mediaObject.clearQueue()
|
||||||
@ -951,13 +942,21 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.seekSlider.show()
|
self.seekSlider.show()
|
||||||
self.onMediaPlay()
|
self.onMediaPlay()
|
||||||
|
|
||||||
|
def mediaVolume(self):
|
||||||
|
"""
|
||||||
|
Respond to the release of Volume Slider
|
||||||
|
"""
|
||||||
|
log.debug(u'SlideController mediaVolume')
|
||||||
|
self.volume = self.volumeSlider.value()
|
||||||
|
self.display.videoVolume(self.volume)
|
||||||
|
|
||||||
def onMediaPause(self):
|
def onMediaPause(self):
|
||||||
"""
|
"""
|
||||||
Respond to the Pause from the media Toolbar
|
Respond to the Pause from the media Toolbar
|
||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaPause')
|
log.debug(u'SlideController onMediaPause')
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
Receiver.send_message(u'videodisplay_pause')
|
self.display.videoPause()
|
||||||
else:
|
else:
|
||||||
self.mediaObject.pause()
|
self.mediaObject.pause()
|
||||||
|
|
||||||
@ -967,7 +966,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaPlay')
|
log.debug(u'SlideController onMediaPlay')
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
Receiver.send_message(u'videodisplay_play')
|
self.display.videoPlay()
|
||||||
else:
|
else:
|
||||||
self.SlidePreview.hide()
|
self.SlidePreview.hide()
|
||||||
self.video.show()
|
self.video.show()
|
||||||
@ -979,7 +978,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaStop')
|
log.debug(u'SlideController onMediaStop')
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
Receiver.send_message(u'videodisplay_stop')
|
self.display.videoStop()
|
||||||
else:
|
else:
|
||||||
self.mediaObject.stop()
|
self.mediaObject.stop()
|
||||||
self.video.hide()
|
self.video.hide()
|
||||||
|
@ -139,13 +139,13 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'changeGlobalFromTab %s', themeName)
|
log.debug(u'changeGlobalFromTab %s', themeName)
|
||||||
for count in range (0, self.themeListWidget.count()):
|
for count in range (0, self.themeListWidget.count()):
|
||||||
#reset the old name
|
# reset the old name
|
||||||
item = self.themeListWidget.item(count)
|
item = self.themeListWidget.item(count)
|
||||||
oldName = item.text()
|
oldName = item.text()
|
||||||
newName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
newName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
if oldName != newName:
|
if oldName != newName:
|
||||||
self.themeListWidget.item(count).setText(newName)
|
self.themeListWidget.item(count).setText(newName)
|
||||||
#Set the new name
|
# Set the new name
|
||||||
if themeName == newName:
|
if themeName == newName:
|
||||||
name = unicode(translate('OpenLP.ThemeManager',
|
name = unicode(translate('OpenLP.ThemeManager',
|
||||||
'%s (default)')) % newName
|
'%s (default)')) % newName
|
||||||
@ -161,11 +161,11 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
for count in range (0, self.themeListWidget.count()):
|
for count in range (0, self.themeListWidget.count()):
|
||||||
item = self.themeListWidget.item(count)
|
item = self.themeListWidget.item(count)
|
||||||
oldName = item.text()
|
oldName = item.text()
|
||||||
#reset the old name
|
# reset the old name
|
||||||
if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()):
|
if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()):
|
||||||
self.themeListWidget.item(count).setText(
|
self.themeListWidget.item(count).setText(
|
||||||
unicode(item.data(QtCore.Qt.UserRole).toString()))
|
unicode(item.data(QtCore.Qt.UserRole).toString()))
|
||||||
#Set the new name
|
# Set the new name
|
||||||
if count == selected_row:
|
if count == selected_row:
|
||||||
self.global_theme = unicode(
|
self.global_theme = unicode(
|
||||||
self.themeListWidget.item(count).text())
|
self.themeListWidget.item(count).text())
|
||||||
@ -295,7 +295,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
path = unicode(path)
|
path = unicode(path)
|
||||||
if path:
|
if path:
|
||||||
SettingsManager.set_last_dir(self.settingsSection, path, 1)
|
SettingsManager.set_last_dir(self.settingsSection, path, 1)
|
||||||
themePath = os.path.join(path, theme + u'.theme')
|
themePath = os.path.join(path, theme + u'.thz')
|
||||||
zip = None
|
zip = None
|
||||||
try:
|
try:
|
||||||
zip = zipfile.ZipFile(themePath, u'w')
|
zip = zipfile.ZipFile(themePath, u'w')
|
||||||
@ -346,11 +346,10 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
log.debug(u'Load themes from dir')
|
log.debug(u'Load themes from dir')
|
||||||
self.themelist = []
|
self.themelist = []
|
||||||
self.themeListWidget.clear()
|
self.themeListWidget.clear()
|
||||||
#root, dirs, files = os.walk(self.path)
|
|
||||||
dirList = os.listdir(self.path)
|
dirList = os.listdir(self.path)
|
||||||
for name in dirList:
|
for name in dirList:
|
||||||
if name.endswith(u'.png'):
|
if name.endswith(u'.png'):
|
||||||
#check to see file is in theme root directory
|
# check to see file is in theme root directory
|
||||||
theme = os.path.join(self.path, name)
|
theme = os.path.join(self.path, name)
|
||||||
if os.path.exists(theme):
|
if os.path.exists(theme):
|
||||||
textName = os.path.splitext(name)[0]
|
textName = os.path.splitext(name)[0]
|
||||||
@ -660,9 +659,8 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
Call the RenderManager to build a Sample Image
|
Call the RenderManager to build a Sample Image
|
||||||
"""
|
"""
|
||||||
log.debug(u'generateImage %s ', themedata)
|
log.debug(u'generateImage \n%s ', themedata)
|
||||||
frame = self.parent.RenderManager.generate_preview(themedata)
|
return self.parent.RenderManager.generate_preview(themedata)
|
||||||
return frame
|
|
||||||
|
|
||||||
def getPreviewImage(self, theme):
|
def getPreviewImage(self, theme):
|
||||||
"""
|
"""
|
||||||
@ -732,8 +730,6 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
theme.display_slideTransition = theme.display_slideTransition
|
theme.display_slideTransition = theme.display_slideTransition
|
||||||
theme.font_footer_color = theme.font_footer_color.strip()
|
theme.font_footer_color = theme.font_footer_color.strip()
|
||||||
theme.font_footer_height = int(theme.font_footer_height.strip())
|
theme.font_footer_height = int(theme.font_footer_height.strip())
|
||||||
theme.font_footer_indentation = \
|
|
||||||
int(theme.font_footer_indentation.strip())
|
|
||||||
theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
|
theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
|
||||||
theme.font_footer_name = theme.font_footer_name.strip()
|
theme.font_footer_name = theme.font_footer_name.strip()
|
||||||
#theme.font_footer_override
|
#theme.font_footer_override
|
||||||
@ -746,7 +742,6 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
theme.font_main_color = theme.font_main_color.strip()
|
theme.font_main_color = theme.font_main_color.strip()
|
||||||
theme.font_main_height = int(theme.font_main_height.strip())
|
theme.font_main_height = int(theme.font_main_height.strip())
|
||||||
theme.font_main_italics = str_to_bool(theme.font_main_italics)
|
theme.font_main_italics = str_to_bool(theme.font_main_italics)
|
||||||
theme.font_main_indentation = int(theme.font_main_indentation)
|
|
||||||
theme.font_main_name = theme.font_main_name.strip()
|
theme.font_main_name = theme.font_main_name.strip()
|
||||||
#theme.font_main_override
|
#theme.font_main_override
|
||||||
theme.font_main_proportion = int(theme.font_main_proportion.strip())
|
theme.font_main_proportion = int(theme.font_main_proportion.strip())
|
||||||
@ -757,3 +752,8 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
#theme.theme_mode
|
#theme.theme_mode
|
||||||
theme.theme_name = theme.theme_name.strip()
|
theme.theme_name = theme.theme_name.strip()
|
||||||
#theme.theme_version
|
#theme.theme_version
|
||||||
|
# Remove the Transparent settings as they are not relevent
|
||||||
|
if theme.background_mode == u'transparent':
|
||||||
|
theme.background_mode = u'opaque'
|
||||||
|
theme.background_type = u'solid'
|
||||||
|
theme.background_startColor = u'#000000'
|
||||||
|
@ -80,9 +80,10 @@ class AlertsPlugin(Plugin):
|
|||||||
log.info(u'Alerts Initialising')
|
log.info(u'Alerts Initialising')
|
||||||
Plugin.initialise(self)
|
Plugin.initialise(self)
|
||||||
self.toolsAlertItem.setVisible(True)
|
self.toolsAlertItem.setVisible(True)
|
||||||
|
self.liveController.alertTab = self.alertsTab
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
log.info(u'Plugin Finalise')
|
log.info(u'Alerts Finalising')
|
||||||
Plugin.finalise(self)
|
Plugin.finalise(self)
|
||||||
self.toolsAlertItem.setVisible(False)
|
self.toolsAlertItem.setVisible(False)
|
||||||
|
|
||||||
|
@ -32,18 +32,9 @@ from openlp.core.lib import Receiver, translate
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
HTMLCODE = u"""
|
|
||||||
<p style=\"color:%s;
|
|
||||||
background-color:%s;
|
|
||||||
font-family:%s;
|
|
||||||
font-size: %spt; \">
|
|
||||||
%s
|
|
||||||
</p>
|
|
||||||
"""
|
|
||||||
|
|
||||||
class AlertsManager(QtCore.QObject):
|
class AlertsManager(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
AlertsTab is the Alerts settings tab in the settings dialog.
|
AlertsManager manages the settings of Alerts.
|
||||||
"""
|
"""
|
||||||
log.info(u'Alert Manager loaded')
|
log.info(u'Alert Manager loaded')
|
||||||
|
|
||||||
@ -94,10 +85,7 @@ class AlertsManager(QtCore.QObject):
|
|||||||
return
|
return
|
||||||
text = self.alertList.pop(0)
|
text = self.alertList.pop(0)
|
||||||
alertTab = self.parent.alertsTab
|
alertTab = self.parent.alertsTab
|
||||||
text = HTMLCODE % (alertTab.font_color, alertTab.bg_color,
|
self.parent.liveController.display.alert(text)
|
||||||
alertTab.font_face, alertTab.font_size, text)
|
|
||||||
self.parent.previewController.parent.displayManager.addAlert(text,
|
|
||||||
alertTab.location)
|
|
||||||
# check to see if we have a timer running
|
# check to see if we have a timer running
|
||||||
if self.timer_id == 0:
|
if self.timer_id == 0:
|
||||||
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
|
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
|
||||||
@ -111,10 +99,8 @@ class AlertsManager(QtCore.QObject):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'timer event')
|
log.debug(u'timer event')
|
||||||
alertTab = self.parent.alertsTab
|
|
||||||
if event.timerId() == self.timer_id:
|
if event.timerId() == self.timer_id:
|
||||||
self.parent.previewController.parent.displayManager.addAlert(u'',
|
self.parent.liveController.display.alert(u'')
|
||||||
alertTab.location)
|
|
||||||
self.killTimer(self.timer_id)
|
self.killTimer(self.timer_id)
|
||||||
self.timer_id = 0
|
self.timer_id = 0
|
||||||
self.generateAlert()
|
self.generateAlert()
|
||||||
|
@ -261,7 +261,7 @@ class AlertsTab(SettingsTab):
|
|||||||
self.font_face = unicode(settings.value(
|
self.font_face = unicode(settings.value(
|
||||||
u'font face', QtCore.QVariant(QtGui.QFont().family())).toString())
|
u'font face', QtCore.QVariant(QtGui.QFont().family())).toString())
|
||||||
self.location = settings.value(
|
self.location = settings.value(
|
||||||
u'location', QtCore.QVariant(0)).toInt()[0]
|
u'location', QtCore.QVariant(1)).toInt()[0]
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
self.FontSizeSpinBox.setValue(self.font_size)
|
self.FontSizeSpinBox.setValue(self.font_size)
|
||||||
self.TimeoutSpinBox.setValue(self.timeout)
|
self.TimeoutSpinBox.setValue(self.timeout)
|
||||||
@ -296,3 +296,4 @@ class AlertsTab(SettingsTab):
|
|||||||
self.FontPreview.setFont(font)
|
self.FontPreview.setFont(font)
|
||||||
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
|
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
|
||||||
(self.bg_color, self.font_color))
|
(self.bg_color, self.font_color))
|
||||||
|
|
||||||
|
@ -504,16 +504,16 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
dual_text = self._decodeQtObject(reference, 'dual_text')
|
dual_text = self._decodeQtObject(reference, 'dual_text')
|
||||||
if self.parent.settings_tab.display_style == 1:
|
if self.parent.settings_tab.display_style == 1:
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||||
u'(', u')')
|
u'{su}(', u'){/su}')
|
||||||
elif self.parent.settings_tab.display_style == 2:
|
elif self.parent.settings_tab.display_style == 2:
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||||
u'{', u'}')
|
u'{su}{', u'}{/su}')
|
||||||
elif self.parent.settings_tab.display_style == 3:
|
elif self.parent.settings_tab.display_style == 3:
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||||
u'[', u']')
|
u'{su}[', u']{/su}')
|
||||||
else:
|
else:
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||||
u'', u'')
|
u'{su}', u'{/su}')
|
||||||
old_chapter = chapter
|
old_chapter = chapter
|
||||||
footer = u'%s (%s %s)' % (book, version, copyright)
|
footer = u'%s (%s %s)' % (book, version, copyright)
|
||||||
# If not found add to footer
|
# If not found add to footer
|
||||||
@ -532,7 +532,11 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
else:
|
else:
|
||||||
# If we are 'Verse Per Line' then force a new line.
|
# If we are 'Verse Per Line' then force a new line.
|
||||||
if self.parent.settings_tab.layout_style == 1:
|
if self.parent.settings_tab.layout_style == 1:
|
||||||
text = text + u'\n\n'
|
text = text + u'\n'
|
||||||
|
else:
|
||||||
|
# split the line but do not replace line breaks in renderer
|
||||||
|
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
||||||
|
text = text + u'\n'
|
||||||
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
|
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
|
||||||
# If we are 'Verse Per Slide' then create a new slide.
|
# If we are 'Verse Per Slide' then create a new slide.
|
||||||
if self.parent.settings_tab.layout_style == 0:
|
if self.parent.settings_tab.layout_style == 0:
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import build_icon, translate
|
from openlp.core.lib import build_icon, translate
|
||||||
|
from openlp.core.ui import SpellTextEdit
|
||||||
|
|
||||||
class Ui_CustomEditDialog(object):
|
class Ui_CustomEditDialog(object):
|
||||||
def setupUi(self, customEditDialog):
|
def setupUi(self, customEditDialog):
|
||||||
@ -73,7 +74,7 @@ class Ui_CustomEditDialog(object):
|
|||||||
self.editLayout3.setSpacing(8)
|
self.editLayout3.setSpacing(8)
|
||||||
self.editLayout3.setMargin(0)
|
self.editLayout3.setMargin(0)
|
||||||
self.editLayout3.setObjectName(u'editLayout3')
|
self.editLayout3.setObjectName(u'editLayout3')
|
||||||
self.verseTextEdit = QtGui.QTextEdit(self.editWidget)
|
self.verseTextEdit = SpellTextEdit(self)
|
||||||
self.verseTextEdit.setObjectName(u'verseTextEdit')
|
self.verseTextEdit.setObjectName(u'verseTextEdit')
|
||||||
self.editLayout3.addWidget(self.verseTextEdit)
|
self.editLayout3.addWidget(self.verseTextEdit)
|
||||||
self.buttonWidget = QtGui.QWidget(self.editWidget)
|
self.buttonWidget = QtGui.QWidget(self.editWidget)
|
||||||
|
@ -110,8 +110,14 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
u':/slides/slide_blank.png',
|
u':/slides/slide_blank.png',
|
||||||
translate('ImagePlugin.MediaItem', 'Replace Live Background'),
|
translate('ImagePlugin.MediaItem', 'Replace Live Background'),
|
||||||
self.onReplaceClick, False)
|
self.onReplaceClick, False)
|
||||||
|
self.resetButton = self.toolbar.addToolbarButton(
|
||||||
|
translate('ImagePlugin.MediaItem', u'Reset Background'),
|
||||||
|
u':/system/system_close.png',
|
||||||
|
translate('ImagePlugin.MediaItem', 'Reset Live Background'),
|
||||||
|
self.onResetClick, False)
|
||||||
# Add the song widget to the page layout
|
# Add the song widget to the page layout
|
||||||
self.pageLayout.addWidget(self.ImageWidget)
|
self.pageLayout.addWidget(self.ImageWidget)
|
||||||
|
self.resetButton.setVisible(False)
|
||||||
|
|
||||||
def onDeleteClick(self):
|
def onDeleteClick(self):
|
||||||
"""
|
"""
|
||||||
@ -169,6 +175,10 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def onResetClick(self):
|
||||||
|
self.resetButton.setVisible(False)
|
||||||
|
self.parent.liveController.display.resetImage()
|
||||||
|
|
||||||
def onReplaceClick(self):
|
def onReplaceClick(self):
|
||||||
if check_item_selected(self.listView,
|
if check_item_selected(self.listView,
|
||||||
translate('ImagePlugin.MediaItem',
|
translate('ImagePlugin.MediaItem',
|
||||||
@ -178,7 +188,8 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
bitem = self.listView.item(item.row())
|
bitem = self.listView.item(item.row())
|
||||||
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
|
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
|
||||||
frame = QtGui.QImage(unicode(filename))
|
frame = QtGui.QImage(unicode(filename))
|
||||||
self.parent.displayManager.displayImageWithText(frame)
|
self.parent.liveController.display.image(frame)
|
||||||
|
self.resetButton.setVisible(True)
|
||||||
|
|
||||||
def onPreviewClick(self):
|
def onPreviewClick(self):
|
||||||
MediaManagerItem.onPreviewClick(self)
|
MediaManagerItem.onPreviewClick(self)
|
||||||
|
@ -97,8 +97,17 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
u':/slides/slide_blank.png',
|
u':/slides/slide_blank.png',
|
||||||
translate('MediaPlugin.MediaItem', 'Replace Live Background'),
|
translate('MediaPlugin.MediaItem', 'Replace Live Background'),
|
||||||
self.onReplaceClick, False)
|
self.onReplaceClick, False)
|
||||||
|
self.resetButton = self.toolbar.addToolbarButton(
|
||||||
|
u'Reset Background', u':/system/system_close.png',
|
||||||
|
translate('ImagePlugin.MediaItem', 'Reset Live Background'),
|
||||||
|
self.onResetClick, False)
|
||||||
# Add the song widget to the page layout
|
# Add the song widget to the page layout
|
||||||
self.pageLayout.addWidget(self.ImageWidget)
|
self.pageLayout.addWidget(self.ImageWidget)
|
||||||
|
self.resetButton.setVisible(False)
|
||||||
|
|
||||||
|
def onResetClick(self):
|
||||||
|
self.resetButton.setVisible(False)
|
||||||
|
self.parent.liveController.display.resetVideo()
|
||||||
|
|
||||||
def onReplaceClick(self):
|
def onReplaceClick(self):
|
||||||
if check_item_selected(self.listView,
|
if check_item_selected(self.listView,
|
||||||
@ -106,7 +115,8 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
'You must select a media file to replace the background with.')):
|
'You must select a media file to replace the background with.')):
|
||||||
item = self.listView.currentItem()
|
item = self.listView.currentItem()
|
||||||
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
self.parent.displayManager.displayVideo(filename)
|
self.parent.liveController.display.video(filename, 0)
|
||||||
|
self.resetButton.setVisible(True)
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None):
|
def generateSlideData(self, service_item, item=None):
|
||||||
if item is None:
|
if item is None:
|
||||||
|
@ -422,7 +422,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.VerseDeleteButton.setEnabled(True)
|
self.VerseDeleteButton.setEnabled(True)
|
||||||
|
|
||||||
def onVerseAddButtonClicked(self):
|
def onVerseAddButtonClicked(self):
|
||||||
self.verse_form.setVerse(u'', True)
|
# Allow insert button as you do not know if multiple verses will
|
||||||
|
# be entered.
|
||||||
|
self.verse_form.setVerse(u'')
|
||||||
if self.verse_form.exec_():
|
if self.verse_form.exec_():
|
||||||
afterText, verse, subVerse = self.verse_form.getVerse()
|
afterText, verse, subVerse = self.verse_form.getVerse()
|
||||||
data = u'%s:%s' % (verse, subVerse)
|
data = u'%s:%s' % (verse, subVerse)
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import build_icon, translate
|
from openlp.core.lib import build_icon, translate
|
||||||
|
from openlp.core.ui import SpellTextEdit
|
||||||
from openlp.plugins.songs.lib import VerseType
|
from openlp.plugins.songs.lib import VerseType
|
||||||
|
|
||||||
class Ui_EditVerseDialog(object):
|
class Ui_EditVerseDialog(object):
|
||||||
@ -38,7 +39,7 @@ class Ui_EditVerseDialog(object):
|
|||||||
self.EditVerseLayout.setSpacing(8)
|
self.EditVerseLayout.setSpacing(8)
|
||||||
self.EditVerseLayout.setMargin(8)
|
self.EditVerseLayout.setMargin(8)
|
||||||
self.EditVerseLayout.setObjectName(u'EditVerseLayout')
|
self.EditVerseLayout.setObjectName(u'EditVerseLayout')
|
||||||
self.VerseTextEdit = QtGui.QPlainTextEdit(EditVerseDialog)
|
self.VerseTextEdit = SpellTextEdit(EditVerseDialog)
|
||||||
self.VerseTextEdit.setObjectName(u'VerseTextEdit')
|
self.VerseTextEdit.setObjectName(u'VerseTextEdit')
|
||||||
self.EditVerseLayout.addWidget(self.VerseTextEdit)
|
self.EditVerseLayout.addWidget(self.VerseTextEdit)
|
||||||
self.VerseTypeLayout = QtGui.QHBoxLayout()
|
self.VerseTypeLayout = QtGui.QHBoxLayout()
|
||||||
|
@ -45,6 +45,9 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||||||
"""
|
"""
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
QtCore.QObject.connect(self.VerseTextEdit,
|
||||||
|
QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
|
||||||
|
self.contextMenu)
|
||||||
QtCore.QObject.connect(
|
QtCore.QObject.connect(
|
||||||
self.InsertButton,
|
self.InsertButton,
|
||||||
QtCore.SIGNAL(u'clicked()'),
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
@ -57,6 +60,10 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||||||
)
|
)
|
||||||
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---')
|
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---')
|
||||||
|
|
||||||
|
def contextMenu(self, point):
|
||||||
|
item = self.serviceManagerList.itemAt(point)
|
||||||
|
print item
|
||||||
|
|
||||||
def insertVerse(self, title, num=1):
|
def insertVerse(self, title, num=1):
|
||||||
if self.VerseTextEdit.textCursor().columnNumber() != 0:
|
if self.VerseTextEdit.textCursor().columnNumber() != 0:
|
||||||
self.VerseTextEdit.insertPlainText(u'\n')
|
self.VerseTextEdit.insertPlainText(u'\n')
|
||||||
|
91
resources/Fedora/191/OpenLP.spec
Normal file
91
resources/Fedora/191/OpenLP.spec
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
%{!?python_sitelib:%global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
|
||||||
|
|
||||||
|
Summary: Open source Church presentation and lyrics projection application
|
||||||
|
Name: OpenLP
|
||||||
|
Version: 1.9.1.1
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Source0: http://downloads.sourceforge.net/openlp/openlp/%{version}/%{name}-%{version}.tar.gz
|
||||||
|
License: GPLv2
|
||||||
|
Group: Applications/Multimedia
|
||||||
|
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||||
|
BuildArch: noarch
|
||||||
|
|
||||||
|
URL: http://openlp.org/
|
||||||
|
|
||||||
|
BuildRequires: desktop-file-utils
|
||||||
|
BuildRequires: python2-devel
|
||||||
|
BuildRequires: python-setuptools
|
||||||
|
|
||||||
|
Requires: PyQt4
|
||||||
|
Requires: phonon
|
||||||
|
Requires: python-BeautifulSoup
|
||||||
|
Requires: python-chardet
|
||||||
|
Requires: python-lxml
|
||||||
|
Requires: python-sqlalchemy
|
||||||
|
Requires: hicolor-icon-theme
|
||||||
|
|
||||||
|
%description
|
||||||
|
OpenLP is a church presentation software, for lyrics projection software,
|
||||||
|
used to display slides of Songs, Bible verses, videos, images, and
|
||||||
|
presentations (if OpenOffice.org is installed) using a computer and projector.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q
|
||||||
|
|
||||||
|
%build
|
||||||
|
python setup.py build
|
||||||
|
|
||||||
|
%install
|
||||||
|
rm -rf %{buildroot}
|
||||||
|
python setup.py install --skip-build -O1 --root %{buildroot}
|
||||||
|
|
||||||
|
install -m644 -p -D resources/images/openlp-logo-16x16.png \
|
||||||
|
%{buildroot}%{_datadir}/icons/hicolor/16x16/apps/openlp.png
|
||||||
|
install -m644 -p -D resources/images/openlp-logo-32x32.png \
|
||||||
|
%{buildroot}%{_datadir}/icons/hicolor/32x32/apps/openlp.png
|
||||||
|
install -m644 -p -D resources/images/openlp-logo-48x48.png \
|
||||||
|
%{buildroot}%{_datadir}/icons/hicolor/48x48/apps/openlp.png
|
||||||
|
install -m644 -p -D resources/images/openlp-logo.svg \
|
||||||
|
%{buildroot}%{_datadir}/icons/hicolor/scalable/apps/openlp.svg
|
||||||
|
|
||||||
|
desktop-file-install \
|
||||||
|
--dir %{buildroot}/%{_datadir}/applications \
|
||||||
|
resources/openlp.desktop
|
||||||
|
|
||||||
|
mv %{buildroot}%{_bindir}/bible-1to2-converter.py \
|
||||||
|
%{buildroot}%{_bindir}/bible-1to2-converter
|
||||||
|
mv %{buildroot}%{_bindir}/openlp-1to2-converter.py \
|
||||||
|
%{buildroot}%{_bindir}/openlp-1to2-converter
|
||||||
|
mv %{buildroot}%{_bindir}/openlp-remoteclient.py \
|
||||||
|
%{buildroot}%{_bindir}/openlp-remoteclient
|
||||||
|
mv %{buildroot}%{_bindir}/openlp.pyw %{buildroot}%{_bindir}/openlp
|
||||||
|
|
||||||
|
|
||||||
|
%post
|
||||||
|
touch --no-create %{_datadir}/icons/hicolor ||:
|
||||||
|
gtk-update-icon-cache -q %{_datadir}/icons/hicolor 2> /dev/null ||:
|
||||||
|
|
||||||
|
%postun
|
||||||
|
touch --no-create %{_datadir}/icons/hicolor ||:
|
||||||
|
gtk-update-icon-cache -q %{_datadir}/icons/hicolor 2> /dev/null ||:
|
||||||
|
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf %{buildroot}
|
||||||
|
|
||||||
|
%files
|
||||||
|
%defattr(-,root,root)
|
||||||
|
%doc copyright.txt LICENSE
|
||||||
|
%{_bindir}/bible-1to2-converter
|
||||||
|
%{_bindir}/openlp-1to2-converter
|
||||||
|
%{_bindir}/openlp-remoteclient
|
||||||
|
%{_bindir}/openlp
|
||||||
|
%{_datadir}/applications/openlp.desktop
|
||||||
|
%{_datadir}/icons/hicolor/*/apps/openlp.*
|
||||||
|
%{python_sitelib}/openlp/
|
||||||
|
%{python_sitelib}/OpenLP-%{version}*.egg-info
|
||||||
|
%doc documentation/*.txt
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Sun Mar 28 2010 Tim Bentley <timbentley@openlp.org> 1.9.1.1
|
||||||
|
- Initial build version - Alpha 1 Release
|
Loading…
Reference in New Issue
Block a user