1# Copyright (C) 2010 Jeremy S. Sanders 2# Email: Jeremy Sanders <jeremy@jeremysanders.net> 3# 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 2 of the License, or 7# (at your option) any later version. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License along 15# with this program; if not, write to the Free Software Foundation, Inc., 16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17############################################################################## 18 19"""Non orthogonal graph root.""" 20 21from __future__ import division 22from . import controlgraph 23from .widget import Widget 24 25from .. import qtall as qt 26from .. import setting 27 28filloptions = ('center', 'outside', 'top', 'bottom', 'left', 'right', 29 'polygon') 30 31def _(text, disambiguation=None, context='NonOrthGraph'): 32 """Translate text.""" 33 return qt.QCoreApplication.translate(context, text, disambiguation) 34 35class FillBrush(setting.BrushExtended): 36 '''Brush for filling point region.''' 37 def __init__(self, *args, **argsv): 38 setting.BrushExtended.__init__(self, *args, **argsv) 39 self.add( setting.Choice('filltype', filloptions, 'center', 40 descr=_('Fill to this edge/position'), 41 usertext=_('Fill type')) ) 42 self.get('hide').newDefault(True) 43 44class NonOrthGraph(Widget): 45 '''Non-orthogonal graph base widget.''' 46 47 @classmethod 48 def addSettings(klass, s): 49 '''Construct list of settings.''' 50 Widget.addSettings(s) 51 52 s.add( setting.Distance( 'leftMargin', 53 '1.7cm', 54 descr=_('Distance from left of graph to edge'), 55 usertext=_('Left margin'), 56 formatting=True) ) 57 s.add( setting.Distance( 'rightMargin', 58 '0.2cm', 59 descr=_('Distance from right of graph to edge'), 60 usertext=_('Right margin'), 61 formatting=True) ) 62 s.add( setting.Distance( 'topMargin', 63 '0.2cm', 64 descr=_('Distance from top of graph to edge'), 65 usertext=_('Top margin'), 66 formatting=True) ) 67 s.add( setting.Distance( 'bottomMargin', 68 '1.7cm', 69 descr=_('Distance from bottom of graph to edge'), 70 usertext=_('Bottom margin'), 71 formatting=True) ) 72 s.add( setting.GraphBrush( 'Background', 73 descr = _('Background plot fill'), 74 usertext=_('Background')), 75 pixmap='settings_bgfill' ) 76 s.add( setting.Line('Border', descr = _('Graph border line'), 77 usertext=_('Border')), 78 pixmap='settings_border') 79 80 @classmethod 81 def allowedParentTypes(klass): 82 from . import page, grid 83 return (page.Page, grid.Grid) 84 85 def graphToPlotCoords(self, coorda, coordb): 86 '''Convert graph to plotting coordinates. 87 Returns (plta, pltb) coordinates 88 ''' 89 90 def coordRanges(self): 91 '''Return coordinate ranges of plot. 92 This is in the form [[mina, maxa], [minb, maxb]].''' 93 94 def drawFillPts(self, painter, extfill, bounds, ptsx, ptsy): 95 '''Draw set of points for filling. 96 extfill: extended fill brush 97 bounds: usual tuple (minx, miny, maxx, maxy) 98 ptsx, ptsy: translated plotter coordinates 99 ''' 100 101 def drawGraph(self, painter, bounds, datarange, outerbounds=None): 102 '''Plot graph area. 103 datarange is [mina, maxa, minb, maxb] or None 104 ''' 105 106 def drawAxes(self, painter, bounds, datarange, outerbounds=None): 107 '''Plot axes. 108 datarange is [mina, maxa, minb, maxb] or None 109 ''' 110 111 def setClip(self, painter, bounds): 112 '''Set clipping for graph.''' 113 114 def getDataRange(self): 115 """Get automatic data range. Return None if no data.""" 116 117 drange = [1e199, -1e199, 1e199, -1e199] 118 for c in self.children: 119 if hasattr(c, 'updateDataRanges'): 120 c.updateDataRanges(drange) 121 122 # no data 123 if drange[0] > drange[1] or drange[2] > drange[3]: 124 drange = None 125 126 return drange 127 128 def getMargins(self, painthelper): 129 """Use settings to compute margins.""" 130 s = self.settings 131 return ( s.get('leftMargin').convert(painthelper), 132 s.get('topMargin').convert(painthelper), 133 s.get('rightMargin').convert(painthelper), 134 s.get('bottomMargin').convert(painthelper) ) 135 136 def draw(self, parentposn, phelper, outerbounds=None): 137 '''Update the margins before drawing.''' 138 139 s = self.settings 140 141 bounds = self.computeBounds(parentposn, phelper) 142 maxbounds = self.computeBounds(parentposn, phelper, withmargin=False) 143 144 # do no painting if hidden 145 if s.hide: 146 return bounds 147 148 painter = phelper.painter(self, bounds) 149 with painter: 150 # reset counter and compute automatic colors 151 phelper.autoplottercount = 0 152 for c in self.children: 153 c.setupAutoColor(painter) 154 155 # plot graph 156 datarange = self.getDataRange() 157 self.drawGraph(painter, bounds, datarange, outerbounds=outerbounds) 158 self.drawAxes(painter, bounds, datarange, outerbounds=outerbounds) 159 160 # paint children 161 for c in reversed(self.children): 162 c.draw(bounds, phelper, outerbounds=outerbounds) 163 164 # controls for adjusting margins 165 phelper.setControlGraph(self, [ 166 controlgraph.ControlMarginBox(self, bounds, maxbounds, phelper)]) 167 168 return bounds 169 170 def updateControlItem(self, cgi): 171 """Graph resized or moved - call helper routine to move self.""" 172 cgi.setWidgetMargins() 173