Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,12 @@ set(SACNVIEW_HEADERS
src/widgets/checkableheader.h
src/models/sacnlistenermodel.h
src/delegates/resettablecounterdelegate.h
src/color_helpers.h
)

set(SACNVIEW_SOURCES
sacnview.natvis
src/color_helpers.cpp
src/commandline.cpp
src/firewallcheck.cpp
src/ipc.cpp
Expand Down
26 changes: 26 additions & 0 deletions src/color_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "color_helpers.h"
#include <QApplication>
#include <QPalette>

double calcLuminance(const QColor & color)
{
// https://w3c.github.io/wcag/guidelines/22/#dfn-relative-luminance
return 0.2126 * color.redF() + 0.7152 * color.greenF() + 0.0722 * color.blueF();
}

double calcContrastRatio(const QColor & color1, const QColor & color2)
{
const double luminance1 = calcLuminance(color1);
const double luminance2 = calcLuminance(color2);
const double lighter = std::max(luminance1, luminance2);
const double darker = std::min(luminance1, luminance2);
// https://w3c.github.io/wcag/guidelines/22/#dfn-contrast-ratio
return (lighter + 0.05) / (darker + 0.05);
}

QColor findBestContrastingColor(const QColor & bgColor)
{
const QPalette palette = qApp->palette();
const std::array fgColors = {palette.color(QPalette::Text), palette.color(QPalette::BrightText)};
return findBestContrastingColor(bgColor, fgColors.cbegin(), fgColors.cend());
}
57 changes: 57 additions & 0 deletions src/color_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#ifndef COLOR_HELPERS_H
#define COLOR_HELPERS_H

#include <QColor>

/**
* Calculate luminance in the sRGB color space.
*
* @see https://w3c.github.io/wcag/guidelines/22/#dfn-relative-luminance
*/
double calcLuminance(const QColor & color);

/**
* Calculate contrast ratio between two colors.
*
* @see https://w3c.github.io/wcag/guidelines/22/#dfn-contrast-ratio
*/
double calcContrastRatio(const QColor & color1, const QColor & color2);

/**
* Find the color in the iterator @p begin .. @p end that contrasts best with @p bgColor.
*
* @param bgColor Background color
* @param begin Start QColor iterator of possible foreground colors.
* @param end End QColor iterator.
*/
template<class FgColorIt>
QColor findBestContrastingColor(const QColor & bgColor, FgColorIt begin, FgColorIt end)
{
using ColorContrastRatio = std::tuple<QColor, double>;
std::vector<ColorContrastRatio> contrastRatios;

// Calculate ratios.
for (FgColorIt it = begin; it != end; ++it)
{
contrastRatios.emplace_back(*it, calcContrastRatio(bgColor, *it));
}

// Find the highest contrast ratio.
ColorContrastRatio best = contrastRatios.front();
for (const auto & contrastRatio : contrastRatios)
{
if (std::get<1>(best) < std::get<1>(contrastRatio))
{
best = contrastRatio;
}
}
return std::get<0>(best);
}

/**
* Find the which of the application palette's text colors best contrasts with @p bgColor.
* @param bgColor Background color
*/
QColor findBestContrastingColor(const QColor & bgColor);

#endif //COLOR_HELPERS_H
26 changes: 25 additions & 1 deletion src/models/sacnsourcetablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@

#include "sacnsourcetablemodel.h"

#include <QApplication>

#include "preferences.h"

#include "sacn/sacnlistener.h"

#include "color_helpers.h"

SACNSourceTableModel::SACNSourceTableModel(QObject * parent)
: QAbstractTableModel(parent)
{}
{
}

SACNSourceTableModel::~SACNSourceTableModel() {}

Expand Down Expand Up @@ -68,6 +73,8 @@ QVariant SACNSourceTableModel::data(const QModelIndex & index, int role) const

case Qt::BackgroundRole: return getBackgroundData(rowData, index.column());

case Qt::ForegroundRole: return getForegroundData(rowData, index.column());

case Qt::TextAlignmentRole:
switch (index.column())
{
Expand Down Expand Up @@ -218,6 +225,23 @@ QVariant SACNSourceTableModel::getBackgroundData(const RowData & rowData, int co
return QVariant();
}

QVariant SACNSourceTableModel::getForegroundData(const RowData & rowData, int column) const
{
const QVariant bgData = getBackgroundData(rowData, column);
if (!bgData.isValid())
{
return QVariant();
}

const QColor bgColor = bgData.value<QColor>();
if (bgColor.isValid())
{
return findBestContrastingColor(bgColor);
}

return QVariant();
}

QVariant SACNSourceTableModel::getTimingSummary(const RowData & rowData, int column) const
{
const FpsCounter::Histogram & histogram = rowData.histogram;
Expand Down
1 change: 1 addition & 0 deletions src/models/sacnsourcetablemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ private Q_SLOTS:
// Data
QVariant getDisplayData(const RowData & rowData, int column) const;
QVariant getBackgroundData(const RowData & rowData, int column) const;
QVariant getForegroundData(const RowData & rowData, int column) const;
QVariant getTimingSummary(const RowData & rowData, int column) const;

void RefreshAllTimingData();
Expand Down
4 changes: 4 additions & 0 deletions src/widgets/glscopewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include <QJsonArray>

#include "color_helpers.h"

static constexpr qreal AXIS_LABEL_WIDTH = 45.0;
static constexpr qreal AXIS_LABEL_HEIGHT = 20.0;
static constexpr qreal TOP_GAP = 10.0;
Expand Down Expand Up @@ -716,6 +718,8 @@ QVariant ScopeModel::data(const QModelIndex & index, int role) const
case COL_COLOUR:
if (role == Qt::BackgroundRole || role == Qt::DisplayRole || role == Qt::EditRole)
return trace->color();
if (role == Qt::ForegroundRole)
return findBestContrastingColor(trace->color());
if (role == DataSortRole) return static_cast<uint32_t>(trace->color().rgba());
if (role == Qt::ToolTipRole) return tr("Trace color (#RRGGBB)");
break;
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/glscopewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,4 +684,4 @@ class GlScopeWidget : public QOpenGLWidget, protected QOpenGLFunctions
std::vector<QVector2D> makeTriggerLine(ScopeModel::Trigger type);

void updateCursor(const QPoint & widgetPos);
};
};
27 changes: 23 additions & 4 deletions src/widgets/gridwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// limitations under the License.

#include "gridwidget.h"
#include "color_helpers.h"

#include <QApplication>
#include <QMouseEvent>
#include <QPainter>
Expand All @@ -29,7 +31,11 @@
#define CELL_COUNT 512

GridWidget::GridWidget(QWidget * parent)
: QWidget(parent), m_colors(CELL_COUNT, this->palette().color(QPalette::Base)), m_cellHeight(CELL_HEIGHT)
: QWidget(parent)
, m_bgColors(CELL_COUNT, this->palette().color(QPalette::Base))
, m_fgColors(CELL_COUNT, this->palette().color(QPalette::Text))
, m_possibleFgColors({this->palette().color(QPalette::Text), this->palette().color(QPalette::BrightText)})
, m_cellHeight(CELL_HEIGHT)
{
for (int i = 0; i < CELL_COUNT; i++)
{
Expand Down Expand Up @@ -117,10 +123,11 @@ void GridWidget::paintEvent(QPaintEvent * event)

if (!value.isEmpty())
{
QColor fillColor = m_colors[address];
QColor fillColor = m_bgColors[address];

QString rowLabel = value;
painter.fillRect(textRect, fillColor);
painter.setPen(m_fgColors[address]);
painter.drawText(textRect, Qt::AlignHCenter | Qt::AlignVCenter, rowLabel);
}
}
Expand Down Expand Up @@ -333,17 +340,29 @@ void GridWidget::mouseDoubleClickEvent(QMouseEvent * event)
void GridWidget::setAllCellColor(const QColor & color)
{
if (color.isValid())
m_colors.fill(color);
{
m_bgColors.fill(color);
const QColor fgColor = findBestContrastingColor(color, m_possibleFgColors.cbegin(), m_possibleFgColors.cend());
m_fgColors.fill(fgColor);
}
else
{
setAllCellColor(palette().color(QPalette::Base));
}
}

void GridWidget::setCellColor(int cell, const QColor & color)
{
if (color.isValid())
m_colors[cell] = color;
{
m_bgColors[cell] = color;
const QColor fgColor = findBestContrastingColor(color, m_possibleFgColors.cbegin(), m_possibleFgColors.cend());
m_fgColors[cell] = fgColor;
}
else
{
setCellColor(cell, palette().color(QPalette::Base));
}
}

void GridWidget::setCellValue(int cell, const QString & value)
Expand Down
4 changes: 3 additions & 1 deletion src/widgets/gridwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ class GridWidget : public QWidget
private:

QList<int> m_selectedAddresses;
QVector<QColor> m_colors;
QVector<QColor> m_bgColors;
QVector<QColor> m_fgColors;
std::array<QColor, 2> m_possibleFgColors;
QStringList m_values;
bool m_allowMultiSelect = false;
QPoint m_lastClickPoint;
Expand Down
Loading