icon.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is adapted from Qt Creator (replacing theme stuff by QColor)
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "icon.h"
27 
28 #include <QApplication>
29 #include <QIcon>
30 #include <QImage>
31 #include <QMetaEnum>
32 #include <QPainter>
33 #include <QPaintEngine>
34 #include <QWidget>
35 
36 namespace moveit_rviz_plugin {
37 namespace utils {
38 
39 static const qreal PUNCH_EDGE_WIDTH = 0.5;
40 static const qreal PUNCH_EDGE_INTENSITY = 0.6;
41 
42 static QPixmap maskToColorAndAlpha(const QPixmap& mask, const QColor& color) {
43  QImage result(mask.toImage().convertToFormat(QImage::Format_ARGB32));
44  result.setDevicePixelRatio(mask.devicePixelRatio());
45  QRgb* bits_start = reinterpret_cast<QRgb*>(result.bits());
46  const QRgb* bits_end = bits_start + result.width() * result.height();
47  const QRgb tint = color.rgb() & 0x00ffffff;
48  const QRgb alpha = QRgb(color.alpha());
49  for (QRgb* pixel = bits_start; pixel < bits_end; ++pixel) {
50  QRgb pixel_alpha = (((~*pixel) & 0xff) * alpha) >> 8;
51  *pixel = (pixel_alpha << 24) | tint;
52  }
53  return QPixmap::fromImage(result);
54 }
55 
56 using MaskAndColor = QPair<QPixmap, QColor>;
57 using MasksAndColors = QList<MaskAndColor>;
58 static MasksAndColors masksAndColors(const Icon& icon, int /*dpr*/) {
59  MasksAndColors result;
60  for (const IconMaskAndColor& i : icon) {
61  const QString& file_name = i.first;
62  const QColor color = i.second;
63  result.append(qMakePair(QPixmap(file_name), color));
64  }
65  return result;
66 }
67 
68 static void smearPixmap(QPainter* painter, const QPixmap& pixmap, qreal radius) {
69  const qreal nagative = -radius - 0.01; // Workaround for QPainter rounding behavior
70  const qreal positive = radius;
71  painter->drawPixmap(QPointF(nagative, nagative), pixmap);
72  painter->drawPixmap(QPointF(0, nagative), pixmap);
73  painter->drawPixmap(QPointF(positive, nagative), pixmap);
74  painter->drawPixmap(QPointF(positive, 0), pixmap);
75  painter->drawPixmap(QPointF(positive, positive), pixmap);
76  painter->drawPixmap(QPointF(0, positive), pixmap);
77  painter->drawPixmap(QPointF(nagative, positive), pixmap);
78  painter->drawPixmap(QPointF(nagative, 0), pixmap);
79 }
80 
81 static QPixmap combinedMask(const MasksAndColors& masks, Icon::IconStyleOptions style) {
82  if (masks.count() == 1)
83  return masks.first().first;
84 
85  QPixmap result(masks.first().first);
86  QPainter p(&result);
87  p.setCompositionMode(QPainter::CompositionMode_Darken);
88  auto mask_image = masks.constBegin();
89  mask_image++;
90  for (; mask_image != masks.constEnd(); ++mask_image) {
91  if (style & Icon::PUNCH_EDGES) {
92  p.save();
93  p.setOpacity(PUNCH_EDGE_INTENSITY);
94  p.setCompositionMode(QPainter::CompositionMode_Lighten);
95  smearPixmap(&p, maskToColorAndAlpha((*mask_image).first, Qt::white), PUNCH_EDGE_WIDTH);
96  p.restore();
97  }
98  p.drawPixmap(0, 0, (*mask_image).first);
99  }
100  p.end();
101  return result;
102 }
103 
104 static QPixmap masksToIcon(const MasksAndColors& masks, const QPixmap& combinedMask, Icon::IconStyleOptions style) {
105  QPixmap result(combinedMask.size());
106  result.setDevicePixelRatio(combinedMask.devicePixelRatio());
107  result.fill(Qt::transparent);
108  QPainter p(&result);
109 
110  for (MasksAndColors::const_iterator mask_image = masks.constBegin(); mask_image != masks.constEnd(); ++mask_image) {
111  if (style & Icon::PUNCH_EDGES && mask_image != masks.constBegin()) {
112  // Punch a transparent outline around an overlay.
113  p.save();
114  p.setOpacity(PUNCH_EDGE_INTENSITY);
115  p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
116  smearPixmap(&p, maskToColorAndAlpha((*mask_image).first, Qt::white), PUNCH_EDGE_WIDTH);
117  p.restore();
118  }
119  p.drawPixmap(0, 0, maskToColorAndAlpha((*mask_image).first, (*mask_image).second));
120  }
121 
122  if (style & Icon::DROP_SHADOW) {
123  const QPixmap shadow_mask = maskToColorAndAlpha(combinedMask, Qt::black);
124  p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
125  p.setOpacity(0.05);
126  p.drawPixmap(QPointF(0, -0.501), shadow_mask);
127  p.drawPixmap(QPointF(-0.501, 0), shadow_mask);
128  p.drawPixmap(QPointF(0.5, 0), shadow_mask);
129  p.drawPixmap(QPointF(0.5, 0.5), shadow_mask);
130  p.drawPixmap(QPointF(-0.501, 0.5), shadow_mask);
131  p.setOpacity(0.2);
132  p.drawPixmap(0, 1, shadow_mask);
133  }
134 
135  p.end();
136 
137  return result;
138 }
139 
140 static QPixmap combinedPlainPixmaps(const QVector<IconMaskAndColor>& images) {
141  QPixmap result(images.first().first);
142  auto pixmap = images.constBegin();
143  pixmap++;
144  for (; pixmap != images.constEnd(); ++pixmap) {
145  const QPixmap overlay((*pixmap).first);
146  result.paintEngine()->painter()->drawPixmap(0, 0, overlay);
147  }
148  return result;
149 }
150 
151 Icon::Icon() {}
152 
153 Icon::Icon(std::initializer_list<IconMaskAndColor> args, Icon::IconStyleOptions style)
154  : QVector<IconMaskAndColor>(args), m_style(style) {}
155 
156 Icon::Icon(const QString& imageFileName) : m_style(NONE) {
157  append({ imageFileName, QColor() });
158 }
159 
160 QIcon Icon::icon() const {
161  if (isEmpty()) {
162  return QIcon();
163  } else if (m_style == NONE) {
164  return QIcon(combinedPlainPixmaps(*this));
165  } else {
166  QIcon result;
167  const int max_dpr = qRound(qApp->devicePixelRatio());
168  for (int dpr = 1; dpr <= max_dpr; dpr++) {
169  const MasksAndColors masks = masksAndColors(*this, dpr);
170  const QPixmap combined_mask = combinedMask(masks, m_style);
171  result.addPixmap(masksToIcon(masks, combined_mask, m_style));
172 
173  const QColor disabled_color = QColor::fromRgba(0x60a4a6a8);
174  result.addPixmap(maskToColorAndAlpha(combined_mask, disabled_color), QIcon::Disabled);
175  }
176  return result;
177  }
178 }
179 
180 QPixmap Icon::pixmap() const {
181  if (isEmpty()) {
182  return QPixmap();
183  } else if (m_style == NONE) {
184  return combinedPlainPixmaps(*this);
185  } else {
186  const MasksAndColors masks = masksAndColors(*this, qRound(qApp->devicePixelRatio()));
187  const QPixmap combined_mask = combinedMask(masks, m_style);
188  return masksToIcon(masks, combined_mask, m_style);
189  }
190 }
191 
192 QString Icon::imageFileName() const {
193  return first().first;
194 }
195 
196 QIcon Icon::combinedIcon(const QList<QIcon>& icons) {
197  QIcon result;
198  QWindow* window = QApplication::allWidgets().first()->windowHandle();
199  for (const QIcon& icon : icons)
200  for (const QIcon::Mode mode : { QIcon::Disabled, QIcon::Normal })
201  for (const QSize& size : icon.availableSizes(mode))
202  result.addPixmap(icon.pixmap(window, size, mode), mode);
203  return result;
204 }
205 } // namespace utils
206 } // namespace moveit_rviz_plugin
moveit_rviz_plugin::utils::masksAndColors
static MasksAndColors masksAndColors(const Icon &icon, int)
Definition: icon.cpp:104
moveit_rviz_plugin::utils::IconMaskAndColor
QPair< QString, QColor > IconMaskAndColor
Definition: icon.h:39
moveit_rviz_plugin::utils::combinedMask
static QPixmap combinedMask(const MasksAndColors &masks, Icon::IconStyleOptions style)
Definition: icon.cpp:127
moveit_rviz_plugin::utils::maskToColorAndAlpha
static QPixmap maskToColorAndAlpha(const QPixmap &mask, const QColor &color)
Definition: icon.cpp:88
moveit_rviz_plugin::utils::masksToIcon
static QPixmap masksToIcon(const MasksAndColors &masks, const QPixmap &combinedMask, Icon::IconStyleOptions style)
Definition: icon.cpp:150
moveit_rviz_plugin::utils::PUNCH_EDGE_WIDTH
static const qreal PUNCH_EDGE_WIDTH
Definition: icon.cpp:85
moveit_rviz_plugin::utils::MaskAndColor
QPair< QPixmap, QColor > MaskAndColor
Definition: icon.cpp:102
moveit_rviz_plugin::utils::Icon::PUNCH_EDGES
@ PUNCH_EDGES
Definition: icon.h:51
isEmpty
bool isEmpty(const geometry_msgs::Pose &msg)
moveit_rviz_plugin::utils::PUNCH_EDGE_INTENSITY
static const qreal PUNCH_EDGE_INTENSITY
Definition: icon.cpp:86
NONE
NONE
icon.h
moveit_rviz_plugin::utils::Icon::Icon
Icon()
Definition: icon.cpp:197
moveit_rviz_plugin::utils::smearPixmap
static void smearPixmap(QPainter *painter, const QPixmap &pixmap, qreal radius)
Definition: icon.cpp:114
moveit_rviz_plugin::utils::combinedPlainPixmaps
static QPixmap combinedPlainPixmaps(const QVector< IconMaskAndColor > &images)
Definition: icon.cpp:186
moveit_rviz_plugin::utils::MasksAndColors
QList< MaskAndColor > MasksAndColors
Definition: icon.cpp:103
moveit_rviz_plugin
append
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
args
moveit_rviz_plugin::utils::Icon::DROP_SHADOW
@ DROP_SHADOW
Definition: icon.h:50


visualization
Author(s): Robert Haschke
autogenerated on Thu Feb 27 2025 03:39:51