diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index b25b2a3f4..f4afeaff6 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -305,21 +305,37 @@ class Renderer(object): The theme to build a text block for. """ log.debug(u'_build_text_rectangle') - main_rect = None - footer_rect = None + main_rect = self.get_main_rectangle(theme) + footer_rect = self.get_main_rectangle(theme) + self._set_text_rectangle(main_rect, footer_rect) + + def get_main_rectangle(self, theme): + """ + Calculates the placement and size of the main rectangle. + + ``theme`` + The theme information + """ if not theme.font_main_override: - main_rect = QtCore.QRect(10, 0, self.width - 20, self.footer_start) + return QtCore.QRect(10, 0, self.width - 20, self.footer_start) else: - main_rect = QtCore.QRect(theme.font_main_x, theme.font_main_y, + return QtCore.QRect(theme.font_main_x, theme.font_main_y, theme.font_main_width - 1, theme.font_main_height - 1) + + def get_footer_rectangle(self, theme): + """ + Calculates the placement and size of the footer rectangle. + + ``theme`` + The theme information + """ if not theme.font_footer_override: - footer_rect = QtCore.QRect(10, self.footer_start, self.width - 20, + return QtCore.QRect(10, self.footer_start, self.width - 20, self.height - self.footer_start) else: - footer_rect = QtCore.QRect(theme.font_footer_x, + return QtCore.QRect(theme.font_footer_x, theme.font_footer_y, theme.font_footer_width - 1, theme.font_footer_height - 1) - self._set_text_rectangle(main_rect, footer_rect) def _set_text_rectangle(self, rect_main, rect_footer): """ diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 3170e0a93..510d71cde 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -364,6 +364,11 @@ class ServiceItem(object): """ self._uuid = other._uuid self.notes = other.notes + # Copy theme over if present. + if other.theme is not None: + self.theme = other.theme + self._new_item() + self.render() if self.is_capable(ItemCapabilities.HasBackgroundAudio): log.debug(self.background_audio) diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index e754480e0..7d2dfa0ba 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -54,6 +54,7 @@ class HideMode(object): from firsttimeform import FirstTimeForm from firsttimelanguageform import FirstTimeLanguageForm +from themelayoutform import ThemeLayoutForm from themeform import ThemeForm from filerenameform import FileRenameForm from starttimeform import StartTimeForm diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index c9f058351..8ad2db9c2 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -1160,7 +1160,6 @@ class ServiceManager(QtGui.QWidget): # if not passed set to config value if expand is None: expand = self.expandTabs - item.render() item.from_service = True if replace: sitem, child = self.findServiceItem() @@ -1169,6 +1168,7 @@ class ServiceManager(QtGui.QWidget): self.repaintServiceList(sitem, child) self.mainwindow.liveController.replaceServiceManagerItem(item) else: + item.render() # nothing selected for dnd if self.dropPosition == 0: if isinstance(item, list): diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index ae05f141e..9ccd91d08 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -33,6 +33,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, translate from openlp.core.lib.theme import BackgroundType, BackgroundGradientType from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.ui import ThemeLayoutForm from openlp.core.utils import get_images_filter from themewizard import Ui_ThemeWizard @@ -58,6 +59,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.registerFields() self.updateThemeAllowed = True self.temp_background_filename = u'' + self.themeLayoutForm = ThemeLayoutForm(self) QtCore.QObject.connect(self.backgroundComboBox, QtCore.SIGNAL(u'currentIndexChanged(int)'), self.onBackgroundComboBoxCurrentIndexChanged) @@ -88,6 +90,9 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.onShadowCheckCheckBoxStateChanged) QtCore.QObject.connect(self.footerColorButton, QtCore.SIGNAL(u'clicked()'), self.onFooterColorButtonClicked) + QtCore.QObject.connect(self, + QtCore.SIGNAL(u'customButtonClicked(int)'), + self.onCustom1ButtonClicked) QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onMainPositionCheckBoxStateChanged) @@ -229,6 +234,10 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): """ Detects Page changes and updates as approprate. """ + if self.page(pageId) == self.areaPositionPage: + self.setOption(QtGui.QWizard.HaveCustomButton1, True) + else: + self.setOption(QtGui.QWizard.HaveCustomButton1, False) if self.page(pageId) == self.previewPage: self.updateTheme() frame = self.thememanager.generateImage(self.theme) @@ -236,6 +245,25 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.displayAspectRatio = float(frame.width()) / frame.height() self.resizeEvent() + def onCustom1ButtonClicked(self, number): + """ + Generate layout preview and display the form. + """ + self.updateTheme() + width = self.thememanager.mainwindow.renderer.width + height = self.thememanager.mainwindow.renderer.height + pixmap = QtGui.QPixmap(width, height) + pixmap.fill(QtCore.Qt.white) + paint = QtGui.QPainter(pixmap) + paint.setPen(QtGui.QPen(QtCore.Qt.blue, 2)) + paint.drawRect(self.thememanager.mainwindow.renderer. + get_main_rectangle(self.theme)) + paint.setPen(QtGui.QPen(QtCore.Qt.red, 2)) + paint.drawRect(self.thememanager.mainwindow.renderer. + get_footer_rectangle(self.theme)) + paint.end() + self.themeLayoutForm.exec_(pixmap) + def onOutlineCheckCheckBoxStateChanged(self, state): """ Change state as Outline check box changed diff --git a/openlp/core/ui/themelayoutdialog.py b/openlp/core/ui/themelayoutdialog.py new file mode 100644 index 000000000..5be08ad65 --- /dev/null +++ b/openlp/core/ui/themelayoutdialog.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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 PyQt4 import QtCore, QtGui + +from openlp.core.lib import translate +from openlp.core.lib.ui import create_accept_reject_button_box + + +class Ui_ThemeLayoutDialog(object): + def setupUi(self, themeLayoutDialog): + themeLayoutDialog.setObjectName(u'themeLayoutDialogDialog') + #themeLayoutDialog.resize(300, 200) + self.previewLayout = QtGui.QVBoxLayout(themeLayoutDialog) + self.previewLayout.setObjectName(u'PreviewLayout') + self.previewArea = QtGui.QWidget(themeLayoutDialog) + self.previewArea.setObjectName(u'PreviewArea') + self.previewAreaLayout = QtGui.QGridLayout(self.previewArea) + self.previewAreaLayout.setMargin(0) + self.previewAreaLayout.setColumnStretch(0, 1) + self.previewAreaLayout.setRowStretch(0, 1) + self.previewAreaLayout.setObjectName(u'PreviewAreaLayout') + self.themeDisplayLabel = QtGui.QLabel(self.previewArea) + self.themeDisplayLabel.setFrameShape(QtGui.QFrame.Box) + self.themeDisplayLabel.setScaledContents(True) + self.themeDisplayLabel.setObjectName(u'ThemeDisplayLabel') + self.previewAreaLayout.addWidget(self.themeDisplayLabel) + self.previewLayout.addWidget(self.previewArea) + self.mainColourLabel = QtGui.QLabel(self.previewArea) + self.mainColourLabel.setObjectName(u'MainColourLabel') + self.previewLayout.addWidget(self.mainColourLabel) + self.footerColourLabel = QtGui.QLabel(self.previewArea) + self.footerColourLabel.setObjectName(u'FooterColourLabel') + self.previewLayout.addWidget(self.footerColourLabel) + self.buttonBox = QtGui.QDialogButtonBox(themeLayoutDialog) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(u'ButtonBox') + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'), + themeLayoutDialog.accept) + self.previewLayout.addWidget(self.buttonBox) + self.retranslateUi(themeLayoutDialog) + QtCore.QMetaObject.connectSlotsByName(themeLayoutDialog) + + def retranslateUi(self, themeLayoutDialog): + themeLayoutDialog.setWindowTitle( + translate('OpenLP.StartTimeForm', 'Theme Layout')) + self.mainColourLabel.setText(translate('OpenLP.StartTimeForm', + 'The blue box shows the main area.')) + self.footerColourLabel.setText(translate('OpenLP.StartTimeForm', + 'The red box shows the footer.')) + diff --git a/openlp/core/ui/themelayoutform.py b/openlp/core/ui/themelayoutform.py new file mode 100644 index 000000000..6f77d31da --- /dev/null +++ b/openlp/core/ui/themelayoutform.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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 PyQt4 import QtGui, QtCore + +from themelayoutdialog import Ui_ThemeLayoutDialog + +from openlp.core.lib import translate +from openlp.core.lib.ui import UiStrings, critical_error_message_box + +class ThemeLayoutForm(QtGui.QDialog, Ui_ThemeLayoutDialog): + """ + The exception dialog + """ + def __init__(self, parent): + QtGui.QDialog.__init__(self, parent) + self.setupUi(self) + + def exec_(self, image): + """ + Run the Dialog with correct heading. + """ + pixmap = image.scaledToHeight(400, QtCore.Qt.SmoothTransformation) + self.themeDisplayLabel.setPixmap(image) + displayAspectRatio = float(image.width()) / image.height() + self.themeDisplayLabel.setFixedSize(400, 400 / displayAspectRatio ) + return QtGui.QDialog.exec_(self) + + def accept(self): + return QtGui.QDialog.accept(self) + diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index c7cba0ebd..1135db274 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -38,7 +38,8 @@ class Ui_ThemeWizard(object): themeWizard.setModal(True) themeWizard.setWizardStyle(QtGui.QWizard.ModernStyle) themeWizard.setOptions(QtGui.QWizard.IndependentPages | - QtGui.QWizard.NoBackButtonOnStartPage) + QtGui.QWizard.NoBackButtonOnStartPage | + QtGui.QWizard.HaveCustomButton1) self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum) # Welcome Page @@ -535,6 +536,9 @@ class Ui_ThemeWizard(object): translate('OpenLP.ThemeWizard', 'px')) self.footerPositionCheckBox.setText( translate('OpenLP.ThemeWizard', 'Use default location')) + themeWizard.setOption(QtGui.QWizard.HaveCustomButton1, False) + themeWizard.setButtonText(QtGui.QWizard.CustomButton1, + translate('OpenLP.ThemeWizard', 'Layout Preview')) self.previewPage.setTitle( translate('OpenLP.ThemeWizard', 'Save and Preview')) self.previewPage.setSubTitle( diff --git a/openlp/plugins/remotes/html/stage.js b/openlp/plugins/remotes/html/stage.js index 09c82c49b..8db92b39a 100644 --- a/openlp/plugins/remotes/html/stage.js +++ b/openlp/plugins/remotes/html/stage.js @@ -121,11 +121,11 @@ window.OpenLP = { $("#nextslide").html(text); } }, - updateClock: function() { + updateClock: function(data) { var div = $("#clock"); var t = new Date(); var h = t.getHours(); - if (h > 12) + if (data.results.twelve && h > 12) h = h - 12; var m = t.getMinutes(); if (m < 10) @@ -136,7 +136,7 @@ window.OpenLP = { $.getJSON( "/api/poll", function (data, status) { - OpenLP.updateClock(); + OpenLP.updateClock(data); if (OpenLP.currentItem != data.results.item) { OpenLP.currentItem = data.results.item; OpenLP.loadSlides(); diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index c81c83d92..522c354b8 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -315,7 +315,7 @@ class HttpConnection(object): """ log.debug(u'ready to read socket') if self.socket.canReadLine(): - data = unicode(self.socket.readLine()) + data = unicode(self.socket.readLine()).encode(u'utf-8') log.debug(u'received: ' + data) words = data.split(u' ') response = None @@ -397,7 +397,9 @@ class HttpConnection(object): result = { u'slide': self.parent.current_slide or 0, u'item': self.parent.current_item._uuid \ - if self.parent.current_item else u'' + if self.parent.current_item else u'', + u'twelve':QtCore.QSettings().value( + u'remotes/twelve hour', QtCore.QVariant(True)).toBool() } return HttpResponse(json.dumps({u'results': result}), {u'Content-Type': u'application/json'}) diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py index 03781ae06..95bb27f1c 100644 --- a/openlp/plugins/remotes/lib/remotetab.py +++ b/openlp/plugins/remotes/lib/remotetab.py @@ -57,6 +57,9 @@ class RemoteTab(SettingsTab): QtCore.QObject.connect(self.addressEdit, QtCore.SIGNAL(u'textChanged(const QString&)'), self.setUrls) self.serverSettingsLayout.addRow(self.addressLabel, self.addressEdit) + self.twelveHourCheckBox = QtGui.QCheckBox(self.serverSettingsGroupBox) + self.twelveHourCheckBox.setObjectName(u'twelveHourCheckBox') + self.serverSettingsLayout.addRow(self.twelveHourCheckBox) self.portLabel = QtGui.QLabel(self.serverSettingsGroupBox) self.portLabel.setObjectName(u'portLabel') self.portSpinBox = QtGui.QSpinBox(self.serverSettingsGroupBox) @@ -80,6 +83,9 @@ class RemoteTab(SettingsTab): self.leftLayout.addWidget(self.serverSettingsGroupBox) self.leftLayout.addStretch() self.rightLayout.addStretch() + QtCore.QObject.connect(self.twelveHourCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onTwelveHourCheckBoxChanged) def retranslateUi(self): self.serverSettingsGroupBox.setTitle( @@ -92,6 +98,9 @@ class RemoteTab(SettingsTab): 'Remote URL:')) self.stageUrlLabel.setText(translate('RemotePlugin.RemoteTab', 'Stage view URL:')) + self.twelveHourCheckBox.setText( + translate('RemotePlugin.RemoteTab', + 'Display stage time in 12h format')) def setUrls(self): ipAddress = u'localhost' @@ -123,6 +132,10 @@ class RemoteTab(SettingsTab): self.addressEdit.setText( QtCore.QSettings().value(self.settingsSection + u'/ip address', QtCore.QVariant(ZERO_URL)).toString()) + self.twelveHour = QtCore.QSettings().value( + self.settingsSection + u'/twelve hour', + QtCore.QVariant(True)).toBool() + self.twelveHourCheckBox.setChecked(self.twelveHour) self.setUrls() def save(self): @@ -130,3 +143,11 @@ class RemoteTab(SettingsTab): QtCore.QVariant(self.portSpinBox.value())) QtCore.QSettings().setValue(self.settingsSection + u'/ip address', QtCore.QVariant(self.addressEdit.text())) + QtCore.QSettings().setValue(self.settingsSection + u'/twelve hour', + QtCore.QVariant(self.twelveHour)) + + def onTwelveHourCheckBoxChanged(self, check_state): + self.twelveHour = False + # we have a set value convert to True/False + if check_state == QtCore.Qt.Checked: + self.twelveHour = True diff --git a/resources/forms/themelayout.ui b/resources/forms/themelayout.ui new file mode 100644 index 000000000..2152fc5d0 --- /dev/null +++ b/resources/forms/themelayout.ui @@ -0,0 +1,81 @@ + + + ThemeLayout + + + + 0 + 0 + 400 + 300 + + + + Theme Layout + + + + + 50 + 260 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + 10 + 361 + 231 + + + + + + + + + + + buttonBox + accepted() + ThemeLayout + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ThemeLayout + reject() + + + 316 + 260 + + + 286 + 274 + + + + +