forked from openlp/openlp
Update Render to use Qgradient instead of home built code.
Colors hard coded for now.
This commit is contained in:
parent
8aa67b5a8b
commit
4ac2ed4fd6
@ -17,13 +17,19 @@ 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
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from PyQt4 import QtGui, QtCore, Qt
|
from PyQt4 import QtGui, QtCore, Qt
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from interpolate import interpolate
|
from interpolate import interpolate
|
||||||
|
|
||||||
class Renderer:
|
class Renderer:
|
||||||
|
|
||||||
|
global log
|
||||||
|
log=logging.getLogger(u'Renderer')
|
||||||
|
log.info(u'Renderer Loaded')
|
||||||
"""All the functions for rendering a set of words onto a Device Context
|
"""All the functions for rendering a set of words onto a Device Context
|
||||||
|
|
||||||
How to use:
|
How to use:
|
||||||
@ -44,21 +50,21 @@ class Renderer:
|
|||||||
self._theme=None
|
self._theme=None
|
||||||
self._bg_image_filename=None
|
self._bg_image_filename=None
|
||||||
self._paint=None
|
self._paint=None
|
||||||
|
|
||||||
def set_debug(self, debug):
|
def set_debug(self, debug):
|
||||||
self._debug=debug
|
self._debug=debug
|
||||||
|
|
||||||
def set_theme(self, theme):
|
def set_theme(self, theme):
|
||||||
self._theme=theme
|
self._theme=theme
|
||||||
if theme.BackgroundType == 2:
|
if theme.BackgroundType == 2:
|
||||||
self.set_bg_image(theme.BackgroundParameter1)
|
self.set_bg_image(theme.BackgroundParameter1)
|
||||||
|
|
||||||
def set_bg_image(self, filename):
|
def set_bg_image(self, filename):
|
||||||
print "set bg image", filename
|
log.debug(u"set bg image %s", filename)
|
||||||
self._bg_image_filename=filename
|
self._bg_image_filename=filename
|
||||||
if self._paint is not None:
|
if self._paint is not None:
|
||||||
self.scale_bg_image()
|
self.scale_bg_image()
|
||||||
|
|
||||||
def scale_bg_image(self):
|
def scale_bg_image(self):
|
||||||
assert self._paint
|
assert self._paint
|
||||||
i=QtGui.QImage(self._bg_image_filename)
|
i=QtGui.QImage(self._bg_image_filename)
|
||||||
@ -67,7 +73,7 @@ class Renderer:
|
|||||||
dcw=self._paint.width()+1;dch=self._paint.height()
|
dcw=self._paint.width()+1;dch=self._paint.height()
|
||||||
imratio=imw/float(imh)
|
imratio=imw/float(imh)
|
||||||
dcratio=dcw/float(dch)
|
dcratio=dcw/float(dch)
|
||||||
print "Image scaling params", imw, imh, imratio, dcw, dch, dcratio
|
log.debug(u"Image scaling params %s %s %s %s %s %s", imw, imh, imratio, dcw, dch, dcratio)
|
||||||
if imratio > dcratio:
|
if imratio > dcratio:
|
||||||
scale=dcw/float(imw)
|
scale=dcw/float(imw)
|
||||||
elif imratio < dcratio:
|
elif imratio < dcratio:
|
||||||
@ -84,9 +90,9 @@ class Renderer:
|
|||||||
self._paint=p
|
self._paint=p
|
||||||
if self._bg_image_filename is not None:
|
if self._bg_image_filename is not None:
|
||||||
self.scale_bg_image()
|
self.scale_bg_image()
|
||||||
|
|
||||||
def set_words_openlp(self, words):
|
def set_words_openlp(self, words):
|
||||||
# print "set words openlp", words
|
# log.debug(u" "set words openlp", words
|
||||||
verses=[]
|
verses=[]
|
||||||
words=words.replace("\r\n", "\n")
|
words=words.replace("\r\n", "\n")
|
||||||
verses_text=words.split('\n\n')
|
verses_text=words.split('\n\n')
|
||||||
@ -99,9 +105,9 @@ class Renderer:
|
|||||||
verses_text.append('\n'.join(v).lstrip()) # remove first \n
|
verses_text.append('\n'.join(v).lstrip()) # remove first \n
|
||||||
|
|
||||||
return verses_text
|
return verses_text
|
||||||
|
|
||||||
def render_screen(self, screennum):
|
def render_screen(self, screennum):
|
||||||
print "render screen\n", screennum, self.words[screennum]
|
log.debug(u"render screen\n %s %s ", screennum, self.words[screennum])
|
||||||
import time
|
import time
|
||||||
t=0.0
|
t=0.0
|
||||||
words=self.words[screennum]
|
words=self.words[screennum]
|
||||||
@ -111,51 +117,45 @@ class Renderer:
|
|||||||
def set_text_rectangle(self, rect):
|
def set_text_rectangle(self, rect):
|
||||||
""" Sets the rectangle within which text should be rendered"""
|
""" Sets the rectangle within which text should be rendered"""
|
||||||
self._rect=rect
|
self._rect=rect
|
||||||
|
|
||||||
def _render_background(self):
|
def _render_background(self):
|
||||||
# xxx may have to prerender to a memdc when set theme is called for use on slow machines
|
|
||||||
# takes 26ms on mijiti's machine!
|
|
||||||
assert(self._theme)
|
assert(self._theme)
|
||||||
assert(self._paint)
|
assert(self._paint)
|
||||||
print "render background", self._theme.BackgroundType
|
log.debug(u"render background %s %s", self._theme.BackgroundType)
|
||||||
p=QtGui.QPainter()
|
p=QtGui.QPainter()
|
||||||
p.begin(self._paint)
|
p.begin(self._paint)
|
||||||
if self._theme.BackgroundType == 0:
|
if self._theme.BackgroundType == 0:
|
||||||
p.fillRect(self._paint.rect(), self._theme.BackgroundParameter1)
|
p.fillRect(self._paint.rect(), self._theme.BackgroundParameter1)
|
||||||
elif self._theme.BackgroundType == 1: # gradient
|
elif self._theme.BackgroundType == 1: # gradient
|
||||||
# xxx Use a QGradient Brush!!!
|
#TODO Add Theme code and fix direction
|
||||||
# get colours as tuples
|
|
||||||
c1=self._theme.BackgroundParameter1.getRgb()
|
gradient = QtGui.QLinearGradient(0, 0, self._paint.width(), self._paint.height())
|
||||||
c2=self._theme.BackgroundParameter2.getRgb()
|
gradient.setColorAt(0, QtGui.QColor(255, 0, 0))
|
||||||
dir=self._theme.BackgroundParameter3
|
gradient.setColorAt(0.5, QtGui.QColor(0, 255, 0))
|
||||||
w=self._paint.width();h=self._paint.height()
|
gradient.setColorAt(1, QtGui.QColor(0, 0, 255))
|
||||||
lines=[]
|
p.setBrush(QtGui.QBrush(gradient))
|
||||||
pens=[]
|
rectPath = QtGui.QPainterPath()
|
||||||
if dir == 0: # vertical
|
|
||||||
for y in range (h):
|
MAX_X = self._paint.width()
|
||||||
c=interpolate(c1, c2, y/float(h))
|
MAX_Y = self._paint.height()
|
||||||
lines.append((0,y,w,y))
|
|
||||||
pens.append(QtGui.QPen(QtGui.QColor(c[0],c[1],c[2]))) # bleagh
|
rectPath.moveTo(0, 0)
|
||||||
else:
|
rectPath.lineTo(0, MAX_Y)
|
||||||
for x in range (w):
|
rectPath.lineTo(MAX_X, MAX_Y)
|
||||||
c=interpolate(c1, c2, x/float(w))
|
rectPath.lineTo(MAX_X, 0)
|
||||||
lines.append((x,0,x,h))
|
rectPath.closeSubpath()
|
||||||
pens.append(QtGui.QPen(QtGui.QColor(c[0],c[1],c[2]))) # bleagh
|
p.drawPath(rectPath)
|
||||||
for i in range(len(pens)):
|
|
||||||
p.setPen(pens[i])
|
|
||||||
l=lines[i]
|
|
||||||
p.drawLine(l[0],l[1],l[2],l[3]) # must be a better way!
|
|
||||||
|
|
||||||
elif self._theme.BackgroundType == 2: # image
|
elif self._theme.BackgroundType == 2: # image
|
||||||
r=self._paint.rect()
|
r=self._paint.rect()
|
||||||
print r.x(), r.y(), r.width(),r.height()
|
log.debug(r.x(), r.y(), r.width(),r.height())
|
||||||
print self._theme.BackgroundParameter2
|
log.debug(self._theme.BackgroundParameter2)
|
||||||
if self._theme.BackgroundParameter2 is not None:
|
if self._theme.BackgroundParameter2 is not None:
|
||||||
p.fillRect(self._paint.rect(), self._theme.BackgroundParameter2)
|
p.fillRect(self._paint.rect(), self._theme.BackgroundParameter2)
|
||||||
p.drawPixmap(self.background_offsetx,self.background_offsety, self.img)
|
p.drawPixmap(self.background_offsetx,self.background_offsety, self.img)
|
||||||
p.end()
|
p.end()
|
||||||
print "render background done"
|
log.debug(u"render background done")
|
||||||
|
|
||||||
def split_set_of_lines(self, lines):
|
def split_set_of_lines(self, lines):
|
||||||
|
|
||||||
"""Given a list of lines, decide how to split them best if they don't all fit on the screen
|
"""Given a list of lines, decide how to split them best if they don't all fit on the screen
|
||||||
@ -166,7 +166,7 @@ class Renderer:
|
|||||||
|
|
||||||
Returns a list of [lists of lines], one set for each screenful
|
Returns a list of [lists of lines], one set for each screenful
|
||||||
"""
|
"""
|
||||||
# print "Split set of lines"
|
# log.debug(u" "Split set of lines"
|
||||||
# Probably ought to save the rendering results to a pseudoDC for redrawing efficiency. But let's not optimse prematurely!
|
# Probably ought to save the rendering results to a pseudoDC for redrawing efficiency. But let's not optimse prematurely!
|
||||||
|
|
||||||
bboxes = []
|
bboxes = []
|
||||||
@ -202,7 +202,7 @@ class Renderer:
|
|||||||
retval.append(thislines)
|
retval.append(thislines)
|
||||||
thislines=[]
|
thislines=[]
|
||||||
else:
|
else:
|
||||||
# print "Just split where you can"
|
# log.debug(u" "Just split where you can"
|
||||||
retval=[]
|
retval=[]
|
||||||
startline=0
|
startline=0
|
||||||
endline=startline+1
|
endline=startline+1
|
||||||
@ -221,9 +221,10 @@ class Renderer:
|
|||||||
|
|
||||||
def _render_lines(self, lines):
|
def _render_lines(self, lines):
|
||||||
"""render a set of lines according to the theme, return bounding box"""
|
"""render a set of lines according to the theme, return bounding box"""
|
||||||
print "_render_lines", lines
|
log.debug(u"_render_lines %s", lines)
|
||||||
|
|
||||||
bbox=self._render_lines_unaligned(lines)
|
bbox=self._render_lines_unaligned(lines)
|
||||||
|
print bbox
|
||||||
|
|
||||||
t=self._theme
|
t=self._theme
|
||||||
x=self._rect.left()
|
x=self._rect.left()
|
||||||
@ -237,10 +238,10 @@ class Renderer:
|
|||||||
assert(0, "Invalid value for theme.VerticalAlign:%d" % t.VerticalAlign)
|
assert(0, "Invalid value for theme.VerticalAlign:%d" % t.VerticalAlign)
|
||||||
self._render_background()
|
self._render_background()
|
||||||
bbox=self._render_lines_unaligned(lines, (x,y))
|
bbox=self._render_lines_unaligned(lines, (x,y))
|
||||||
print "render lines DONE"
|
log.debug(u"render lines DONE")
|
||||||
|
|
||||||
return bbox
|
return bbox
|
||||||
|
|
||||||
def _render_lines_unaligned(self, lines, tlcorner=(0,0)):
|
def _render_lines_unaligned(self, lines, tlcorner=(0,0)):
|
||||||
|
|
||||||
"""Given a list of lines to render, render each one in turn
|
"""Given a list of lines to render, render each one in turn
|
||||||
@ -249,7 +250,7 @@ class Renderer:
|
|||||||
than a screenful (eg. by using split_set_of_lines)
|
than a screenful (eg. by using split_set_of_lines)
|
||||||
|
|
||||||
Returns the bounding box of the text as QRect"""
|
Returns the bounding box of the text as QRect"""
|
||||||
print "render unaligned", lines
|
log.debug(u"render unaligned %s", lines)
|
||||||
x,y=tlcorner
|
x,y=tlcorner
|
||||||
brx=x
|
brx=x
|
||||||
bry=y
|
bry=y
|
||||||
@ -268,7 +269,7 @@ class Renderer:
|
|||||||
p.setPen(QtGui.QPen(QtGui.QColor(0,0,255)))
|
p.setPen(QtGui.QPen(QtGui.QColor(0,0,255)))
|
||||||
p.drawRect(retval)
|
p.drawRect(retval)
|
||||||
p.end()
|
p.end()
|
||||||
print "render unaligned DONE"
|
log.debug(u"render unaligned DONE")
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
@ -282,14 +283,14 @@ class Renderer:
|
|||||||
|
|
||||||
Returns the bottom-right corner (of what was rendered) as a tuple(x,y).
|
Returns the bottom-right corner (of what was rendered) as a tuple(x,y).
|
||||||
"""
|
"""
|
||||||
print "Render single line '%s' @ %s "%( line, tlcorner)
|
log.debug(u"Render single line '%s' @ %s "%( line, tlcorner))
|
||||||
x,y=tlcorner
|
x,y=tlcorner
|
||||||
# We draw the text to see how big it is and then iterate to make it fit
|
# 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
|
# when we line wrap we do in in the "lyrics" style, so the second line is
|
||||||
# right aligned with a "hanging indent"
|
# right aligned with a "hanging indent"
|
||||||
|
|
||||||
# get the words
|
# get the words
|
||||||
# print "Getting the words split right"
|
# log.debug(u" "Getting the words split right"
|
||||||
words=line.split(" ")
|
words=line.split(" ")
|
||||||
thisline=' '.join(words)
|
thisline=' '.join(words)
|
||||||
lastword=len(words)
|
lastword=len(words)
|
||||||
@ -307,8 +308,8 @@ class Renderer:
|
|||||||
lastword-=1
|
lastword-=1
|
||||||
thisline=' '.join(words[:lastword])
|
thisline=' '.join(words[:lastword])
|
||||||
|
|
||||||
# print "This is how they split", lines
|
# log.debug(u" "This is how they split", lines
|
||||||
# print "Now render them"
|
# log.debug(u" "Now render them"
|
||||||
startx=x
|
startx=x
|
||||||
starty=y
|
starty=y
|
||||||
rightextent=None
|
rightextent=None
|
||||||
@ -356,7 +357,7 @@ class Renderer:
|
|||||||
self._get_extent_and_render(line, (x-self._outline_offset,y-self._outline_offset), dodraw=True, color = t.OutlineColor)
|
self._get_extent_and_render(line, (x-self._outline_offset,y-self._outline_offset), dodraw=True, color = t.OutlineColor)
|
||||||
|
|
||||||
self._get_extent_and_render(line, tlcorner=(x,y), dodraw=True)
|
self._get_extent_and_render(line, tlcorner=(x,y), dodraw=True)
|
||||||
# print "Line %2d: Render '%s' at (%d, %d) wh=(%d,%d)"%( linenum, line, x, y,w,h)
|
# log.debug(u" "Line %2d: Render '%s' at (%d, %d) wh=(%d,%d)"%( linenum, line, x, y,w,h)
|
||||||
y += h
|
y += h
|
||||||
if linenum == 0:
|
if linenum == 0:
|
||||||
self._first_line_right_extent=rightextent
|
self._first_line_right_extent=rightextent
|
||||||
@ -378,7 +379,7 @@ class Renderer:
|
|||||||
|
|
||||||
return width and height of text as a tuple (w,h)"""
|
return width and height of text as a tuple (w,h)"""
|
||||||
# setup defaults
|
# setup defaults
|
||||||
print "_get_extent_and_render", [line], tlcorner, dodraw
|
log.debug(u"_get_extent_and_render %s %s %s ", [line], tlcorner, dodraw)
|
||||||
p=QtGui.QPainter()
|
p=QtGui.QPainter()
|
||||||
p.begin(self._paint)
|
p.begin(self._paint)
|
||||||
# 'twould be more efficient to set this once when theme changes
|
# 'twould be more efficient to set this once when theme changes
|
||||||
@ -390,10 +391,10 @@ class Renderer:
|
|||||||
# to make the unit tests monitor independent, we have to be able to
|
# to make the unit tests monitor independent, we have to be able to
|
||||||
# specify whether a font proportion is in pixels or points
|
# specify whether a font proportion is in pixels or points
|
||||||
if self._theme.FontUnits.lower() == "pixels":
|
if self._theme.FontUnits.lower() == "pixels":
|
||||||
print "pixels"
|
log.debug(u"pixels")
|
||||||
font.setPixelSize(self._theme.FontProportion)
|
font.setPixelSize(self._theme.FontProportion)
|
||||||
print self._theme.FontName, self._theme.FontProportion
|
log.debug(self._theme.FontName, self._theme.FontProportion)
|
||||||
print font.family(), font.pointSize()
|
log.debug(font.family(), font.pointSize())
|
||||||
p.setFont(font)
|
p.setFont(font)
|
||||||
if color == None:
|
if color == None:
|
||||||
p.setPen(self._theme.FontColor)
|
p.setPen(self._theme.FontColor)
|
||||||
|
@ -81,6 +81,7 @@ class TestRender_base:
|
|||||||
def teardown_class(self):
|
def teardown_class(self):
|
||||||
print "class quit", self, self.app
|
print "class quit", self, self.app
|
||||||
self.app.quit()
|
self.app.quit()
|
||||||
|
|
||||||
def setup_method(self, method):
|
def setup_method(self, method):
|
||||||
print "SSsetup", method
|
print "SSsetup", method
|
||||||
if not hasattr(self, "app"):
|
if not hasattr(self, "app"):
|
||||||
@ -157,6 +158,7 @@ Line 3"""
|
|||||||
expected_answer=["Verse 1: Line 1\nLine 2","Verse 2: Line 1\nLine 2","Verse 3: Line 1\nLine 2\nLine 3"]
|
expected_answer=["Verse 1: Line 1\nLine 2","Verse 2: Line 1\nLine 2","Verse 3: Line 1\nLine 2\nLine 3"]
|
||||||
answer=self.r.set_words_openlp(words)
|
answer=self.r.set_words_openlp(words)
|
||||||
assert (answer==expected_answer)
|
assert (answer==expected_answer)
|
||||||
|
|
||||||
def test_render_screens(self):
|
def test_render_screens(self):
|
||||||
words="""
|
words="""
|
||||||
Verse 1: Line 1
|
Verse 1: Line 1
|
||||||
@ -177,6 +179,7 @@ Line 3"""
|
|||||||
answer=self.r.render_screen(v)
|
answer=self.r.render_screen(v)
|
||||||
# print v, answer.x(), answer.y(), answer.width(), answer.height()
|
# print v, answer.x(), answer.y(), answer.width(), answer.height()
|
||||||
assert(answer==expected_answer[v])
|
assert(answer==expected_answer[v])
|
||||||
|
|
||||||
def split_test(self, number, answer, expected_answers):
|
def split_test(self, number, answer, expected_answers):
|
||||||
lines=[]
|
lines=[]
|
||||||
print "Split test", number, answer
|
print "Split test", number, answer
|
||||||
|
@ -8,6 +8,8 @@ else:
|
|||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
DelphiColors={"clRed":0xFF0000,
|
DelphiColors={"clRed":0xFF0000,
|
||||||
|
"clBlue":0x0000FF,
|
||||||
|
"clYellow":0x0FFFF00,
|
||||||
"clBlack":0x000000,
|
"clBlack":0x000000,
|
||||||
"clWhite":0xFFFFFF}
|
"clWhite":0xFFFFFF}
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ blankstylexml=\
|
|||||||
<Theme>
|
<Theme>
|
||||||
<Name>BlankStyle</Name>
|
<Name>BlankStyle</Name>
|
||||||
<BackgroundMode>1</BackgroundMode>
|
<BackgroundMode>1</BackgroundMode>
|
||||||
<BackgroundType>0</BackgroundType>
|
<BackgroundType>0</BackgroundType>
|
||||||
<BackgroundParameter1>$000000</BackgroundParameter1>
|
<BackgroundParameter1>$000000</BackgroundParameter1>
|
||||||
<BackgroundParameter2/>
|
<BackgroundParameter2/>
|
||||||
<BackgroundParameter3/>
|
<BackgroundParameter3/>
|
||||||
@ -37,10 +39,10 @@ class Theme:
|
|||||||
""" stores the info about a theme
|
""" stores the info about a theme
|
||||||
attributes:
|
attributes:
|
||||||
name : theme name
|
name : theme name
|
||||||
|
|
||||||
BackgroundMode : 1 - Transparent
|
BackgroundMode : 1 - Transparent
|
||||||
1 - Opaque
|
1 - Opaque
|
||||||
|
|
||||||
BackgroundType : 0 - solid color
|
BackgroundType : 0 - solid color
|
||||||
1 - gradient color
|
1 - gradient color
|
||||||
2 - image
|
2 - image
|
||||||
@ -53,7 +55,7 @@ class Theme:
|
|||||||
for solid - N/A
|
for solid - N/A
|
||||||
BackgroundParameter3 : for image - N/A
|
BackgroundParameter3 : for image - N/A
|
||||||
for gradient - 0 -> vertical, 1 -> horizontal
|
for gradient - 0 -> vertical, 1 -> horizontal
|
||||||
|
|
||||||
FontName : name of font to use
|
FontName : name of font to use
|
||||||
FontColor : color for main font
|
FontColor : color for main font
|
||||||
FontProportion : size of font
|
FontProportion : size of font
|
||||||
@ -108,7 +110,7 @@ class Theme:
|
|||||||
# print "nope",
|
# print "nope",
|
||||||
pass
|
pass
|
||||||
elif DelphiColors.has_key(t):
|
elif DelphiColors.has_key(t):
|
||||||
# print "colour",
|
# print "colour",
|
||||||
val=DelphiColors[t]
|
val=DelphiColors[t]
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
@ -121,7 +123,7 @@ class Theme:
|
|||||||
val= QtGui.QColor((val>>16) & 0xFF, (val>>8)&0xFF, val&0xFF)
|
val= QtGui.QColor((val>>16) & 0xFF, (val>>8)&0xFF, val&0xFF)
|
||||||
# print [val]
|
# print [val]
|
||||||
setattr(self,element.tag, val)
|
setattr(self,element.tag, val)
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
s=""
|
s=""
|
||||||
|
Loading…
Reference in New Issue
Block a user