forked from openlp/openlp
New branch
This commit is contained in:
commit
5c3d32cfd9
@ -165,15 +165,41 @@ def context_menu_separator(base):
|
||||
action.setSeparator(True)
|
||||
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 retuns
|
||||
it as a byte stream.
|
||||
|
||||
``image``
|
||||
The image to converted.
|
||||
"""
|
||||
byte_array = QtCore.QByteArray()
|
||||
buffer = QtCore.QBuffer(byte_array) #// use buffer to store pixmap into byteArray
|
||||
buffer.open(QtCore.QIODevice.WriteOnly)
|
||||
if isinstance(image, QtGui.QImage):
|
||||
pixmap = QtGui.QPixmap.fromImage(image)
|
||||
else:
|
||||
pixmap = QtGui.QPixmap(image)
|
||||
pixmap.save(buffer, "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.
|
||||
|
||||
``image``
|
||||
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)
|
||||
if not preview.isNull():
|
||||
#Only resize if different size
|
||||
if preview.width() == width and preview.height == height:
|
||||
return preview
|
||||
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
||||
@ -183,7 +209,7 @@ def resize_image(image, width, height):
|
||||
# and move it to the centre of the preview space
|
||||
new_image = QtGui.QImage(width, height,
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
new_image.fill(QtCore.Qt.black)
|
||||
new_image.fill(background)
|
||||
painter = QtGui.QPainter(new_image)
|
||||
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
|
||||
return new_image
|
||||
@ -212,6 +238,7 @@ from settingstab import SettingsTab
|
||||
from serviceitem import ServiceItem
|
||||
from serviceitem import ServiceItemType
|
||||
from serviceitem import ItemCapabilities
|
||||
from htmlbuilder import build_html
|
||||
from toolbar import OpenLPToolbar
|
||||
from dockwidget import OpenLPDockWidget
|
||||
from theme import ThemeLevel, ThemeXML
|
||||
|
171
openlp/core/lib/htmlbuilder.py
Normal file
171
openlp/core/lib/htmlbuilder.py
Normal file
@ -0,0 +1,171 @@
|
||||
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
|
||||
# Thompson, Jon Tibble, Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
}
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
</style>
|
||||
<script language="javascript">
|
||||
var t = null;
|
||||
|
||||
function startfade(newtext){
|
||||
var text1 = document.getElementById('lyrics');
|
||||
var text2 = document.getElementById('lyrics2');
|
||||
if(text2.style.opacity==''||parseFloat(text2.style.opacity) < 0.5){
|
||||
text2.innerHTML = text1.innerHTML;
|
||||
text2.style.opacity = text1.style.opacity;
|
||||
}
|
||||
text1.style.opacity = 0;
|
||||
text1.innerHTML = newtext;
|
||||
if(t!=null)
|
||||
clearTimeout(t);
|
||||
t = setTimeout('fade()', 50);
|
||||
}
|
||||
function fade(){
|
||||
var text1 = document.getElementById('lyrics');
|
||||
var text2 = document.getElementById('lyrics2');
|
||||
if(parseFloat(text1.style.opacity) < 1)
|
||||
text1.style.opacity = parseFloat(text1.style.opacity) + 0.02;
|
||||
if(parseFloat(text2.style.opacity) > 0)
|
||||
text2.style.opacity = parseFloat(text2.style.opacity) - 0.02;
|
||||
if((parseFloat(text1.style.opacity) < 1)||(parseFloat(text2.style.opacity) > 0))
|
||||
t = setTimeout('fade()', 50);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="lyrics" class="lyrics"></div>
|
||||
<div id="lyrics2" class="lyrics"></div>
|
||||
<div id="alert"></div>
|
||||
<video id="video"></video>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
def build_html(theme, screen, alert, image):
|
||||
width = screen[u'size'].width()
|
||||
height = screen[u'size'].height()
|
||||
html = HTMLSRC % (build_video(theme, width, height, alert),
|
||||
build_image(theme, width, height, alert),
|
||||
build_lyrics(theme, width, height, alert),
|
||||
build_alert(theme, width, height, alert),
|
||||
build_image(theme, width, height, alert),
|
||||
build_image_src(theme, width, height, alert, image))
|
||||
print html
|
||||
return html
|
||||
|
||||
def build_video(theme, width, height, alert):
|
||||
video = """
|
||||
#video {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 640px
|
||||
height: 480px;
|
||||
z-index:1;
|
||||
}
|
||||
"""
|
||||
return video
|
||||
|
||||
def build_image(theme, width, height, alert):
|
||||
image = """
|
||||
#image {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: %spx;
|
||||
height: %spx;
|
||||
z-index:2;
|
||||
}
|
||||
"""
|
||||
return image % (width, height)
|
||||
|
||||
def build_image_src(theme, width, height, alert, image):
|
||||
# <img src="" height="480" width="640" />
|
||||
image_src = """
|
||||
<img src="data:image/png;base64,%s">";
|
||||
"""
|
||||
return image_src % image_to_byte(image)
|
||||
|
||||
def build_lyrics(theme, width, height, alert):
|
||||
lyrics = """
|
||||
#lyrics {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 640px;
|
||||
height: 480px;
|
||||
z-index:3;
|
||||
%s;
|
||||
%s;
|
||||
font-family %s;
|
||||
font-size: %spx;
|
||||
}
|
||||
"""
|
||||
lyrics_html = u''
|
||||
shadow = u''
|
||||
outline = u''
|
||||
if theme:
|
||||
if theme.display_shadow:
|
||||
shadow = u'text-shadow: %spx %spx %spx %s' %\
|
||||
(theme.display_shadow_size, theme.display_shadow_size,
|
||||
theme.display_shadow_size, theme.display_shadow_color)
|
||||
if theme.display_outline:
|
||||
# 1px is the blur radius
|
||||
outline = u'text-outline: %spx 1px %s' %\
|
||||
(theme.display_outline_size, theme.display_outline_color)
|
||||
lyrics_html = lyrics % (shadow, outline, theme.font_main_name, theme.font_main_proportion)
|
||||
print lyrics_html
|
||||
return lyrics_html
|
||||
|
||||
def build_alert(theme, width, height, alert):
|
||||
alert = """
|
||||
#alert {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 70px;
|
||||
width: %spx;
|
||||
height: 10px;
|
||||
z-index:4;
|
||||
font-size: 50px;
|
||||
}
|
||||
#alert p {
|
||||
background-color: red;
|
||||
}
|
||||
"""
|
||||
return alert % (width)
|
@ -145,8 +145,46 @@ class Renderer(object):
|
||||
for line in lines:
|
||||
text.append(line)
|
||||
split_text = self.pre_render_text(text)
|
||||
|
||||
doc = QtGui.QTextDocument()
|
||||
doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height()))
|
||||
df = doc.defaultFont()
|
||||
df.setPixelSize(self._theme.font_main_proportion)
|
||||
df.setFamily(self._theme.font_main_name)
|
||||
main_weight = 50
|
||||
if self._theme.font_main_weight == u'Bold':
|
||||
main_weight = 75
|
||||
df.setWeight(main_weight)
|
||||
doc.setDefaultFont(df)
|
||||
myCursor = QtGui.QTextCursor(doc)
|
||||
layout = doc.documentLayout()
|
||||
formatted = []
|
||||
if self._theme.display_horizontalAlign == 2:
|
||||
shell = "<p align=center>%s</font></p>"
|
||||
elif self._theme.display_horizontalAlign == 1:
|
||||
shell = "<p align=right>%s</font></p>"
|
||||
else:
|
||||
shell = "<p>%s</p>"
|
||||
temp_text = u''
|
||||
old_html_text = u''
|
||||
page = []
|
||||
for line in text:
|
||||
# mark line ends
|
||||
temp_text = temp_text + line + u'<br>'
|
||||
html_text = shell % temp_text
|
||||
doc.setHtml(html_text)
|
||||
#Text too long so gone to next mage
|
||||
if layout.pageCount() != 1:
|
||||
page.append(shell % old_html_text)
|
||||
formatted.append(page)
|
||||
temp_text = line
|
||||
old_html_text = temp_text
|
||||
page.append(shell % old_html_text)
|
||||
formatted.append(page)
|
||||
|
||||
log.debug(u'format_slide - End')
|
||||
return split_text
|
||||
#return split_text
|
||||
return formatted
|
||||
|
||||
def pre_render_text(self, text):
|
||||
metrics = QtGui.QFontMetrics(self.main_font)
|
||||
|
@ -98,9 +98,11 @@ class RenderManager(object):
|
||||
def set_override_theme(self, theme):
|
||||
"""
|
||||
Set the appropriate theme depending on the theme level.
|
||||
Called by the service item when building a display frame
|
||||
|
||||
``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)
|
||||
if self.theme_level == ThemeLevel.Global:
|
||||
@ -127,6 +129,7 @@ class RenderManager(object):
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
self.renderer.set_theme(self.themedata)
|
||||
self.build_text_rectangle(self.themedata)
|
||||
return self.renderer.bg_frame
|
||||
|
||||
def build_text_rectangle(self, theme):
|
||||
"""
|
||||
@ -180,8 +183,9 @@ class RenderManager(object):
|
||||
footer.append(u'CCLI 123456')
|
||||
formatted = self.renderer.format_slide(verse, False)
|
||||
#Only Render the first slide page returned
|
||||
return self.renderer.generate_frame_from_lines(formatted[0],
|
||||
footer)[u'main']
|
||||
image = self.previewDisplay.preview(self.renderer.bg_frame, verse, self.themedata)
|
||||
return image #self.renderer.generate_frame_from_lines(formatted[0],
|
||||
#footer)[u'main']
|
||||
|
||||
def format_slide(self, words):
|
||||
"""
|
||||
@ -207,7 +211,9 @@ class RenderManager(object):
|
||||
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)
|
||||
image = self.previewDisplay.preview(self.renderer.bg_frame,
|
||||
main_text[0], self.themedata)
|
||||
return image
|
||||
|
||||
def calculate_default(self, screen):
|
||||
"""
|
||||
|
@ -167,21 +167,22 @@ class ServiceItem(object):
|
||||
has generated by the render method above.
|
||||
"""
|
||||
log.debug(u'render individual')
|
||||
changed = False
|
||||
if self.theme is None:
|
||||
self.render_manager.set_override_theme(None)
|
||||
bg_image = self.render_manager.set_override_theme(None)
|
||||
else:
|
||||
self.render_manager.set_override_theme(self.theme)
|
||||
format = self._display_frames[row][u'text'].split(u'\n')
|
||||
bg_image = self.render_manager.set_override_theme(self.theme)
|
||||
raw_html = 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,
|
||||
if raw_html[0]:
|
||||
frame = self.render_manager.generate_slide(raw_html,
|
||||
self.raw_footer)
|
||||
else:
|
||||
frame = self.render_manager.generate_slide(format, u'')
|
||||
frame = self.render_manager.generate_slide(raw_html, u'')
|
||||
self.cache[row] = frame
|
||||
return frame
|
||||
return bg_image, frame, raw_html[0]
|
||||
|
||||
def add_from_image(self, path, title, image):
|
||||
"""
|
||||
@ -370,7 +371,7 @@ class ServiceItem(object):
|
||||
if self.service_item_type == ServiceItemType.Text:
|
||||
return self.render_individual(row)
|
||||
else:
|
||||
return {u'main':self._raw_frames[row][u'image'], u'trans':None}
|
||||
return self._raw_frames[row][u'image']
|
||||
|
||||
def get_frame_title(self, row=0):
|
||||
"""
|
||||
|
@ -40,8 +40,6 @@ from slidecontroller import HideMode
|
||||
from servicenoteform import ServiceNoteForm
|
||||
from serviceitemeditform import ServiceItemEditForm
|
||||
from screen import ScreenList
|
||||
from maindisplay import MainDisplay
|
||||
from maindisplay import VideoDisplay
|
||||
from maindisplay import DisplayManager
|
||||
from amendthemeform import AmendThemeForm
|
||||
from slidecontroller import SlideController
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -527,7 +527,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||
self.songsSettingsSection = u'songs'
|
||||
self.serviceNotSaved = False
|
||||
self.settingsmanager = SettingsManager(screens)
|
||||
self.displayManager = DisplayManager(screens)
|
||||
self.displayManager = DisplayManager(self, screens)
|
||||
self.aboutForm = AboutForm(self, applicationVersion)
|
||||
self.settingsForm = SettingsForm(self.screens, self, self)
|
||||
self.recentFiles = QtCore.QStringList()
|
||||
|
@ -590,6 +590,7 @@ class SlideController(QtGui.QWidget):
|
||||
else:
|
||||
self.PreviewListWidget.selectRow(slideno)
|
||||
self.enableToolBar(serviceItem)
|
||||
#Reset the display html
|
||||
self.onSlideSelected()
|
||||
self.PreviewListWidget.setFocus()
|
||||
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix,
|
||||
@ -769,23 +770,19 @@ class SlideController(QtGui.QWidget):
|
||||
self.updatePreview()
|
||||
else:
|
||||
before = time.time()
|
||||
frame = self.serviceItem.get_rendered_frame(row)
|
||||
changed, frame, raw_html = self.serviceItem.get_rendered_frame(row)
|
||||
if isinstance(frame, QtGui.QImage):
|
||||
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||
else:
|
||||
if isinstance(frame[u'main'], basestring):
|
||||
self.SlidePreview.setPixmap(
|
||||
QtGui.QPixmap(frame[u'main']))
|
||||
else:
|
||||
self.SlidePreview.setPixmap(
|
||||
QtGui.QPixmap.fromImage(frame[u'main']))
|
||||
self.SlidePreview.setPixmap(QtGui.QPixmap(frame))
|
||||
log.log(
|
||||
15, u'Slide Rendering took %4s' % (time.time() - before))
|
||||
if self.isLive:
|
||||
if self.serviceItem.is_text():
|
||||
self.mainDisplay.frameView(frame, True)
|
||||
self.displayManager.buildHtml(changed)
|
||||
self.displayManager.text(raw_html)
|
||||
else:
|
||||
self.displayManager.displayImage(frame[u'main'])
|
||||
self.displayManager.displayImage(frame)
|
||||
self.selectedRow = row
|
||||
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
|
||||
row)
|
||||
|
@ -521,16 +521,16 @@ class BibleMediaItem(MediaManagerItem):
|
||||
permission = self._decodeQtObject(reference, 'permission')
|
||||
if self.parent.settings_tab.display_style == 1:
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||
u'(u', u')')
|
||||
u'<sup>(u', u')</sup>')
|
||||
elif self.parent.settings_tab.display_style == 2:
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||
u'{', u'}')
|
||||
u'<sup>{', u'}</sup>')
|
||||
elif self.parent.settings_tab.display_style == 3:
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||
u'[', u']')
|
||||
u'<sup>[', u']</sup>')
|
||||
else:
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
||||
u'', u'')
|
||||
u'<sup>', u'</sup>')
|
||||
old_chapter = chapter
|
||||
footer = u'%s (%s %s)' % (book, version, copyright)
|
||||
#If not found add to footer
|
||||
|
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