2 ## This file is part of the sigrok-meter project.
4 ## Copyright (C) 2014 Jens Steinhauser <jens.steinhauser@gmail.com>
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 import sigrok
.core
as sr
24 QtCore
= qtcompat
.QtCore
25 QtGui
= qtcompat
.QtGui
27 class MeasurementDataModel(QtGui
.QStandardItemModel
):
28 '''Model to hold the measured values.'''
30 '''Role used to identify and find the item.'''
31 _idRole
= QtCore
.Qt
.UserRole
+ 1
33 '''Role used to store the device vendor and model.'''
34 descRole
= QtCore
.Qt
.UserRole
+ 2
36 def __init__(self
, parent
):
37 super(self
.__class
__, self
).__init
__(parent
)
39 # Use the description text to sort the items for now, because the
40 # _idRole holds tuples, and using them to sort doesn't work.
41 self
.setSortRole(MeasurementDataModel
.descRole
)
43 # Used in 'format_value()' to check against.
44 self
.inf
= float('inf')
46 def format_unit(self
, u
):
50 sr
.Unit
.OHM
: u
'\u03A9',
53 sr
.Unit
.CELSIUS
: u
'\u00B0C',
54 sr
.Unit
.FAHRENHEIT
: u
'\u00B0F',
56 sr
.Unit
.PERCENTAGE
: '%',
60 sr
.Unit
.DECIBEL_MW
: 'dBu',
61 sr
.Unit
.DECIBEL_VOLT
: 'dBV',
63 sr
.Unit
.DECIBEL_SPL
: 'dB',
64 # sr.Unit.CONCENTRATION
65 sr
.Unit
.REVOLUTIONS_PER_MINUTE
: 'rpm',
66 sr
.Unit
.VOLT_AMPERE
: 'VA',
68 sr
.Unit
.WATT_HOUR
: 'Wh',
69 sr
.Unit
.METER_SECOND
: 'm/s',
70 sr
.Unit
.HECTOPASCAL
: 'hPa',
71 sr
.Unit
.HUMIDITY_293K
: '%rF',
72 sr
.Unit
.DEGREE
: u
'\u00B0',
76 return units
.get(u
, '')
78 def format_mqflags(self
, mqflags
):
79 if sr
.QuantityFlag
.AC
in mqflags
:
81 elif sr
.QuantityFlag
.DC
in mqflags
:
86 def format_value(self
, mag
):
89 return '{:f}'.format(mag
)
91 def getItem(self
, device
, channel
):
92 '''Returns the item for the device + channel combination from the model,
93 or creates a new item if no existing one matches.'''
95 # unique identifier for the device + channel
96 # TODO: isn't there something better?
100 device
.serial_number(),
101 device
.connection_id(),
105 # find the correct item in the model
106 for row
in range(self
.rowCount()):
107 item
= self
.item(row
)
108 rid
= item
.data(MeasurementDataModel
._idRole
)
109 rid
= tuple(rid
) # PySide returns a list
113 # nothing found, create a new item
114 desc
= '{} {}, channel "{}"'.format(
115 device
.vendor
, device
.model
, channel
.name
)
117 item
= QtGui
.QStandardItem()
118 item
.setData(uid
, MeasurementDataModel
._idRole
)
119 item
.setData(desc
, MeasurementDataModel
.descRole
)
124 @QtCore.Slot(object, object, object)
125 def update(self
, device
, channel
, data
):
126 '''Updates the data for the device (+channel) with the most recent
127 measurement from the given payload.'''
129 item
= self
.getItem(device
, channel
)
131 value
, unit
, mqflags
= data
132 value_str
= self
.format_value(value
)
133 unit_str
= self
.format_unit(unit
)
134 mqflags_str
= self
.format_mqflags(mqflags
)
136 disp
= ' '.join([value_str
, unit_str
, mqflags_str
])
137 item
.setData(disp
, QtCore
.Qt
.DisplayRole
)
139 class MultimeterDelegate(QtGui
.QStyledItemDelegate
):
140 '''Delegate to show the data items from a MeasurementDataModel.'''
142 def __init__(self
, parent
, font
):
143 '''Initializes the delegate.
145 :param font: Font used for the description text, the value is drawn
146 with a slightly bigger and bold variant of the font.
149 super(self
.__class
__, self
).__init
__(parent
)
152 self
._bfont
= QtGui
.QFont(self
._nfont
)
154 self
._bfont
.setBold(True)
155 if self
._bfont
.pixelSize() != -1:
156 self
._bfont
.setPixelSize(self
._bfont
.pixelSize() * 1.8)
158 self
._bfont
.setPointSizeF(self
._bfont
.pointSizeF() * 1.8)
160 fi
= QtGui
.QFontInfo(self
._nfont
)
161 self
._nfontheight
= fi
.pixelSize()
163 fm
= QtGui
.QFontMetrics(self
._bfont
)
164 r
= fm
.boundingRect('-XX.XXXXXX X XX')
165 self
._size
= QtCore
.QSize(r
.width() * 1.2, r
.height() * 3.5)
167 def sizeHint(self
, option
=None, index
=None):
170 def paint(self
, painter
, options
, index
):
171 value
= index
.data(QtCore
.Qt
.DisplayRole
)
172 desc
= index
.data(MeasurementDataModel
.descRole
)
174 # description in the top left corner
175 painter
.setFont(self
._nfont
)
176 p
= options
.rect
.topLeft()
177 p
+= QtCore
.QPoint(self
._nfontheight
, 2 * self
._nfontheight
)
178 painter
.drawText(p
, desc
)
180 # value in the center
181 painter
.setFont(self
._bfont
)
182 r
= options
.rect
.adjusted(self
._nfontheight
, 2.5 * self
._nfontheight
,
184 painter
.drawText(r
, QtCore
.Qt
.AlignCenter
, value
)