2008-12-01 13:15:31 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
2008-10-23 19:49:13 +00:00
|
|
|
"""
|
|
|
|
OpenLP - Open Source Lyrics Projection
|
|
|
|
Copyright (c) 2008 Raoul Snyman
|
2009-04-22 19:46:10 +00:00
|
|
|
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
|
2008-10-23 19:49:13 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
"""
|
2009-03-29 14:38:23 +00:00
|
|
|
import logging
|
2009-04-15 04:58:51 +00:00
|
|
|
import os, os.path
|
2008-10-07 19:12:32 +00:00
|
|
|
import sys
|
2009-05-11 05:09:43 +00:00
|
|
|
|
|
|
|
from datetime import *
|
2008-10-07 19:12:32 +00:00
|
|
|
from PyQt4 import QtGui, QtCore, Qt
|
|
|
|
|
|
|
|
from copy import copy
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
class Renderer:
|
2009-03-29 14:38:23 +00:00
|
|
|
|
|
|
|
global log
|
|
|
|
log=logging.getLogger(u'Renderer')
|
|
|
|
log.info(u'Renderer Loaded')
|
2008-10-07 19:12:32 +00:00
|
|
|
"""All the functions for rendering a set of words onto a Device Context
|
|
|
|
|
|
|
|
How to use:
|
2009-05-01 05:02:53 +00:00
|
|
|
set the words to be displayed with a call to format_slide() - this returns an array of screenfuls of data
|
2008-10-07 19:12:32 +00:00
|
|
|
set a theme (if you need) with set_theme
|
|
|
|
tell it which DC to render to with set_DC()
|
|
|
|
set the borders of where you want the text (if not the whole DC) with set_text_rectangle()
|
|
|
|
tell it to render a particular screenfull with render_screen(n)
|
|
|
|
|
|
|
|
"""
|
2009-05-16 10:24:03 +00:00
|
|
|
def __init__(self):
|
|
|
|
self._rect = None
|
|
|
|
self._debug = 0
|
|
|
|
self.words = None
|
2008-10-07 19:12:32 +00:00
|
|
|
self._right_margin = 64 # the amount of right indent
|
2009-05-16 10:24:03 +00:00
|
|
|
self._shadow_offset = 5
|
|
|
|
self._outline_offset = 2
|
|
|
|
self.theme_name = None
|
|
|
|
self._theme = None
|
|
|
|
self._bg_image_filename = None
|
|
|
|
self._frame = None
|
|
|
|
self._bg_frame = None
|
|
|
|
self.bg_image = None
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
def set_debug(self, debug):
|
|
|
|
self._debug=debug
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
def set_theme(self, theme):
|
2009-05-16 10:24:03 +00:00
|
|
|
"""
|
|
|
|
External API to pass in the theme to be used
|
|
|
|
"""
|
|
|
|
log.debug(u'set theme')
|
|
|
|
self._theme = theme
|
|
|
|
self._bg_frame = None
|
|
|
|
self.theme_name = theme.theme_name
|
2009-04-06 18:45:45 +00:00
|
|
|
if theme.background_type == u'image':
|
2009-05-16 10:24:03 +00:00
|
|
|
if theme.background_filename is not None:
|
2009-04-28 19:20:03 +00:00
|
|
|
self.set_bg_image(theme.background_filename)
|
2008-10-07 19:12:32 +00:00
|
|
|
|
|
|
|
def set_bg_image(self, filename):
|
2009-04-06 18:45:45 +00:00
|
|
|
log.debug(u'set bg image %s', filename)
|
2009-05-16 19:47:30 +00:00
|
|
|
self._bg_image_filename = str(filename)
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._frame is not None:
|
2008-10-07 19:12:32 +00:00
|
|
|
self.scale_bg_image()
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
def scale_bg_image(self):
|
2009-05-16 10:24:03 +00:00
|
|
|
assert self._frame
|
|
|
|
image = QtGui.QImage(self._bg_image_filename)
|
2008-10-07 19:12:32 +00:00
|
|
|
# rescale and offset
|
2009-05-16 10:24:03 +00:00
|
|
|
imw = image.width()
|
|
|
|
imh = image.height()
|
|
|
|
dcw = self._frame.width()+1
|
|
|
|
dch = self._frame.height()
|
|
|
|
imratio = imw/float(imh)
|
|
|
|
dcratio = dcw/float(dch)
|
2009-04-06 18:45:45 +00:00
|
|
|
log.debug(u'Image scaling params %s %s %s %s %s %s', imw, imh, imratio, dcw, dch, dcratio)
|
2008-10-07 19:12:32 +00:00
|
|
|
if imratio > dcratio:
|
2009-05-16 10:24:03 +00:00
|
|
|
scale = dcw/float(imw)
|
2008-10-07 19:12:32 +00:00
|
|
|
elif imratio < dcratio:
|
2009-05-16 10:24:03 +00:00
|
|
|
scale = dch/float(imh)
|
2008-10-07 19:12:32 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
scale = dcw/float(imw) # either will do
|
|
|
|
neww = int(round(imw*scale))
|
|
|
|
newh = int(round(imh*scale))
|
2008-10-07 19:12:32 +00:00
|
|
|
self.background_offsetx=(dcw-neww)/2
|
|
|
|
self.background_offsety=(dch-newh)/2
|
2009-05-16 10:24:03 +00:00
|
|
|
self.bg_image=QtGui.QPixmap.fromImage(image.scaled(QtCore.QSize(neww, newh), Qt.Qt.KeepAspectRatio))
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
def set_frame_dest(self, frame_width, frame_height, preview=False):
|
|
|
|
"""
|
|
|
|
External API to pass the frame size to be painted
|
|
|
|
"""
|
|
|
|
if preview == True:
|
|
|
|
self._bg_frame = None
|
|
|
|
log.debug(u'set frame dest (frame) w %d h %d',frame_width, frame_height)
|
|
|
|
self._frame = QtGui.QPixmap(frame_width, frame_height)
|
2008-10-07 19:12:32 +00:00
|
|
|
if self._bg_image_filename is not None:
|
|
|
|
self.scale_bg_image()
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._bg_frame is None:
|
|
|
|
self._render_background()
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2009-04-25 06:11:15 +00:00
|
|
|
def format_slide(self, words, footer):
|
2009-05-16 10:24:03 +00:00
|
|
|
"""
|
|
|
|
External API to sort out the text to pe placed on the frame
|
|
|
|
"""
|
2009-04-25 06:11:15 +00:00
|
|
|
log.debug(u'format_slide %s', words)
|
2009-05-16 10:24:03 +00:00
|
|
|
verses = []
|
2009-05-01 05:02:53 +00:00
|
|
|
verses_text = words.splitlines()
|
2009-05-16 10:24:03 +00:00
|
|
|
for verse in verses_text:
|
|
|
|
lines = verse.split(u'\n')
|
2009-04-25 06:11:15 +00:00
|
|
|
verses.append(self.split_set_of_lines(lines, footer)[0])
|
|
|
|
self.words = verses
|
2009-05-16 10:24:03 +00:00
|
|
|
verses_text = []
|
2008-10-07 19:12:32 +00:00
|
|
|
for v in verses:
|
2009-04-06 18:45:45 +00:00
|
|
|
verses_text.append(u'\n'.join(v).lstrip()) # remove first \n
|
2008-10-07 19:12:32 +00:00
|
|
|
return verses_text
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
def render_screen(self, screennum):
|
2009-04-06 18:45:45 +00:00
|
|
|
log.debug(u'render screen\n %s %s ', screennum, self.words[screennum])
|
2009-05-16 10:24:03 +00:00
|
|
|
t = 0.0
|
|
|
|
words = self.words[screennum]
|
|
|
|
retval = self._render_lines(words)
|
2008-10-07 19:12:32 +00:00
|
|
|
return retval
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2009-04-09 19:12:47 +00:00
|
|
|
def set_text_rectangle(self, rect_main, rect_footer):
|
2008-10-07 19:12:32 +00:00
|
|
|
""" Sets the rectangle within which text should be rendered"""
|
2009-05-16 10:24:03 +00:00
|
|
|
self._rect = rect_main
|
|
|
|
self._rect_footer = rect_footer
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
def _render_background(self):
|
2009-05-16 10:24:03 +00:00
|
|
|
"""
|
|
|
|
Generate a background frame to the same size as the frame to be used
|
|
|
|
Results cached for performance reasons.
|
|
|
|
"""
|
2008-10-07 19:12:32 +00:00
|
|
|
assert(self._theme)
|
2009-05-16 10:24:03 +00:00
|
|
|
self._bg_frame = QtGui.QPixmap(self._frame.width(), self._frame.height())
|
2009-04-06 18:45:45 +00:00
|
|
|
log.debug(u'render background %s ', self._theme.background_type)
|
2009-05-11 05:09:43 +00:00
|
|
|
bef = datetime.now()
|
2009-05-16 10:24:03 +00:00
|
|
|
painter = QtGui.QPainter()
|
|
|
|
painter.begin(self._bg_frame)
|
2009-04-06 18:45:45 +00:00
|
|
|
if self._theme.background_type == u'solid':
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.fillRect(self._frame.rect(), QtGui.QColor(self._theme.background_color))
|
2009-04-11 07:33:45 +00:00
|
|
|
elif self._theme.background_type == u'gradient' : # gradient
|
2009-04-06 18:45:45 +00:00
|
|
|
gradient = None
|
2009-04-19 20:07:52 +00:00
|
|
|
if self._theme.background_direction == u'horizontal':
|
2009-05-16 10:24:03 +00:00
|
|
|
w = int(self._frame.width())/2
|
|
|
|
gradient = QtGui.QLinearGradient(w, 0, w, self._frame.height()) # vertical
|
2009-04-19 20:07:52 +00:00
|
|
|
elif self._theme.background_direction == u'vertical':
|
2009-05-16 10:24:03 +00:00
|
|
|
h = int(self._frame.height())/2
|
|
|
|
gradient = QtGui.QLinearGradient(0, h, self._frame.width(), h) # Horizontal
|
2009-04-06 18:45:45 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
w = int(self._frame.width())/2
|
|
|
|
h = int(self._frame.height())/2
|
2009-04-06 18:45:45 +00:00
|
|
|
gradient = QtGui.QRadialGradient(w, h, w) # Circular
|
|
|
|
|
2009-04-15 04:58:51 +00:00
|
|
|
gradient.setColorAt(0, QtGui.QColor(self._theme.background_startColor))
|
|
|
|
gradient.setColorAt(1, QtGui.QColor(self._theme.background_endColor))
|
2009-04-06 18:45:45 +00:00
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.setBrush(QtGui.QBrush(gradient))
|
2009-03-29 14:38:23 +00:00
|
|
|
rectPath = QtGui.QPainterPath()
|
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
max_x = self._frame.width()
|
|
|
|
max_y = self._frame.height()
|
2009-03-29 14:38:23 +00:00
|
|
|
rectPath.moveTo(0, 0)
|
2009-04-06 18:45:45 +00:00
|
|
|
rectPath.lineTo(0, max_y)
|
|
|
|
rectPath.lineTo(max_x, max_y)
|
|
|
|
rectPath.lineTo(max_x, 0)
|
|
|
|
|
2009-03-29 14:38:23 +00:00
|
|
|
rectPath.closeSubpath()
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.drawPath(rectPath)
|
2008-10-07 19:12:32 +00:00
|
|
|
|
2009-04-06 18:45:45 +00:00
|
|
|
elif self._theme.background_type== u'image': # image
|
2009-05-16 10:24:03 +00:00
|
|
|
r = self._frame.rect()
|
2009-04-06 18:45:45 +00:00
|
|
|
log.debug(u'Image size details %d %d %d %d ', r.x(), r.y(), r.width(),r.height())
|
2009-04-15 04:58:51 +00:00
|
|
|
#log.debug(u' Background Parameter %d ', self._theme.background_color1)
|
|
|
|
#if self._theme.background_color1 is not None:
|
2009-05-16 10:24:03 +00:00
|
|
|
# p.fillRect(self._frame.rect(), self._theme.background_borderColor)
|
|
|
|
if self.bg_image is not None:
|
|
|
|
painter.drawPixmap(self.background_offsetx,self.background_offsety, self.bg_image)
|
2009-04-28 19:20:03 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.fillRect(self._frame.rect(), QtGui.QColor(u'#000000'))
|
|
|
|
painter.end()
|
2009-05-11 05:09:43 +00:00
|
|
|
aft = datetime.now()
|
|
|
|
print "background time", bef, aft, aft-bef
|
|
|
|
log.debug(u'render background finish')
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2009-04-25 06:11:15 +00:00
|
|
|
def split_set_of_lines(self, lines, footer):
|
2008-10-07 19:12:32 +00:00
|
|
|
|
|
|
|
"""Given a list of lines, decide how to split them best if they don't all fit on the screen
|
|
|
|
- this is done by splitting at 1/2, 1/3 or 1/4 of the set
|
|
|
|
If it doesn't fit, even at this size, just split at each opportunity
|
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
We'll do this by getting the bounding box of each line, and then summing them appropriately
|
2008-10-07 19:12:32 +00:00
|
|
|
Returns a list of [lists of lines], one set for each screenful
|
|
|
|
"""
|
2009-04-25 06:11:15 +00:00
|
|
|
log.debug(u'Split set of lines')
|
2008-10-07 19:12:32 +00:00
|
|
|
bboxes = []
|
|
|
|
for line in lines:
|
2009-04-25 06:11:15 +00:00
|
|
|
bboxes.append(self._render_single_line(line, footer))
|
2009-05-16 10:24:03 +00:00
|
|
|
|
|
|
|
numlines = len(lines)
|
|
|
|
bottom = self._rect.bottom()
|
2008-10-07 19:12:32 +00:00
|
|
|
for ratio in (numlines, numlines/2, numlines/3, numlines/4):
|
2009-05-16 10:24:03 +00:00
|
|
|
good = 1
|
|
|
|
startline = 0
|
|
|
|
endline = startline + ratio
|
|
|
|
while (endline <= numlines):
|
|
|
|
by = 0
|
2009-04-15 04:58:51 +00:00
|
|
|
for (x, y) in bboxes[startline:endline]:
|
2009-05-16 10:24:03 +00:00
|
|
|
by += y
|
2009-05-16 19:47:30 +00:00
|
|
|
print "A ", by, bottom , bboxes
|
2008-10-07 19:12:32 +00:00
|
|
|
if by > bottom:
|
|
|
|
good=0
|
|
|
|
break
|
2009-05-16 10:24:03 +00:00
|
|
|
startline += ratio
|
|
|
|
endline = startline+ratio
|
|
|
|
if good == 1:
|
2008-10-07 19:12:32 +00:00
|
|
|
break
|
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
retval = []
|
|
|
|
numlines_per_page = ratio
|
2008-10-07 19:12:32 +00:00
|
|
|
if good:
|
2009-05-16 10:24:03 +00:00
|
|
|
c = 0
|
|
|
|
thislines = []
|
2008-10-07 19:12:32 +00:00
|
|
|
while c < numlines:
|
|
|
|
thislines.append(lines[c])
|
2009-05-16 10:24:03 +00:00
|
|
|
c += 1
|
2008-10-07 19:12:32 +00:00
|
|
|
if len(thislines) == numlines_per_page:
|
|
|
|
retval.append(thislines)
|
2009-05-16 10:24:03 +00:00
|
|
|
thislines = []
|
2008-10-07 19:12:32 +00:00
|
|
|
else:
|
2009-03-29 14:38:23 +00:00
|
|
|
# log.debug(u" "Just split where you can"
|
2009-05-16 10:24:03 +00:00
|
|
|
retval = []
|
|
|
|
startline = 0
|
|
|
|
endline = startline+1
|
|
|
|
while (endline <= numlines):
|
|
|
|
by = 0
|
2009-04-15 04:58:51 +00:00
|
|
|
for (x, y) in bboxes[startline:endline]:
|
2009-05-16 10:24:03 +00:00
|
|
|
by += y
|
2008-10-07 19:12:32 +00:00
|
|
|
if by > bottom:
|
|
|
|
retval.append(lines[startline:endline-1])
|
2009-05-16 10:24:03 +00:00
|
|
|
startline = endline-1
|
|
|
|
endline = startline # gets incremented below
|
|
|
|
by = 0
|
|
|
|
endline += 1
|
2008-10-07 19:12:32 +00:00
|
|
|
return retval
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2009-04-09 19:12:47 +00:00
|
|
|
def _correctAlignment(self, rect, bbox):
|
2009-05-16 10:24:03 +00:00
|
|
|
x = rect.left()
|
2009-04-09 19:12:47 +00:00
|
|
|
if int(self._theme.display_verticalAlign) == 0: # top align
|
|
|
|
y = rect.top()
|
2009-04-22 17:28:32 +00:00
|
|
|
elif int(self._theme.display_verticalAlign) == 2: # bottom align
|
2009-05-16 10:24:03 +00:00
|
|
|
y = rect.bottom()-bbox.height()
|
2009-04-22 17:28:32 +00:00
|
|
|
elif int(self._theme.display_verticalAlign) == 1: # centre align
|
2009-05-16 10:24:03 +00:00
|
|
|
y = rect.top()+(rect.height()-bbox.height())/2
|
2009-04-09 19:12:47 +00:00
|
|
|
else:
|
|
|
|
assert(0, u'Invalid value for theme.VerticalAlign:%s' % self._theme.display_verticalAlign)
|
|
|
|
return x, y
|
|
|
|
|
2009-04-28 19:20:03 +00:00
|
|
|
def render_lines(self, lines, footer_lines=None):
|
2008-10-07 19:12:32 +00:00
|
|
|
"""render a set of lines according to the theme, return bounding box"""
|
2009-05-11 05:09:43 +00:00
|
|
|
log.debug(u'render_lines - Start')
|
2008-10-07 19:12:32 +00:00
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
bbox = self._render_lines_unaligned(lines, False) # Main font
|
2009-04-28 19:20:03 +00:00
|
|
|
if footer_lines is not None:
|
2009-05-16 10:24:03 +00:00
|
|
|
bbox1 = self._render_lines_unaligned(footer_lines, True) # Footer Font
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
self._frame = QtGui.QPixmap(self._bg_frame)
|
|
|
|
|
2009-04-09 19:12:47 +00:00
|
|
|
x, y = self._correctAlignment(self._rect, bbox)
|
2009-05-16 10:24:03 +00:00
|
|
|
bbox = self._render_lines_unaligned(lines, False, (x, y))
|
2009-04-09 19:12:47 +00:00
|
|
|
|
2009-04-28 19:20:03 +00:00
|
|
|
if footer_lines is not None:
|
2009-05-16 10:24:03 +00:00
|
|
|
bbox = self._render_lines_unaligned(footer_lines, True, (self._rect_footer.left(), self._rect_footer.top()) )
|
2009-05-11 05:09:43 +00:00
|
|
|
log.debug(u'render_lines- Finish')
|
2009-05-16 10:24:03 +00:00
|
|
|
|
|
|
|
return self._frame
|
2009-03-29 14:38:23 +00:00
|
|
|
|
2009-04-09 19:12:47 +00:00
|
|
|
def _render_lines_unaligned(self, lines, footer, tlcorner=(0,0)):
|
2009-05-16 10:24:03 +00:00
|
|
|
"""
|
|
|
|
Given a list of lines to render, render each one in turn
|
2008-10-07 19:12:32 +00:00
|
|
|
(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)
|
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
Returns the bounding box of the text as QRect
|
|
|
|
"""
|
2009-05-11 05:09:43 +00:00
|
|
|
log.debug(u'render lines unaligned Start')
|
2009-05-16 10:24:03 +00:00
|
|
|
x, y = tlcorner
|
|
|
|
brx = x
|
|
|
|
bry = y
|
2008-10-07 19:12:32 +00:00
|
|
|
for line in lines:
|
|
|
|
# render after current bottom, but at original left edge
|
|
|
|
# keep track of right edge to see which is biggest
|
2009-04-09 19:12:47 +00:00
|
|
|
(thisx, bry) = self._render_single_line(line, footer, (x,bry))
|
2009-05-16 19:47:30 +00:00
|
|
|
print thisx , bry
|
2008-10-07 19:12:32 +00:00
|
|
|
if (thisx > brx):
|
2009-05-16 19:47:30 +00:00
|
|
|
brx = thisx
|
2009-05-16 10:24:03 +00:00
|
|
|
retval = QtCore.QRect(x, y,brx-x, bry-y)
|
2008-10-07 19:12:32 +00:00
|
|
|
if self._debug:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter = QtGui.QPainter()
|
|
|
|
painter.begin(self._frame)
|
|
|
|
painter.setPen(QtGui.QPen(QtGui.QColor(0,0,255)))
|
|
|
|
painter.drawRect(retval)
|
|
|
|
painter.end()
|
2009-05-11 05:09:43 +00:00
|
|
|
log.debug(u'render lines unaligned Finish')
|
2008-10-07 19:12:32 +00:00
|
|
|
return retval
|
|
|
|
|
2009-04-09 19:12:47 +00:00
|
|
|
def _render_single_line(self, line, footer, tlcorner=(0,0)):
|
2009-05-16 19:47:30 +00:00
|
|
|
"""
|
|
|
|
Render a single line of words onto the DC, top left corner
|
2008-10-07 19:12:32 +00:00
|
|
|
specified.
|
|
|
|
|
|
|
|
If the line is too wide for the context, it wraps, but
|
|
|
|
right-aligns the surplus words in the manner of song lyrics
|
|
|
|
|
2009-04-15 04:58:51 +00:00
|
|
|
Returns the bottom-right corner (of what was rendered) as a tuple(x, y).
|
2008-10-07 19:12:32 +00:00
|
|
|
"""
|
2009-04-25 06:11:15 +00:00
|
|
|
log.debug(u'Render single line %s @ %s '%( line, tlcorner))
|
2009-05-16 19:47:30 +00:00
|
|
|
x, y = tlcorner
|
2008-10-07 19:12:32 +00:00
|
|
|
# We draw the text to see how big it is and then iterate to make it fit
|
|
|
|
# when we line wrap we do in in the "lyrics" style, so the second line is
|
|
|
|
# right aligned with a "hanging indent"
|
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
print "before ", line
|
|
|
|
words = line.split(u' ')
|
|
|
|
thisline = u' '.join(words)
|
|
|
|
lastword = len(words)
|
|
|
|
lines = []
|
|
|
|
maxx = self._rect.width(); maxy=self._rect.height();
|
2008-10-07 19:12:32 +00:00
|
|
|
while (len(words)>0):
|
2009-05-16 10:24:03 +00:00
|
|
|
w , h = self._get_extent_and_render(thisline, footer)
|
|
|
|
rhs = w + x
|
2008-10-07 19:12:32 +00:00
|
|
|
if rhs < maxx-self._right_margin:
|
|
|
|
lines.append(thisline)
|
2009-05-16 10:24:03 +00:00
|
|
|
words = words[lastword:]
|
|
|
|
thisline = ' '.join(words)
|
|
|
|
lastword = len(words)
|
2008-10-07 19:12:32 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
lastword -= 1
|
|
|
|
thisline = ' '.join(words[:lastword])
|
|
|
|
startx = x
|
|
|
|
starty = y
|
|
|
|
rightextent = None
|
2009-04-23 18:12:36 +00:00
|
|
|
if footer: # dont allow alignment messing with footers
|
|
|
|
align = 0
|
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
align = self._theme .display_horizontalAlign
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2008-10-07 19:12:32 +00:00
|
|
|
for linenum in range(len(lines)):
|
2009-05-16 10:24:03 +00:00
|
|
|
line = lines[linenum]
|
2009-05-16 19:47:30 +00:00
|
|
|
print "render line ", line
|
2008-10-07 19:12:32 +00:00
|
|
|
#find out how wide line is
|
2009-05-16 10:24:03 +00:00
|
|
|
w , h = self._get_extent_and_render(line, footer, tlcorner=(x, y), draw=False)
|
2008-10-07 19:12:32 +00:00
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._theme.display_shadow:
|
2009-05-16 19:47:30 +00:00
|
|
|
w += self._shadow_offset
|
|
|
|
h += self._shadow_offset
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._theme.display_outline:
|
2009-05-16 19:47:30 +00:00
|
|
|
w += 2*self._outline_offset # pixels either side
|
|
|
|
h += 2*self._outline_offset # pixels top/bottom
|
2008-10-07 19:12:32 +00:00
|
|
|
if align==0: # left align
|
2009-05-16 19:47:30 +00:00
|
|
|
rightextent = x+w
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._theme.display_wrapStyle == 1 and linenum != 0: # shift right from last line's rh edge
|
2009-05-16 19:47:30 +00:00
|
|
|
rightextent = self._first_line_right_extent + self._right_margin
|
2008-10-07 19:12:32 +00:00
|
|
|
if rightextent > maxx:
|
|
|
|
rightextent = maxx
|
|
|
|
x = rightextent-w
|
|
|
|
|
2009-05-16 10:24:03 +00:00
|
|
|
elif align == 1: # right align
|
|
|
|
rightextent = maxx
|
|
|
|
x = maxx-w
|
|
|
|
elif align == 2: # centre
|
|
|
|
x = (maxx-w)/2;
|
|
|
|
rightextent = x+w
|
2008-10-07 19:12:32 +00:00
|
|
|
# now draw the text, and any outlines/shadows
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._theme.display_shadow:
|
2009-04-09 19:12:47 +00:00
|
|
|
self._get_extent_and_render(line, footer,tlcorner=(x+self._shadow_offset,y+self._shadow_offset),
|
2009-05-16 16:38:03 +00:00
|
|
|
draw=True, color = self._theme.display_shadow_color)
|
2009-05-16 10:24:03 +00:00
|
|
|
if self._theme.display_outline:
|
2009-05-16 16:38:03 +00:00
|
|
|
self._get_extent_and_render(line, footer,(x+self._outline_offset,y), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
|
|
|
self._get_extent_and_render(line, footer,(x, y+self._outline_offset), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
|
|
|
self._get_extent_and_render(line, footer,(x, y-self._outline_offset), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
|
|
|
self._get_extent_and_render(line, footer,(x-self._outline_offset,y), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
2008-10-07 19:12:32 +00:00
|
|
|
if self._outline_offset > 1:
|
2009-05-16 16:38:03 +00:00
|
|
|
self._get_extent_and_render(line, footer,(x+self._outline_offset,y+self._outline_offset), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
|
|
|
self._get_extent_and_render(line, footer,(x-self._outline_offset,y+self._outline_offset), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
|
|
|
self._get_extent_and_render(line, footer,(x+self._outline_offset,y-self._outline_offset), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
|
|
|
self._get_extent_and_render(line, footer,(x-self._outline_offset,y-self._outline_offset), draw=True,
|
|
|
|
color = self._theme.display_outline_color)
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2009-04-15 04:58:51 +00:00
|
|
|
self._get_extent_and_render(line, footer,tlcorner=(x, y), draw=True)
|
2009-04-06 18:45:45 +00:00
|
|
|
# log.debug(u'Line %2d: Render '%s' at (%d, %d) wh=(%d,%d)' % ( linenum, line, x, y,w,h)
|
2008-10-07 19:12:32 +00:00
|
|
|
y += h
|
|
|
|
if linenum == 0:
|
2009-05-16 10:24:03 +00:00
|
|
|
self._first_line_right_extent = rightextent
|
2008-10-07 19:12:32 +00:00
|
|
|
# draw a box around the text - debug only
|
|
|
|
if self._debug:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter = QtGui.QPainter()
|
|
|
|
painter.begin(self._frame)
|
|
|
|
painter.setPen(QtGui.QPen(QtGui.QColor(0,255,0)))
|
2009-05-16 19:47:30 +00:00
|
|
|
painter.drawRect(startx , starty , rightextent-startx , y-starty)
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.end()
|
2008-10-23 19:49:13 +00:00
|
|
|
|
2009-05-16 19:47:30 +00:00
|
|
|
brcorner = (rightextent , y)
|
2009-05-11 05:09:43 +00:00
|
|
|
log.debug(u'Render single line Finish')
|
2008-10-07 19:12:32 +00:00
|
|
|
return brcorner
|
|
|
|
|
|
|
|
# xxx this is what to override for an SDL version
|
2009-04-09 19:12:47 +00:00
|
|
|
def _get_extent_and_render(self, line, footer, tlcorner=(0,0), draw=False, color=None):
|
2009-05-16 10:24:03 +00:00
|
|
|
"""
|
|
|
|
Find bounding box of text - as render_single_line.
|
2009-04-06 18:45:45 +00:00
|
|
|
If draw is set, actually draw the text to the current DC as well
|
2009-05-16 10:24:03 +00:00
|
|
|
return width and height of text as a tuple (w,h)
|
|
|
|
"""
|
2008-10-07 19:12:32 +00:00
|
|
|
# setup defaults
|
2009-05-09 07:01:33 +00:00
|
|
|
#log.debug(u'_get_extent_and_render %s %s %s ', [line], tlcorner, draw)
|
2009-05-16 10:24:03 +00:00
|
|
|
painter = QtGui.QPainter()
|
|
|
|
painter.begin(self._frame)
|
2008-10-07 19:12:32 +00:00
|
|
|
# 'twould be more efficient to set this once when theme changes
|
|
|
|
# or p changes
|
2009-03-29 16:51:42 +00:00
|
|
|
if footer :
|
2009-05-16 10:24:03 +00:00
|
|
|
font = QtGui.QFont(self._theme.font_footer_name,
|
2009-04-06 18:45:45 +00:00
|
|
|
int(self._theme.font_footer_proportion), # size
|
2009-03-29 16:51:42 +00:00
|
|
|
QtGui.QFont.Normal, # weight
|
|
|
|
0)# italic
|
2009-05-16 10:24:03 +00:00
|
|
|
font.setPixelSize(int(self._theme.font_footer_proportion))
|
2009-03-29 16:51:42 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
font = QtGui.QFont(self._theme.font_main_name,
|
2009-04-06 18:45:45 +00:00
|
|
|
int(self._theme.font_main_proportion), # size
|
2009-03-29 16:51:42 +00:00
|
|
|
QtGui.QFont.Normal, # weight
|
|
|
|
0)# italic
|
2009-04-06 18:45:45 +00:00
|
|
|
font.setPixelSize(int(self._theme.font_main_proportion))
|
|
|
|
#log.debug(u'Font details %s %s %s %d', self._theme.font_main_name, self._theme.font_main_proportion, font.family(), font.pointSize())
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.setFont(font)
|
2008-10-07 19:12:32 +00:00
|
|
|
if color == None:
|
2009-04-06 18:45:45 +00:00
|
|
|
if footer:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.setPen(QtGui.QColor(self._theme.font_footer_color))
|
2009-04-06 18:45:45 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.setPen(QtGui.QColor(self._theme.font_main_color))
|
2008-10-07 19:12:32 +00:00
|
|
|
else:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.setPen(QtGui.QColor(color))
|
|
|
|
x, y = tlcorner
|
2008-10-07 19:12:32 +00:00
|
|
|
metrics=QtGui.QFontMetrics(font)
|
|
|
|
# xxx some fudges to make it exactly like wx! Take 'em out later
|
2009-05-16 10:24:03 +00:00
|
|
|
w = metrics.width(line)
|
|
|
|
h = metrics.height()-2
|
2009-04-06 18:45:45 +00:00
|
|
|
if draw:
|
2009-05-16 10:24:03 +00:00
|
|
|
painter.drawText(x, y+metrics.height()-metrics.descent()-1, line)
|
|
|
|
painter.end()
|
2008-10-07 19:12:32 +00:00
|
|
|
return (w, h)
|
2009-05-16 10:24:03 +00:00
|
|
|
|
|
|
|
def snoop_Image(self, image, image2=None):
|
|
|
|
"""
|
|
|
|
Debugging method to allow images to be viewed
|
|
|
|
"""
|
|
|
|
im = image.toImage()
|
|
|
|
im.save("renderer.png", "png")
|
|
|
|
if image2 is not None:
|
|
|
|
im = image2.toImage()
|
|
|
|
im.save("renderer2.png", "png")
|