Krita Source Code Documentation
Loading...
Searching...
No Matches
KisHistogramView.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Krita
3 *
4 * SPDX-FileCopyrightText: 2021 Deif Lou <ginoba@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include <QMouseEvent>
10
11#include <kis_histogram.h>
12#include <KoColorSpace.h>
13#include <KisHistogramPainter.h>
14
15#include "KisHistogramView.h"
16
27
29 : QWidget(parent)
30 , m_d(new Private)
31{}
32
34{
35 qDeleteAll(m_d->histogramPainters);
36}
37
39 const QVector<const KoColorSpace*> &colorSpaces,
40 const QVector<QVector<int>> &channels)
41{
42 Q_ASSERT(colorSpaces.size() == histograms.size());
43 Q_ASSERT(channels.size() == 0 || channels.size() == histograms.size());
44
45 m_d->histogramIndex = 0;
46 qDeleteAll(m_d->histogramPainters);
47 m_d->histogramPainters.clear();
48
49 if (histograms.size() == 0) {
50 return;
51 }
52
53 QVector<QVector<int>> autoGeneratedChannels;
54 if (channels.size() == 0) {
55 for (int i = 0; i < histograms.size(); ++i) {
56 autoGeneratedChannels.append(QVector<int>());
57 }
58 }
59
60 const QVector<QVector<int>> &finalChannels =
61 channels.size() == 0 ? autoGeneratedChannels : channels;
62
63 for (int i = 0; i < histograms.size(); ++i) {
64 m_d->histogramPainters.append(new KisHistogramPainter());
65 m_d->histogramPainters[i]->setup(histograms[i], colorSpaces[i], finalChannels[i]);
66 }
67}
68
70{
71 return m_d->histogramPainters[m_d->histogramIndex]->channels();
72}
73
74void KisHistogramView::setChannel(int channel, int histogramIndex)
75{
76 setChannels({channel}, histogramIndex);
77}
78
79void KisHistogramView::setChannels(const QVector<int> &channels, int histogramIndex)
80{
81 Q_ASSERT(m_d->histogramPainters.size() > 0);
82 Q_ASSERT(histogramIndex >= 0 && histogramIndex < m_d->histogramPainters.size());
83
84 const QColor defaultColor = m_d->histogramPainters[m_d->histogramIndex]->defaultColor();
85 const bool isLogarithmic = m_d->histogramPainters[m_d->histogramIndex]->isLogarithmic();
86
87 m_d->histogramIndex = histogramIndex;
88 m_d->histogramPainters[m_d->histogramIndex]->setChannels(channels);
89 m_d->histogramPainters[m_d->histogramIndex]->setDefaultColor(defaultColor);
90 m_d->histogramPainters[m_d->histogramIndex]->setLogarithmic(isLogarithmic);
92
93 update();
94}
95
100
102{
103 Q_ASSERT(m_d->histogramPainters.size() > 0);
104
105 return m_d->histogramPainters[m_d->histogramIndex]->defaultColor();
106}
107
108void KisHistogramView::setDefaultColor(const QColor &newDefaultColor)
109{
110 Q_ASSERT(m_d->histogramPainters.size() > 0);
111
112 m_d->histogramPainters[m_d->histogramIndex]->setDefaultColor(newDefaultColor);
113 update();
114}
115
117{
118 Q_ASSERT(m_d->histogramPainters.size() > 0);
119
120 return m_d->histogramPainters[m_d->histogramIndex]->scale();
121}
122
123void KisHistogramView::setScale(qreal newScale)
124{
125 Q_ASSERT(m_d->histogramPainters.size() > 0);
126
127 m_d->histogramPainters[m_d->histogramIndex]->setScale(newScale);
128 update();
129}
130
132{
133 setScale(1.0);
134}
135
137{
138 Q_ASSERT(m_d->histogramPainters.size() > 0);
139
140 m_d->histogramPainters[m_d->histogramIndex]->setScaleToCutLongPeaks();
141 update();
142}
143
145{
146 Q_ASSERT(m_d->histogramPainters.size() > 0);
147
148 return m_d->histogramPainters[m_d->histogramIndex]->isLogarithmic();
149}
150
152{
153 Q_ASSERT(m_d->histogramPainters.size() > 0);
154
155 m_d->histogramPainters[m_d->histogramIndex]->setLogarithmic(logarithmic);
157 update();
158}
159
161{
162 Q_UNUSED(e);
163
164 QPainter painter(this);
165
166 // Background
167 painter.fillRect(rect(), palette().base());
168
169 // Histogram
170 if (m_d->histogramPainters.size() > 0 &&
171 m_d->histogramPainters[m_d->histogramIndex]->channels().size() > 0) {
172 // Histogram
173 QImage histogramImage = m_d->histogramPainters[m_d->histogramIndex]->paint(size());
174 // Shadow
175 QLinearGradient shadowGradient(QPointF(0.0, 0.0), QPointF(0.0, static_cast<qreal>(height()) * 0.2));
176 shadowGradient.setColorAt(0.00, QColor(0, 0, 0, 64));
177 shadowGradient.setColorAt(0.25, QColor(0, 0, 0, 36));
178 shadowGradient.setColorAt(0.50, QColor(0, 0, 0, 16));
179 shadowGradient.setColorAt(0.75, QColor(0, 0, 0, 4));
180 shadowGradient.setColorAt(1.00, QColor(0, 0, 0, 0));
181 QPainter histogramPainter(&histogramImage);
182 histogramPainter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
183 histogramPainter.fillRect(histogramImage.rect(), shadowGradient);
184 if (!isEnabled()) {
185 painter.setOpacity(0.5);
186 }
187 painter.drawImage(0, 0, histogramImage);
188 painter.setOpacity(1.0);
189 } else {
190 const qreal w = static_cast<qreal>(width());
191 const qreal h = static_cast<qreal>(height());
192 const qreal radius = qMin(w, h) * 0.3;
193 const QPointF center = QPointF(w / 2.0, h / 2.0);
194 const int penWidth = static_cast<int>(qRound(radius / 8));
195 painter.setPen(QPen(palette().alternateBase(), penWidth, Qt::SolidLine, Qt::FlatCap));
196 painter.setBrush(Qt::NoBrush);
197 painter.setRenderHint(QPainter::Antialiasing);
198 painter.drawEllipse(center, radius, radius);
199 painter.drawLine(center + QPointF(radius, -radius), center + QPointF(-radius, radius));
200 }
201
202 // Border
203 QColor c = palette().text().color();
204 c.setAlpha(64);
205 painter.setPen(QPen(c, 1));
206 painter.setBrush(Qt::NoBrush);
207 painter.setRenderHint(QPainter::Antialiasing, false);
208 painter.drawRect(0, 0, width() - 1, height() - 1);
209}
210
212{
213 if (m_d->histogramPainters.size() == 0 ||
214 m_d->histogramPainters[m_d->histogramIndex]->channels().size() == 0) {
215 return;
216 }
217
218 if (e->button() != Qt::LeftButton) {
219 return;
220 }
221
222 if (qFuzzyCompare(scale(), 1.0)) {
224 } else {
226 }
227}
228
230{
231 if (m_d->histogramPainters.size() == 0 ||
232 m_d->histogramPainters[m_d->histogramIndex]->channels().size() == 0) {
233 return;
234 }
235
236 if (e->button() != Qt::LeftButton) {
237 return;
238 }
239
240 m_d->preDraggingScale = scale();
241 m_d->draggingStartMouseY = e->y();
242 m_d->isScaling = false;
243}
244
246{
247 if (m_d->histogramPainters.size() == 0 ||
248 m_d->histogramPainters[m_d->histogramIndex]->channels().size() == 0) {
249 return;
250 }
251
252 if (!(e->buttons() & Qt::LeftButton)) {
253 return;
254 }
255
256 if (m_d->isScaling) {
257 const qreal newScale =
258 m_d->preDraggingScale * static_cast<qreal>(height() - e->y()) /
259 static_cast<qreal>(height() - m_d->draggingStartMouseY);
260 setScale(qMax(newScale, 1.0));
261 } else {
262 if (qAbs(e->y() - m_d->draggingStartMouseY) > 4) {
263 m_d->isScaling = true;
264 }
265 }
266
267}
A class that can render different KisHistograms. It renders a somewhat smooth shape (with different c...
QVector< KisHistogramPainter * > histogramPainters
const QVector< int > & channels() const
Returns the channels that are available for the currently selected histogram.
QColor defaultColor() const
Returns the color that is being used to paint a generic histogram. All the histogram channels will us...
void setScaleToCutLongPeaks()
Sometimes there can be some outliers in the histogram that show in the widget as long vertical peaks....
bool isLogarithmic() const
Returns true if the histogram shape being shown is formed by the logarithmic mapping of the original ...
void mouseMoveEvent(QMouseEvent *e) override
KisHistogramView(QWidget *parent)
void setDefaultColor(const QColor &newDefaultColor)
Set the default color used when there is no preference to color the selected histogram.
void setLogarithmic(bool logarithmic)
Set if the histogram shape being shown is formed by the logarithmic mapping of the original histogram...
void setChannels(const QVector< int > &channels, int histogramIndex=0)
Activates the given channels of the given histogram. This allows to change the view between the diffe...
void paintEvent(QPaintEvent *e) override
void clearChannels()
This clears the channel selection. The widget will show a null symbol in it's center when there are n...
void mousePressEvent(QMouseEvent *e) override
void setScaleToFit()
Set the scale used to paint the widget to 1. You can also return to a scale of 1 by double clicking o...
void setScale(qreal newScale)
Set the scale used to paint the widget. The scale can also be changed by clicking and dragging up/dow...
void setup(const QVector< KisHistogram * > &histograms, const QVector< const KoColorSpace * > &colorSpaces, const QVector< QVector< int > > &channels={})
Sets up the widget by passing a collection of KisHistograms, the color space for each histogram and t...
qreal scale() const
Return the vertical scale that is used to paint the histogram shape. A scale of 1 will show all the h...
QScopedPointer< Private > m_d
void mouseDoubleClickEvent(QMouseEvent *e) override
void setChannel(int channel, int histogramIndex=0)
Activates the given channel of the given histogram. This allows to change the view between the differ...
static bool qFuzzyCompare(half p1, half p2)
rgba palette[MAX_PALETTE]
Definition palette.c:35