|
|
@@ -2,7 +2,7 @@ |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
# Digital Peak Meter, a custom Qt4 widget |
|
|
|
# Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> |
|
|
|
# Copyright (C) 2011-2015 Filipe Coelho <falktx@falktx.com> |
|
|
|
# |
|
|
|
# This program is free software; you can redistribute it and/or |
|
|
|
# modify it under the terms of the GNU General Public License as |
|
|
@@ -36,151 +36,231 @@ else: |
|
|
|
# Widget Class |
|
|
|
|
|
|
|
class DigitalPeakMeter(QWidget): |
|
|
|
# enum Color |
|
|
|
COLOR_GREEN = 1 |
|
|
|
COLOR_BLUE = 2 |
|
|
|
|
|
|
|
# enum Orientation |
|
|
|
HORIZONTAL = 1 |
|
|
|
VERTICAL = 2 |
|
|
|
|
|
|
|
# enum Color |
|
|
|
GREEN = 1 |
|
|
|
BLUE = 2 |
|
|
|
|
|
|
|
# enum Style |
|
|
|
STYLE_DEFAULT = 1 |
|
|
|
STYLE_OPENAV = 2 |
|
|
|
STYLE_RNCBC = 3 |
|
|
|
|
|
|
|
def __init__(self, parent): |
|
|
|
QWidget.__init__(self, parent) |
|
|
|
|
|
|
|
self.fChannels = 0 |
|
|
|
self.fDrawLines = True |
|
|
|
self.fOrientation = self.VERTICAL |
|
|
|
# defaults are VERTICAL, COLOR_GREEN, STYLE_DEFAULT |
|
|
|
|
|
|
|
self.fChannelCount = 0 |
|
|
|
self.fChannelData = [] |
|
|
|
self.fLastChannelData = [] |
|
|
|
|
|
|
|
self.fMeterColor = self.COLOR_GREEN |
|
|
|
self.fMeterColorBase = QColor(93, 231, 61) |
|
|
|
self.fMeterColorBaseAlt = QColor(15, 110, 15, 100) |
|
|
|
|
|
|
|
self.fMeterLinesEnabled = True |
|
|
|
self.fMeterOrientation = self.VERTICAL |
|
|
|
self.fMeterStyle = self.STYLE_DEFAULT |
|
|
|
|
|
|
|
self.fMeterBackground = QColor("#111111") |
|
|
|
self.fMeterGradient = QLinearGradient(0, 0, 0, 0) |
|
|
|
|
|
|
|
self.fSmoothMultiplier = 1 |
|
|
|
|
|
|
|
self.fColorBackground = QColor("#111111") |
|
|
|
self.fGradientMeter = QLinearGradient(0, 0, 1, 1) |
|
|
|
self.updateGrandient() |
|
|
|
|
|
|
|
self.fMeterStyle = self.STYLE_DEFAULT |
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
self.setChannels(0) |
|
|
|
self.setColor(self.GREEN) |
|
|
|
def channelCount(self): |
|
|
|
return self.fChannelCount |
|
|
|
|
|
|
|
def displayMeter(self, meter, level, forced = False): |
|
|
|
if meter <= 0 or meter > self.fChannels: |
|
|
|
return qCritical("DigitalPeakMeter::displayMeter(%i, %f) - invalid meter number" % (meter, level)) |
|
|
|
if not isinstance(level, float): |
|
|
|
return qCritical("DigitalPeakMeter::displayMeter(%i, %f) - meter value must be float" % (meter, level)) |
|
|
|
def setChannelCount(self, count): |
|
|
|
if self.fChannelCount == count: |
|
|
|
return |
|
|
|
|
|
|
|
i = meter - 1 |
|
|
|
if count < 0: |
|
|
|
return qCritical("DigitalPeakMeter::setChannelCount(%i) - channel count must be a positive integer or zero" % count) |
|
|
|
|
|
|
|
if self.fSmoothMultiplier > 0 and not forced: |
|
|
|
level = (self.fLastValueData[i] * self.fSmoothMultiplier + level) / float(self.fSmoothMultiplier + 1) |
|
|
|
self.fChannelCount = count |
|
|
|
self.fChannelData = [] |
|
|
|
self.fLastChannelData = [] |
|
|
|
|
|
|
|
if level < 0.001: |
|
|
|
level = 0.0 |
|
|
|
elif level > 0.999: |
|
|
|
level = 1.0 |
|
|
|
for x in range(count): |
|
|
|
self.fChannelData.append(0.0) |
|
|
|
self.fLastChannelData.append(0.0) |
|
|
|
|
|
|
|
if self.fChannelsData[i] != level: |
|
|
|
self.fChannelsData[i] = level |
|
|
|
self.update() |
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def meterColor(self): |
|
|
|
return self.fMeterColor |
|
|
|
|
|
|
|
self.fLastValueData[i] = level |
|
|
|
def setMeterColor(self, color): |
|
|
|
if self.fMeterColor == color: |
|
|
|
return |
|
|
|
|
|
|
|
def setChannels(self, channels): |
|
|
|
if channels < 0: |
|
|
|
return qCritical("DigitalPeakMeter::setChannels(%i) - 'channels' must be a positive integer" % channels) |
|
|
|
if color not in (self.COLOR_GREEN, self.COLOR_BLUE): |
|
|
|
return qCritical("DigitalPeakMeter::setMeterColor(%i) - invalid color" % color) |
|
|
|
|
|
|
|
self.fChannels = channels |
|
|
|
self.fChannelsData = [] |
|
|
|
self.fLastValueData = [] |
|
|
|
self.fMeterColor = color |
|
|
|
|
|
|
|
for x in range(channels): |
|
|
|
self.fChannelsData.append(0.0) |
|
|
|
self.fLastValueData.append(0.0) |
|
|
|
if color == self.COLOR_GREEN: |
|
|
|
self.fMeterColorBase = QColor(93, 231, 61) |
|
|
|
self.fMeterColorBaseAlt = QColor(15, 110, 15, 100) |
|
|
|
elif color == self.COLOR_BLUE: |
|
|
|
self.fMeterColorBase = QColor(82, 238, 248) |
|
|
|
self.fMeterColorBaseAlt = QColor(15, 15, 110, 100) |
|
|
|
|
|
|
|
def setColor(self, color): |
|
|
|
if color == self.GREEN: |
|
|
|
self.fColorBase = QColor(93, 231, 61) |
|
|
|
self.fColorBaseAlt = QColor(15, 110, 15, 100) |
|
|
|
elif color == self.BLUE: |
|
|
|
self.fColorBase = QColor(82, 238, 248) |
|
|
|
self.fColorBaseAlt = QColor(15, 15, 110, 100) |
|
|
|
else: |
|
|
|
return qCritical("DigitalPeakMeter::setColor(%i) - invalid color" % color) |
|
|
|
self.updateGrandient() |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def meterLinesEnabled(self): |
|
|
|
return self.fMeterLinesEnabled |
|
|
|
|
|
|
|
def setMeterLinesEnabled(self, yesNo): |
|
|
|
if self.fMeterLinesEnabled == yesNo: |
|
|
|
return |
|
|
|
|
|
|
|
self.fMeterLinesEnabled = yesNo |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def meterOrientation(self): |
|
|
|
return self.fMeterOrientation |
|
|
|
|
|
|
|
def setMeterOrientation(self, orientation): |
|
|
|
if self.fMeterOrientation == orientation: |
|
|
|
return |
|
|
|
|
|
|
|
self.setOrientation(self.fOrientation) |
|
|
|
if orientation not in (self.HORIZONTAL, self.VERTICAL): |
|
|
|
return qCritical("DigitalPeakMeter::setMeterOrientation(%i) - invalid orientation" % orientation) |
|
|
|
|
|
|
|
self.fMeterOrientation = orientation |
|
|
|
|
|
|
|
self.updateGrandient() |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def meterStyle(self): |
|
|
|
return self.fMeterStyle |
|
|
|
|
|
|
|
def setMeterStyle(self, style): |
|
|
|
self.fMeterStyle = style |
|
|
|
self.setOrientation(self.fOrientation) |
|
|
|
if self.fMeterStyle == style: |
|
|
|
return |
|
|
|
|
|
|
|
def setLinesEnabled(self, yesNo): |
|
|
|
self.fDrawLines = yesNo |
|
|
|
if style not in (self.STYLE_DEFAULT, self.STYLE_OPENAV, self.STYLE_RNCBC): |
|
|
|
return qCritical("DigitalPeakMeter::setMeterStyle(%i) - invalid style" % style) |
|
|
|
|
|
|
|
def setOrientation(self, orientation): |
|
|
|
self.fOrientation = orientation |
|
|
|
self.fGradientMeter = QLinearGradient(0, 0, 1, 1) |
|
|
|
self.fMeterStyle = style |
|
|
|
|
|
|
|
if self.fMeterStyle == self.STYLE_OPENAV: |
|
|
|
self.fGradientMeter.setColorAt(0.0, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(1.0, self.fColorBase) |
|
|
|
if style == self.STYLE_DEFAULT: |
|
|
|
self.fMeterBackground = QColor("#111111") |
|
|
|
elif style == self.STYLE_OPENAV: |
|
|
|
self.fMeterBackground = QColor("#1A1A1A") |
|
|
|
elif style == self.STYLE_RNCBC: |
|
|
|
self.fMeterBackground = QColor("#111111") |
|
|
|
|
|
|
|
elif self.fOrientation == self.HORIZONTAL: |
|
|
|
self.fGradientMeter.setColorAt(0.0, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(0.2, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(0.4, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(0.6, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(0.8, Qt.yellow) |
|
|
|
self.fGradientMeter.setColorAt(1.0, Qt.red) |
|
|
|
self.updateGrandient() |
|
|
|
|
|
|
|
elif self.fOrientation == self.VERTICAL: |
|
|
|
self.fGradientMeter.setColorAt(0.0, Qt.red) |
|
|
|
self.fGradientMeter.setColorAt(0.2, Qt.yellow) |
|
|
|
self.fGradientMeter.setColorAt(0.4, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(0.6, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(0.8, self.fColorBase) |
|
|
|
self.fGradientMeter.setColorAt(1.0, self.fColorBase) |
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
else: |
|
|
|
return qCritical("DigitalPeakMeter::setOrientation(%i) - invalid orientation" % orientation) |
|
|
|
def smoothMultiplier(self): |
|
|
|
return self.fSmoothMultiplier |
|
|
|
|
|
|
|
self.updateSizes() |
|
|
|
def setSmoothMultiplier(self, value): |
|
|
|
if self.fSmoothMultiplier == value: |
|
|
|
return |
|
|
|
|
|
|
|
def setSmoothRelease(self, value): |
|
|
|
if not isinstance(value, int): |
|
|
|
return qCritical("DigitalPeakMeter::setSmoothMultiplier() - value must be an integer") |
|
|
|
if value < 0: |
|
|
|
value = 0 |
|
|
|
elif value > 5: |
|
|
|
value = 5 |
|
|
|
return qCritical("DigitalPeakMeter::setSmoothMultiplier(%i) - value must be >= 0" % value) |
|
|
|
if value > 5: |
|
|
|
return qCritical("DigitalPeakMeter::setSmoothMultiplier(%i) - value must be < 5" % value) |
|
|
|
|
|
|
|
self.fSmoothMultiplier = value |
|
|
|
|
|
|
|
def minimumSizeHint(self): |
|
|
|
return QSize(10, 10) |
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def sizeHint(self): |
|
|
|
return QSize(self.fWidth, self.fHeight) |
|
|
|
def displayMeter(self, meter, level, forced = False): |
|
|
|
if not isinstance(meter, int): |
|
|
|
return qCritical("DigitalPeakMeter::displayMeter(,) - meter value must be an integer") |
|
|
|
if not isinstance(level, float): |
|
|
|
return qCritical("DigitalPeakMeter::displayMeter(%i,) - level value must be a float" % (meter,)) |
|
|
|
if meter <= 0 or meter > self.fChannelCount: |
|
|
|
return qCritical("DigitalPeakMeter::displayMeter(%i, %f) - invalid meter number" % (meter, level)) |
|
|
|
|
|
|
|
def updateSizes(self): |
|
|
|
self.fWidth = self.width() |
|
|
|
self.fHeight = self.height() |
|
|
|
self.fSizeMeter = 0 |
|
|
|
i = meter - 1 |
|
|
|
|
|
|
|
if self.fOrientation == self.HORIZONTAL: |
|
|
|
self.fGradientMeter.setFinalStop(self.fWidth, 0) |
|
|
|
if self.fSmoothMultiplier > 0 and not forced: |
|
|
|
level = (self.fLastChannelData[i] * float(self.fSmoothMultiplier) + level) / float(self.fSmoothMultiplier + 1) |
|
|
|
|
|
|
|
if self.fChannels > 0: |
|
|
|
self.fSizeMeter = self.fHeight / self.fChannels |
|
|
|
if level < 0.001: |
|
|
|
level = 0.0 |
|
|
|
elif level > 0.999: |
|
|
|
level = 1.0 |
|
|
|
|
|
|
|
elif self.fOrientation == self.VERTICAL: |
|
|
|
self.fGradientMeter.setFinalStop(0, self.fHeight) |
|
|
|
if self.fChannelData[i] != level: |
|
|
|
self.fChannelData[i] = level |
|
|
|
self.update() |
|
|
|
|
|
|
|
self.fLastChannelData[i] = level |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def updateGrandient(self): |
|
|
|
self.fMeterGradient = QLinearGradient(0, 0, 1, 1) |
|
|
|
|
|
|
|
if self.fMeterStyle == self.STYLE_OPENAV: |
|
|
|
self.fMeterGradient.setColorAt(0.0, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(1.0, self.fMeterColorBase) |
|
|
|
|
|
|
|
if self.fChannels > 0: |
|
|
|
self.fSizeMeter = self.fWidth / self.fChannels |
|
|
|
elif self.fMeterOrientation == self.HORIZONTAL: |
|
|
|
self.fMeterGradient.setColorAt(0.0, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(0.2, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(0.4, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(0.6, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(0.8, Qt.yellow) |
|
|
|
self.fMeterGradient.setColorAt(1.0, Qt.red) |
|
|
|
|
|
|
|
elif self.fMeterOrientation == self.VERTICAL: |
|
|
|
self.fMeterGradient.setColorAt(0.0, Qt.red) |
|
|
|
self.fMeterGradient.setColorAt(0.2, Qt.yellow) |
|
|
|
self.fMeterGradient.setColorAt(0.4, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(0.6, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(0.8, self.fMeterColorBase) |
|
|
|
self.fMeterGradient.setColorAt(1.0, self.fMeterColorBase) |
|
|
|
|
|
|
|
self.updateGrandientFinalStop() |
|
|
|
|
|
|
|
def updateGrandientFinalStop(self): |
|
|
|
if self.fMeterOrientation == self.HORIZONTAL: |
|
|
|
self.fMeterGradient.setFinalStop(self.width(), 0) |
|
|
|
|
|
|
|
elif self.fMeterOrientation == self.VERTICAL: |
|
|
|
self.fMeterGradient.setFinalStop(0, self.height()) |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def minimumSizeHint(self): |
|
|
|
return QSize(10, 10) |
|
|
|
|
|
|
|
def sizeHint(self): |
|
|
|
return QSize(self.width(), self.height()) |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def paintEvent(self, event): |
|
|
|
painter = QPainter(self) |
|
|
|
event.accept() |
|
|
|
|
|
|
|
width = self.width() |
|
|
|
height = self.height() |
|
|
|
|
|
|
|
if self.fMeterStyle == self.STYLE_OPENAV: |
|
|
|
painter.setPen(QColor("#1A1A1A")) |
|
|
|
painter.setBrush(QColor("#1A1A1A")) |
|
|
@@ -188,35 +268,35 @@ class DigitalPeakMeter(QWidget): |
|
|
|
painter.setPen(Qt.black) |
|
|
|
painter.setBrush(Qt.black) |
|
|
|
|
|
|
|
painter.drawRect(0, 0, self.fWidth, self.fHeight) |
|
|
|
painter.drawRect(0, 0, width, height) |
|
|
|
|
|
|
|
meterX = 0 |
|
|
|
startX = -1 if self.fMeterStyle == self.STYLE_OPENAV else 0 |
|
|
|
padding = 2 if self.fMeterStyle == self.STYLE_OPENAV else 0 |
|
|
|
|
|
|
|
painter.setPen(self.fColorBackground) |
|
|
|
painter.setBrush(self.fGradientMeter) |
|
|
|
painter.setPen(self.fMeterBackground) # FIXME ? |
|
|
|
painter.setBrush(self.fMeterGradient) |
|
|
|
|
|
|
|
if self.fMeterStyle == self.STYLE_OPENAV: |
|
|
|
color = self.fGradientMeter.stops()[0][1] |
|
|
|
painter.setPen(color) |
|
|
|
color.setAlphaF(0.5) |
|
|
|
painter.setBrush(color) |
|
|
|
del color |
|
|
|
#if self.fMeterStyle == self.STYLE_OPENAV: |
|
|
|
#color = self.fMeterGradient.stops()[0][1] |
|
|
|
#painter.setPen(color) |
|
|
|
#color.setAlphaF(0.5) |
|
|
|
#painter.setBrush(color) |
|
|
|
#del color |
|
|
|
|
|
|
|
for i in range(self.fChannels): |
|
|
|
for i in range(self.fChannelCount): |
|
|
|
level = self.fChannelsData[i] |
|
|
|
|
|
|
|
if self.fOrientation == self.HORIZONTAL: |
|
|
|
value = level * float(self.fWidth) |
|
|
|
elif self.fOrientation == self.VERTICAL: |
|
|
|
value = float(self.fHeight) - (level * float(self.fHeight)) |
|
|
|
if self.fMeterOrientation == self.HORIZONTAL: |
|
|
|
value = level * float(width) |
|
|
|
elif self.fMeterOrientation == self.VERTICAL: |
|
|
|
value = float(height) - (level * float(height)) |
|
|
|
else: |
|
|
|
value = 0.0 |
|
|
|
|
|
|
|
if self.fOrientation == self.HORIZONTAL: |
|
|
|
if self.fMeterOrientation == self.HORIZONTAL: |
|
|
|
painter.drawRect(startX, meterX+padding, int(value), self.fSizeMeter-padding*(1 if self.fChannels > 1 else 2)) |
|
|
|
elif self.fOrientation == self.VERTICAL: |
|
|
|
elif self.fMeterOrientation == self.VERTICAL: |
|
|
|
painter.drawRect(meterX, int(value), self.fSizeMeter, self.fHeight) |
|
|
|
|
|
|
|
meterX += self.fSizeMeter |
|
|
@@ -287,7 +367,30 @@ class DigitalPeakMeter(QWidget): |
|
|
|
painter.setPen(QColor(110, 15, 15, 100)) |
|
|
|
painter.drawLine(2, lsmall - (lsmall * 0.96), lfull-2.0, lsmall - (lsmall * 0.96)) |
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
def resizeEvent(self, event): |
|
|
|
self.updateSizes() |
|
|
|
self.updateGrandientFinalStop() |
|
|
|
QWidget.resizeEvent(self, event) |
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------------------------------------ |
|
|
|
# Main Testing |
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
import sys |
|
|
|
import resources_rc |
|
|
|
|
|
|
|
if config_UseQt5: |
|
|
|
from PyQt5.QtWidgets import QApplication |
|
|
|
else: |
|
|
|
from PyQt4.QtGui import QApplication |
|
|
|
|
|
|
|
app = QApplication(sys.argv) |
|
|
|
|
|
|
|
gui = DigitalPeakMeter(None) |
|
|
|
gui.setChannelCount(2) |
|
|
|
gui.displayMeter(1, 0.5) |
|
|
|
gui.displayMeter(2, 0.8) |
|
|
|
gui.show() |
|
|
|
|
|
|
|
sys.exit(app.exec_()) |