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