1#    Copyright (C) 2007 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"""A colorbar widget for the image widget. Should show the scale of
20the image."""
21
22from __future__ import division
23from .. import qtall as qt
24import numpy as N
25
26from .. import document
27from .. import setting
28from .. import utils
29from ..helpers import qtloops
30
31from . import widget
32from . import axis
33
34def _(text, disambiguation=None, context='ColorBar'):
35    """Translate text."""
36    return qt.QCoreApplication.translate(context, text, disambiguation)
37
38class ColorBar(axis.Axis):
39    """Color bar for showing scale of image.
40
41    This naturally is descended from an axis
42    """
43
44    typename='colorbar'
45    allowusercreation = True
46    description = _('Image color bar')
47    isaxis = False
48
49    @classmethod
50    def addSettings(klass, s):
51        """Construct list of settings."""
52        axis.Axis.addSettings(s)
53
54        s.add( setting.WidgetChoice('widgetName', '',
55                                    descr=_('Corresponding widget'),
56                                    widgettypes=('image', 'xy', 'nonorthpoint'),
57                                    usertext = _('Widget')), 0 )
58
59        s.get('log').readonly = True
60        s.get('datascale').readonly = True
61
62        s.add( setting.AlignHorzWManual( 'horzPosn',
63                                         'right',
64                                         descr = _('Horizontal position'),
65                                         usertext=_('Horz posn'),
66                                         formatting=True) )
67        s.add( setting.AlignVertWManual( 'vertPosn',
68                                         'bottom',
69                                         descr = _('Vertical position'),
70                                         usertext=_('Vert posn'),
71                                         formatting=True) )
72        s.add( setting.DistanceOrAuto('width', 'Auto',
73                                      descr = _('Width of colorbar'),
74                                      usertext=_('Width'),
75                                      formatting=True) )
76        s.add( setting.DistanceOrAuto('height', 'Auto',
77                                      descr = _('Height of colorbar'),
78                                      usertext=_('Height'),
79                                      formatting=True) )
80
81        s.add( setting.Float( 'horzManual',
82                              0.,
83                              descr = _('Manual horizontal fractional position'),
84                              usertext=_('Horz manual'),
85                              formatting=True) )
86        s.add( setting.Float( 'vertManual',
87                              0.,
88                              descr = _('Manual vertical fractional position'),
89                              usertext=_('Vert manual'),
90                              formatting=True) )
91
92        s.add( setting.Line('Border', descr = _('Colorbar border line'),
93                            usertext=_('Border')),
94               pixmap='settings_border')
95
96        s.add( setting.SettingBackwardCompat('image', 'widgetName', None) )
97
98    @classmethod
99    def allowedParentTypes(klass):
100        from . import graph, grid, nonorthgraph
101        return (graph.Graph, grid.Grid, nonorthgraph.NonOrthGraph)
102
103    @property
104    def userdescription(self):
105        return _("widget='%s', label='%s'") % (
106            self.settings.widgetName, self.settings.label)
107
108    def chooseName(self):
109        """Get name of widget."""
110
111        # override axis naming of x and y
112        return widget.Widget.chooseName(self)
113
114    def _axisDraw(self, posn, parentposn, outerbounds, painter, phelper):
115        """Do actual drawing."""
116
117        s = self.settings
118
119        # get height of label font
120        bounds = self.computeBounds(parentposn, phelper)
121
122        font = s.get('Label').makeQFont(phelper)
123        painter.setFont(font)
124        fontheight = utils.FontMetrics(font, painter.device()).height()
125
126        horz = s.direction == 'horizontal'
127
128        # use above to estimate width and height if necessary
129        w = s.get('width')
130        if w.isAuto():
131            if horz:
132                totalwidth = bounds[2] - bounds[0] - 2*fontheight
133            else:
134                totalwidth = fontheight
135        else:
136            totalwidth = w.convert(painter)
137
138        h = s.get('height')
139        if h.isAuto():
140            if horz:
141                totalheight = fontheight
142            else:
143                totalheight = bounds[3] - bounds[1] - 2*fontheight
144        else:
145            totalheight = h.convert(painter)
146
147        # work out horizontal position
148        h = s.horzPosn
149        if h == 'left':
150            bounds[0] += fontheight
151            bounds[2] = bounds[0] + totalwidth
152        elif h == 'right':
153            bounds[2] -= fontheight
154            bounds[0] = bounds[2] - totalwidth
155        elif h == 'centre':
156            delta = (bounds[2]-bounds[0]-totalwidth)/2.
157            bounds[0] += delta
158            bounds[2] -= delta
159        elif h == 'manual':
160            bounds[0] += (bounds[2]-bounds[0])*s.horzManual
161            bounds[2] = bounds[0] + totalwidth
162
163        # work out vertical position
164        v = s.vertPosn
165        if v == 'top':
166            bounds[1] += fontheight
167            bounds[3] = bounds[1] + totalheight
168        elif v == 'bottom':
169            bounds[3] -= fontheight
170            bounds[1] = bounds[3] - totalheight
171        elif v == 'centre':
172            delta = (bounds[3]-bounds[1]-totalheight)/2.
173            bounds[1] += delta
174            bounds[3] -= delta
175        elif v == 'manual':
176            bounds[1] += (bounds[3]-bounds[1])*s.vertManual
177            bounds[3] = bounds[1] + totalheight
178
179        # FIXME: this is ugly - update bounds in helper state
180        phelper.states[(self,0)].bounds = bounds
181
182        # do no painting if hidden or no image
183        imgwidget = s.get('widgetName').findWidget()
184        if s.hide:
185            return bounds
186
187        self.updateAxisLocation(bounds)
188
189        # update image if necessary with new settings
190        if imgwidget is not None:
191            minval, maxval, axisscale, cmapname, trans, invert = \
192                imgwidget.getColorbarParameters()
193
194            cmap = self.document.evaluate.getColormap(cmapname, invert)
195
196            img = utils.makeColorbarImage(
197                minval, maxval, axisscale, cmap, trans,
198                direction=s.direction)
199        else:
200            # couldn't find widget
201            minval, maxval, axisscale = 0., 1., 'linear'
202            img = None
203
204        s.get('log').setSilent(axisscale == 'log')
205        self.setAutoRange([minval, maxval])
206        self.computePlottedRange(force=True)
207
208        # now draw image on axis...
209        minpix, maxpix = self.graphToPlotterCoords(
210            bounds, N.array([minval, maxval]) )
211
212        routside = qt.QRectF(
213            bounds[0], bounds[1],
214            bounds[2]-bounds[0], bounds[3]-bounds[1] )
215
216        # really draw the img
217        if img is not None:
218            # coordinates to draw image and to clip rectangle
219            if s.direction == 'horizontal':
220                c = [ minpix, bounds[1], maxpix, bounds[3] ]
221                cl = [ self.coordParr1, bounds[1], self.coordParr2, bounds[3] ]
222            else:
223                c = [ bounds[0], maxpix, bounds[2], minpix ]
224                cl = [ bounds[0], self.coordParr1, bounds[2], self.coordParr2 ]
225            r = qt.QRectF(c[0], c[1], c[2]-c[0], c[3]-c[1])
226            rclip = qt.QRectF(cl[0], cl[1], cl[2]-cl[0], cl[3]-cl[1])
227
228            painter.save()
229            painter.setClipRect(rclip & routside)
230            painter.drawImage(r, img)
231            #qtloops.plotImageAsRects(painter, r, img)
232            painter.restore()
233
234        # if there's a border
235        if not s.Border.hide:
236            painter.setPen( s.get('Border').makeQPen(painter) )
237            painter.setBrush( qt.QBrush() )
238            painter.drawRect( routside )
239
240        # actually draw axis
241        axis.Axis._axisDraw(self, bounds, parentposn, None, painter,
242                            phelper)
243
244# allow the factory to instantiate a colorbar
245document.thefactory.register( ColorBar )
246