Changeset View
Changeset View
Standalone View
Standalone View
src/icon.cpp
Show First 20 Lines • Show All 132 Lines • ▼ Show 20 Line(s) | 132 | : QQuickItem(parent), | |||
---|---|---|---|---|---|
133 | m_smooth(false), | 133 | m_smooth(false), | ||
134 | m_changed(false), | 134 | m_changed(false), | ||
135 | m_active(false), | 135 | m_active(false), | ||
136 | m_selected(false), | 136 | m_selected(false), | ||
137 | m_isMask(false) | 137 | m_isMask(false) | ||
138 | { | 138 | { | ||
139 | setFlag(ItemHasContents, true); | 139 | setFlag(ItemHasContents, true); | ||
140 | //FIXME: not necessary anymore | 140 | //FIXME: not necessary anymore | ||
141 | connect(qApp, &QGuiApplication::paletteChanged, this, [this]() { | 141 | connect(qApp, &QGuiApplication::paletteChanged, this, &QQuickItem::polish); | ||
142 | m_changed = true; | 142 | connect(this, &QQuickItem::enabledChanged, this, &QQuickItem::polish); | ||
143 | update(); | | |||
144 | }); | | |||
145 | connect(this, &QQuickItem::enabledChanged, this, [this]() { | | |||
146 | m_changed = true; | | |||
147 | update(); | | |||
148 | }); | | |||
149 | } | 143 | } | ||
150 | 144 | | |||
151 | 145 | | |||
152 | Icon::~Icon() | 146 | Icon::~Icon() | ||
153 | { | 147 | { | ||
154 | } | 148 | } | ||
155 | 149 | | |||
156 | void Icon::setSource(const QVariant &icon) | 150 | void Icon::setSource(const QVariant &icon) | ||
157 | { | 151 | { | ||
158 | if (m_source == icon) { | 152 | if (m_source == icon) { | ||
159 | return; | 153 | return; | ||
160 | } | 154 | } | ||
161 | m_source = icon; | 155 | m_source = icon; | ||
162 | m_changed = true; | | |||
163 | m_monochromeHeuristics.clear(); | 156 | m_monochromeHeuristics.clear(); | ||
164 | 157 | | |||
165 | if (!m_theme) { | 158 | if (!m_theme) { | ||
166 | m_theme = static_cast<Kirigami::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::PlatformTheme>(this, true)); | 159 | m_theme = static_cast<Kirigami::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::PlatformTheme>(this, true)); | ||
167 | Q_ASSERT(m_theme); | 160 | Q_ASSERT(m_theme); | ||
168 | 161 | | |||
169 | connect(m_theme, &Kirigami::PlatformTheme::colorsChanged, this, [this]() { | 162 | connect(m_theme, &Kirigami::PlatformTheme::colorsChanged, this, &QQuickItem::polish); | ||
170 | m_changed = true; | | |||
171 | update(); | | |||
172 | }); | | |||
173 | } | 163 | } | ||
174 | 164 | | |||
175 | if (icon.type() == QVariant::String) { | 165 | if (icon.type() == QVariant::String) { | ||
176 | const QString iconSource = icon.toString(); | 166 | const QString iconSource = icon.toString(); | ||
177 | m_isMaskHeuristic = (iconSource.endsWith(QLatin1String("-symbolic")) | 167 | m_isMaskHeuristic = (iconSource.endsWith(QLatin1String("-symbolic")) | ||
178 | || iconSource.endsWith(QLatin1String("-symbolic-rtl")) | 168 | || iconSource.endsWith(QLatin1String("-symbolic-rtl")) | ||
179 | || iconSource.endsWith(QLatin1String("-symbolic-ltr"))); | 169 | || iconSource.endsWith(QLatin1String("-symbolic-ltr"))); | ||
180 | emit isMaskChanged(); | 170 | emit isMaskChanged(); | ||
181 | } | 171 | } | ||
182 | 172 | | |||
183 | if (m_networkReply) { | 173 | if (m_networkReply) { | ||
184 | //if there was a network query going on, interrupt it | 174 | //if there was a network query going on, interrupt it | ||
185 | m_networkReply->close(); | 175 | m_networkReply->close(); | ||
186 | } | 176 | } | ||
187 | m_loadedImage = QImage(); | 177 | m_loadedImage = QImage(); | ||
188 | update(); | 178 | | ||
179 | polish(); | ||||
189 | emit sourceChanged(); | 180 | emit sourceChanged(); | ||
190 | } | 181 | } | ||
191 | 182 | | |||
192 | QVariant Icon::source() const | 183 | QVariant Icon::source() const | ||
193 | { | 184 | { | ||
194 | return m_source; | 185 | return m_source; | ||
195 | } | 186 | } | ||
196 | 187 | | |||
197 | void Icon::setActive(const bool active) | 188 | void Icon::setActive(const bool active) | ||
198 | { | 189 | { | ||
199 | if (active == m_active) { | 190 | if (active == m_active) { | ||
200 | return; | 191 | return; | ||
201 | } | 192 | } | ||
202 | m_active = active; | 193 | m_active = active; | ||
203 | m_changed = true; | 194 | polish(); | ||
204 | update(); | | |||
205 | emit activeChanged(); | 195 | emit activeChanged(); | ||
206 | } | 196 | } | ||
207 | 197 | | |||
208 | bool Icon::active() const | 198 | bool Icon::active() const | ||
209 | { | 199 | { | ||
210 | return m_active; | 200 | return m_active; | ||
211 | } | 201 | } | ||
212 | 202 | | |||
213 | bool Icon::valid() const | 203 | bool Icon::valid() const | ||
214 | { | 204 | { | ||
215 | return !m_source.isNull(); | 205 | return !m_source.isNull(); | ||
216 | } | 206 | } | ||
217 | 207 | | |||
218 | void Icon::setSelected(const bool selected) | 208 | void Icon::setSelected(const bool selected) | ||
219 | { | 209 | { | ||
220 | if (selected == m_selected) { | 210 | if (selected == m_selected) { | ||
221 | return; | 211 | return; | ||
222 | } | 212 | } | ||
223 | m_selected = selected; | 213 | m_selected = selected; | ||
224 | m_changed = true; | 214 | polish(); | ||
225 | update(); | | |||
226 | emit selectedChanged(); | 215 | emit selectedChanged(); | ||
227 | } | 216 | } | ||
228 | 217 | | |||
229 | bool Icon::selected() const | 218 | bool Icon::selected() const | ||
230 | { | 219 | { | ||
231 | return m_selected; | 220 | return m_selected; | ||
232 | } | 221 | } | ||
233 | 222 | | |||
234 | void Icon::setIsMask(bool mask) | 223 | void Icon::setIsMask(bool mask) | ||
235 | { | 224 | { | ||
236 | if (m_isMask == mask) { | 225 | if (m_isMask == mask) { | ||
237 | return; | 226 | return; | ||
238 | } | 227 | } | ||
239 | 228 | | |||
240 | m_isMask = mask; | 229 | m_isMask = mask; | ||
241 | m_isMaskHeuristic = mask; | 230 | m_isMaskHeuristic = mask; | ||
242 | m_changed = true; | 231 | polish(); | ||
243 | update(); | | |||
244 | emit isMaskChanged(); | 232 | emit isMaskChanged(); | ||
245 | } | 233 | } | ||
246 | 234 | | |||
247 | bool Icon::isMask() const | 235 | bool Icon::isMask() const | ||
248 | { | 236 | { | ||
249 | return m_isMask || m_isMaskHeuristic; | 237 | return m_isMask || m_isMaskHeuristic; | ||
250 | } | 238 | } | ||
251 | 239 | | |||
252 | void Icon::setColor(const QColor &color) | 240 | void Icon::setColor(const QColor &color) | ||
253 | { | 241 | { | ||
254 | if (m_color == color) { | 242 | if (m_color == color) { | ||
255 | return; | 243 | return; | ||
256 | } | 244 | } | ||
257 | 245 | | |||
258 | m_color = color; | 246 | m_color = color; | ||
259 | m_changed = true; | 247 | polish(); | ||
260 | update(); | | |||
261 | emit colorChanged(); | 248 | emit colorChanged(); | ||
262 | } | 249 | } | ||
263 | 250 | | |||
264 | QColor Icon::color() const | 251 | QColor Icon::color() const | ||
265 | { | 252 | { | ||
266 | return m_color; | 253 | return m_color; | ||
267 | } | 254 | } | ||
268 | 255 | | |||
Show All 9 Lines | |||||
278 | } | 265 | } | ||
279 | 266 | | |||
280 | void Icon::setSmooth(const bool smooth) | 267 | void Icon::setSmooth(const bool smooth) | ||
281 | { | 268 | { | ||
282 | if (smooth == m_smooth) { | 269 | if (smooth == m_smooth) { | ||
283 | return; | 270 | return; | ||
284 | } | 271 | } | ||
285 | m_smooth = smooth; | 272 | m_smooth = smooth; | ||
286 | m_changed = true; | 273 | polish(); | ||
287 | update(); | | |||
288 | emit smoothChanged(); | 274 | emit smoothChanged(); | ||
289 | } | 275 | } | ||
290 | 276 | | |||
291 | bool Icon::smooth() const | 277 | bool Icon::smooth() const | ||
292 | { | 278 | { | ||
293 | return m_smooth; | 279 | return m_smooth; | ||
294 | } | 280 | } | ||
295 | 281 | | |||
296 | QSGNode* Icon::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/) | 282 | QSGNode* Icon::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/) | ||
297 | { | 283 | { | ||
298 | if (m_source.isNull()) { | 284 | if (m_source.isNull()) { | ||
299 | delete node; | 285 | delete node; | ||
300 | return Q_NULLPTR; | 286 | return Q_NULLPTR; | ||
301 | } | 287 | } | ||
302 | 288 | | |||
303 | if (m_changed || node == nullptr) { | 289 | if (m_changed || node == nullptr) { | ||
304 | QImage img; | | |||
305 | const QSize itemSize(width(), height()); | 290 | const QSize itemSize(width(), height()); | ||
306 | QRect nodeRect(QPoint(0,0), itemSize); | 291 | QRect nodeRect(QPoint(0,0), itemSize); | ||
307 | 292 | | |||
293 | ManagedTextureNode* mNode = dynamic_cast<ManagedTextureNode*>(node); | ||||
294 | if (!mNode) { | ||||
295 | delete node; | ||||
296 | mNode = new ManagedTextureNode; | ||||
297 | } | ||||
308 | if (itemSize.width() != 0 && itemSize.height() != 0) { | 298 | if (itemSize.width() != 0 && itemSize.height() != 0) { | ||
309 | const auto multiplier = QCoreApplication::instance()->testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1 : (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()); | 299 | const auto multiplier = QCoreApplication::instance()->testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1 : (window() ? window()->devicePixelRatio() : qGuiApp->devicePixelRatio()); | ||
310 | const QSize size = itemSize * multiplier; | 300 | const QSize size = itemSize * multiplier; | ||
311 | 301 | mNode->setTexture(s_iconImageCache->loadTexture(window(), m_icon)); | |||
312 | switch(m_source.type()){ | 302 | if (m_icon.size() != size) { | ||
313 | case QVariant::Pixmap: | | |||
314 | img = m_source.value<QPixmap>().toImage(); | | |||
315 | break; | | |||
316 | case QVariant::Image: | | |||
317 | img = m_source.value<QImage>(); | | |||
318 | break; | | |||
319 | case QVariant::Bitmap: | | |||
320 | img = m_source.value<QBitmap>().toImage(); | | |||
321 | break; | | |||
322 | case QVariant::Icon: | | |||
323 | img = m_source.value<QIcon>().pixmap(size, iconMode(), QIcon::On).toImage(); | | |||
324 | break; | | |||
325 | case QVariant::Url: | | |||
326 | case QVariant::String: | | |||
327 | img = findIcon(size); | | |||
328 | break; | | |||
329 | case QVariant::Brush: | | |||
330 | //todo: fill here too? | | |||
331 | case QVariant::Color: | | |||
332 | img = QImage(size, QImage::Format_Alpha8); | | |||
333 | img.fill(m_source.value<QColor>()); | | |||
334 | break; | | |||
335 | default: | | |||
336 | break; | | |||
337 | } | | |||
338 | | ||||
339 | if (img.isNull()){ | | |||
340 | img = QImage(size, QImage::Format_Alpha8); | | |||
341 | img.fill(Qt::transparent); | | |||
342 | } | | |||
343 | if (img.size() != size) { | | |||
344 | // At this point, the image will already be scaled, but we need to output it in | 303 | // At this point, the image will already be scaled, but we need to output it in | ||
345 | // the correct aspect ratio, painted centered in the viewport. So: | 304 | // the correct aspect ratio, painted centered in the viewport. So: | ||
346 | QRect destination(QPoint(0, 0), img.size().scaled(itemSize, Qt::KeepAspectRatio)); | 305 | QRect destination(QPoint(0, 0), m_icon.size().scaled(itemSize, Qt::KeepAspectRatio)); | ||
347 | destination.moveCenter(nodeRect.center()); | 306 | destination.moveCenter(nodeRect.center()); | ||
348 | nodeRect = destination; | 307 | nodeRect = destination; | ||
349 | } | 308 | } | ||
350 | | ||||
351 | const QColor tintColor = !m_color.isValid() || m_color == Qt::transparent ? (m_selected ? m_theme->highlightedTextColor() : m_theme->textColor()) : m_color; | | |||
352 | | ||||
353 | //TODO: initialize m_isMask with icon.isMask() | | |||
354 | if (tintColor.alpha() > 0 && (isMask() || guessMonochrome(img))) { | | |||
355 | QPainter p(&img); | | |||
356 | p.setCompositionMode(QPainter::CompositionMode_SourceIn); | | |||
357 | p.fillRect(img.rect(), tintColor); | | |||
358 | p.end(); | | |||
359 | } | 309 | } | ||
360 | } | | |||
361 | m_changed = false; | | |||
362 | | ||||
363 | ManagedTextureNode* mNode = dynamic_cast<ManagedTextureNode*>(node); | | |||
364 | if (!mNode) { | | |||
365 | delete node; | | |||
366 | mNode = new ManagedTextureNode; | | |||
367 | } | | |||
368 | mNode->setTexture(s_iconImageCache->loadTexture(window(), img)); | | |||
369 | mNode->setRect(nodeRect); | 310 | mNode->setRect(nodeRect); | ||
370 | node = mNode; | 311 | node = mNode; | ||
371 | if (m_smooth) { | 312 | if (m_smooth) { | ||
372 | mNode->setFiltering(QSGTexture::Linear); | 313 | mNode->setFiltering(QSGTexture::Linear); | ||
373 | } | 314 | } | ||
315 | m_changed = false; | ||||
374 | } | 316 | } | ||
375 | 317 | | |||
376 | return node; | 318 | return node; | ||
377 | } | 319 | } | ||
378 | 320 | | |||
379 | void Icon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) | 321 | void Icon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) | ||
380 | { | 322 | { | ||
323 | QQuickItem::geometryChanged(newGeometry, oldGeometry); | ||||
381 | if (newGeometry.size() != oldGeometry.size()) { | 324 | if (newGeometry.size() != oldGeometry.size()) { | ||
382 | m_changed = true; | 325 | polish(); | ||
383 | update(); | | |||
384 | } | 326 | } | ||
385 | QQuickItem::geometryChanged(newGeometry, oldGeometry); | | |||
386 | } | 327 | } | ||
387 | 328 | | |||
388 | void Icon::handleRedirect(QNetworkReply* reply) | 329 | void Icon::handleRedirect(QNetworkReply* reply) | ||
389 | { | 330 | { | ||
390 | QNetworkAccessManager* qnam = reply->manager(); | 331 | QNetworkAccessManager* qnam = reply->manager(); | ||
391 | if (reply->error() != QNetworkReply::NoError) { | 332 | if (reply->error() != QNetworkReply::NoError) { | ||
392 | return; | 333 | return; | ||
393 | } | 334 | } | ||
Show All 26 Lines | 352 | { | |||
420 | const QString filename = reply->url().fileName(); | 361 | const QString filename = reply->url().fileName(); | ||
421 | if (!m_loadedImage.load(reply, filename.mid(filename.indexOf(QLatin1Char('.'))).toLatin1().constData())) { | 362 | if (!m_loadedImage.load(reply, filename.mid(filename.indexOf(QLatin1Char('.'))).toLatin1().constData())) { | ||
422 | qWarning() << "received broken image" << reply->url(); | 363 | qWarning() << "received broken image" << reply->url(); | ||
423 | 364 | | |||
424 | // broken image from data, inform the user of this with some useful broken-image thing... | 365 | // broken image from data, inform the user of this with some useful broken-image thing... | ||
425 | const QSize size = QSize(width(), height()) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()); | 366 | const QSize size = QSize(width(), height()) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()); | ||
426 | m_loadedImage = QIcon::fromTheme(m_fallback).pixmap(size, iconMode(), QIcon::On).toImage(); | 367 | m_loadedImage = QIcon::fromTheme(m_fallback).pixmap(size, iconMode(), QIcon::On).toImage(); | ||
427 | } | 368 | } | ||
369 | polish(); | ||||
370 | } | ||||
371 | | ||||
372 | void Icon::updatePolish() | ||||
373 | { | ||||
374 | QQuickItem::updatePolish(); | ||||
375 | | ||||
376 | const QSize itemSize(width(), height()); | ||||
377 | if (itemSize.width() != 0 && itemSize.height() != 0) { | ||||
378 | const auto multiplier = QCoreApplication::instance()->testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1 : (window() ? window()->devicePixelRatio() : qGuiApp->devicePixelRatio()); | ||||
379 | const QSize size = itemSize * multiplier; | ||||
380 | | ||||
381 | switch(m_source.type()){ | ||||
382 | case QVariant::Pixmap: | ||||
383 | m_icon = m_source.value<QPixmap>().toImage(); | ||||
384 | break; | ||||
385 | case QVariant::Image: | ||||
386 | m_icon = m_source.value<QImage>(); | ||||
387 | break; | ||||
388 | case QVariant::Bitmap: | ||||
389 | m_icon = m_source.value<QBitmap>().toImage(); | ||||
390 | break; | ||||
391 | case QVariant::Icon: | ||||
392 | m_icon = m_source.value<QIcon>().pixmap(size, iconMode(), QIcon::On).toImage(); | ||||
393 | break; | ||||
394 | case QVariant::Url: | ||||
395 | case QVariant::String: | ||||
396 | m_icon = findIcon(size); | ||||
397 | break; | ||||
398 | case QVariant::Brush: | ||||
399 | //todo: fill here too? | ||||
400 | case QVariant::Color: | ||||
401 | m_icon = QImage(size, QImage::Format_Alpha8); | ||||
402 | m_icon.fill(m_source.value<QColor>()); | ||||
403 | break; | ||||
404 | default: | ||||
405 | break; | ||||
406 | } | ||||
407 | | ||||
408 | if (m_icon.isNull()){ | ||||
409 | m_icon = QImage(size, QImage::Format_Alpha8); | ||||
410 | m_icon.fill(Qt::transparent); | ||||
411 | } | ||||
412 | | ||||
413 | const QColor tintColor = !m_color.isValid() || m_color == Qt::transparent ? (m_selected ? m_theme->highlightedTextColor() : m_theme->textColor()) : m_color; | ||||
414 | | ||||
415 | //TODO: initialize m_isMask with icon.isMask() | ||||
416 | if (tintColor.alpha() > 0 && (isMask() || guessMonochrome(m_icon))) { | ||||
417 | QPainter p(&m_icon); | ||||
418 | p.setCompositionMode(QPainter::CompositionMode_SourceIn); | ||||
419 | p.fillRect(m_icon.rect(), tintColor); | ||||
420 | p.end(); | ||||
421 | } | ||||
422 | } | ||||
428 | m_changed = true; | 423 | m_changed = true; | ||
429 | update(); | 424 | update(); | ||
430 | } | 425 | } | ||
431 | 426 | | |||
432 | QImage Icon::findIcon(const QSize &size) | 427 | QImage Icon::findIcon(const QSize &size) | ||
433 | { | 428 | { | ||
434 | QImage img; | 429 | QImage img; | ||
435 | QString iconSource = m_source.toString(); | 430 | QString iconSource = m_source.toString(); | ||
▲ Show 20 Lines • Show All 163 Lines • Show Last 20 Lines |