Krita Source Code Documentation
Loading...
Searching...
No Matches
channelmodel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Sven Langkamp <sven.langkamp@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "channelmodel.h"
8#include <QImage>
9#include <KoColorSpace.h>
10#include <KoChannelInfo.h>
12
13#include <kis_painter.h>
14
15#include <kis_group_layer.h>
16#include <kis_paint_device.h>
17#include <kis_iterator_ng.h>
18#include <kis_default_bounds.h>
19
20#include <kis_canvas2.h>
21
23 QAbstractTableModel(parent),
24 m_canvas(nullptr),
25 m_channelCount(0)
26{
27 setThumbnailSizeLimit(QSize(64, 64));
28}
29
33
34QVariant ChannelModel::data(const QModelIndex& index, int role) const
35{
36 if (m_canvas && m_canvas->image() && index.isValid()) {
37 KisGroupLayerSP rootLayer = m_canvas->image()->rootLayer();
38 const KoColorSpace *cs = rootLayer->colorSpace();
39 if (cs->channelCount() != m_channelCount) return QVariant();
40
41 const QList<KoChannelInfo*> channels = cs->channels();
42
43 int channelIndex = index.row();
44
45 if (index.row() < cs->channelCount()) {
46
47 switch (role) {
48 case Qt::DisplayRole: {
49 if (index.column() == 2) {
50 return channels.at(channelIndex)->name();
51 }
52 return QVariant();
53 }
54 case Qt::DecorationRole: {
55 if (index.column() == 1 &&
56 !m_thumbnails.isEmpty() &&
57 index.row() < m_thumbnails.size()) {
58
59 return QVariant(m_thumbnails.at(index.row()));
60 }
61 return QVariant();
62 }
63 case Qt::CheckStateRole: {
64 Q_ASSERT(index.row() < rowCount());
65 Q_ASSERT(index.column() < columnCount());
66
67 if (index.column() == 0) {
68 QBitArray flags = rootLayer->channelFlags();
69 return (flags.isEmpty() || flags.testBit(channelIndex)) ? Qt::Checked : Qt::Unchecked;
70 }
71 return QVariant();
72 }
73 }
74 }
75 }
76 return QVariant();
77}
78
79QVariant ChannelModel::headerData(int section, Qt::Orientation orientation, int role) const
80{
81 Q_UNUSED(section); Q_UNUSED(orientation); Q_UNUSED(role);
82 return QVariant();
83}
84
85int ChannelModel::rowCount(const QModelIndex& /*parent*/) const
86{
87 if (!m_canvas || !m_canvas->image()) return 0;
88
89 return m_channelCount;
90}
91
92int ChannelModel::columnCount(const QModelIndex& /*parent*/) const
93{
94 if (!m_canvas) return 0;
95
96 //columns are: checkbox, thumbnail, channel name
97 return 3;
98}
99
100bool ChannelModel::setData(const QModelIndex& index, const QVariant& value, int role)
101{
102 if (m_canvas && m_canvas->image()) {
103 KisGroupLayerSP rootLayer = m_canvas->image()->rootLayer();
104 const KoColorSpace *cs = rootLayer->colorSpace();
105 if (cs->channelCount() != m_channelCount) return false;
106
107 const QList<KoChannelInfo*> channels = cs->channels();
108 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(index.row() <= channels.count(), false);
109
110 int channelIndex = index.row();
111
112 if (role == Qt::CheckStateRole) {
113 QBitArray flags = rootLayer->channelFlags();
114 flags = flags.isEmpty() ? cs->channelFlags(true, true) : flags;
115 Q_ASSERT(!flags.isEmpty());
116
117 flags.setBit(channelIndex, value.toInt() == Qt::Checked);
118 rootLayer->setChannelFlags(flags);
119
120 Q_EMIT channelFlagsChanged();
121 emitAllDataChanged(channels.count() - 1, 0);
122 return true;
123 }
124 }
125 return false;
126}
127
128//User double clicked on a row (but on channel checkbox)
129//we select this channel, and deselect all other channels (except alpha, which we don't touch)
130//this makes it fast to select single color channel
131void ChannelModel::rowActivated(const QModelIndex &index)
132{
133 if (m_canvas && m_canvas->image()) {
134 KisGroupLayerWSP rootLayer = m_canvas->image()->rootLayer();
135 const KoColorSpace* cs = rootLayer->colorSpace();
136 if (cs->channelCount() != m_channelCount) return;
137
138 const QList<KoChannelInfo*> channels = cs->channels();
139 Q_ASSERT(index.row() <= channels.count());
140
141 int channelIndex = index.row();
142
143 QBitArray flags = rootLayer->channelFlags();
144 flags = flags.isEmpty() ? cs->channelFlags(true, true) : flags;
145 Q_ASSERT(!flags.isEmpty());
146
147 for (int i = 0; i < channels.count(); ++i) {
148 if (channels[i]->channelType() != KoChannelInfo::ALPHA) {
149 flags.setBit(i, (i == channelIndex));
150 }
151 }
152
153 rootLayer->setChannelFlags(flags);
154
155 Q_EMIT channelFlagsChanged();
156 emitAllDataChanged(channels.count() - 1, 0);
157 }
158}
159
160Qt::ItemFlags ChannelModel::flags(const QModelIndex& /*index*/) const
161{
162 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
163 return flags;
164}
165
167{
169
170 m_canvas = canvas;
171
172 if (m_canvas) {
174 SIGNAL(sigColorSpaceChanged(const KoColorSpace*)),
175 this,
176 SLOT(slotColorSpaceChanged(const KoColorSpace*)));
177 }
178}
179
181{
182 if (m_canvas) {
183 KisGroupLayerWSP rootLayer = m_canvas->image()->rootLayer();
184
185 if (!cs || *rootLayer->colorSpace() == *cs) {
186 const int newChannelCount = cs ? cs->channelCount() : 0;
187
188
189 if (newChannelCount != m_channelCount) {
190 beginResetModel();
191 m_thumbnails = channels;
192 m_channelCount = newChannelCount;
193 endResetModel();
194 } else {
195 m_thumbnails = channels;
196 emitAllDataChanged(channels.count() - 1, columnCount() - 1);
197 }
198 }
199 }
200}
201
203{
204 setChannelThumbnails({}, colorSpace);
205}
206
208{
210}
211
213{
215}
216
217void ChannelModel::emitAllDataChanged(int bottomRow, int rightColumn)
218{
219 if (bottomRow >= 0 && rightColumn >= 0) {
220 int rows = rowCount();
221 int cols = columnCount();
222 if (rows > 0 && cols > 0) {
223 Q_EMIT dataChanged(this->index(0, 0), this->index(qMin(bottomRow, rows - 1), qMin(rightColumn, cols - 1)));
224 }
225 }
226}
227
228#include "moc_channelmodel.cpp"
float value(const T *src, size_t ch)
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void setCanvas(KisCanvas2 *canvas)
void rowActivated(const QModelIndex &index)
void slotColorSpaceChanged(const KoColorSpace *colorSpace)
QPointer< KisCanvas2 > m_canvas
QVector< QImage > m_thumbnails
void channelFlagsChanged()
void setChannelThumbnails(const QVector< QImage > &channels, const KoColorSpace *cs)
QSize m_thumbnailSizeLimit
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
~ChannelModel() override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void setThumbnailSizeLimit(QSize size)
ChannelModel(QObject *parent=0)
KisSignalAutoConnectionsStore m_canvasConnections
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
QSize thumbnailSizeLimit() const
void emitAllDataChanged(int bottomRow, int rightColumn)
void addConnection(Sender sender, Signal signal, Receiver receiver, Method method, Qt::ConnectionType type=Qt::AutoConnection)
@ ALPHA
The channel represents the opacity of a pixel.
QBitArray channelFlags(bool color=true, bool alpha=false) const
QList< KoChannelInfo * > channels
virtual quint32 channelCount() const =0
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
const KoColorSpace * colorSpace() const override
QBitArray channelFlags
Definition kis_layer.cc:167
virtual void setChannelFlags(const QBitArray &channelFlags)
Definition kis_layer.cc:342