Skip to content

Commit 52018c5

Browse files
committed
Fix Hdpi Icon Scaling
Menu icons (16x16) were difficult to repurpose for toolbars because they would resize to fit 20x20, this change composites them onto a 20x20 pixmap so this no longer happens, this seems to make the whole process more stable
1 parent 3e1efe7 commit 52018c5

File tree

3 files changed

+130
-28
lines changed

3 files changed

+130
-28
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Thumbs.db
1313

1414
# bundled thirdparty libraries
1515
/thirdparty/boost
16+
/thirdparty/libjpeg-turbo64
1617
/thirdparty/lzo
1718
/thirdparty/tiff-4.0.3
1819
/thirdparty/LibJPEG/jpeg-9

toonz/sources/include/toonzqt/gutil.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ QPixmap DVAPI recolorPixmap(
113113
QPixmap pixmap, QColor color = Preferences::instance()->getIconTheme()
114114
? Qt::black
115115
: Qt::white);
116+
QPixmap DVAPI compositePixmap(QPixmap pixmap, qreal opacity,
117+
int canvasWidth = 20, int canvasHeight = 20,
118+
int iconWidth = 16, int iconHeight = 16,
119+
int offset = 0);
116120
QIcon DVAPI createQIcon(const char *iconSVGName, bool useFullOpacity = false);
117121
QIcon DVAPI createQIconPNG(const char *iconPNGName);
118122
QIcon DVAPI createQIconOnOffPNG(const char *iconPNGName, bool withOver = true);

toonz/sources/toonzqt/gutil.cpp

Lines changed: 125 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -260,46 +260,143 @@ QPixmap recolorPixmap(QPixmap pixmap, QColor color) {
260260
.rgba();
261261
}
262262
}
263-
return pixmap = QPixmap::fromImage(img);
263+
pixmap = QPixmap::fromImage(img);
264+
return pixmap;
265+
}
266+
267+
//-----------------------------------------------------------------------------
268+
269+
QPixmap compositePixmap(QPixmap pixmap, qreal opacity, int canvasWidth,
270+
int canvasHeight, int iconWidth, int iconHeight,
271+
int offset) {
272+
/* Creates a composite pixmap from two pixmaps. The canvas controls the final
273+
* size, whereas pixmap is the image to be composited ontop. You can control
274+
* the position of pixmap by setting an offset (top-left), default is 0. */
275+
276+
static int devPixRatio = getDevPixRatio();
277+
278+
QPixmap canvas(canvasWidth, canvasHeight);
279+
canvas.fill(Qt::transparent); // set this to a color to debug
280+
QPixmap combined(canvasWidth, canvasHeight);
281+
combined.fill(Qt::transparent);
282+
if (!pixmap.isNull()) {
283+
QPainter painter;
284+
painter.begin(&combined);
285+
QRect canvasRect(0, 0, canvasWidth, canvasHeight);
286+
painter.drawPixmap(canvasRect, canvas);
287+
painter.setOpacity(opacity);
288+
QRect iconRect(offset, offset, iconWidth, iconHeight);
289+
painter.drawPixmap(iconRect, pixmap);
290+
painter.end();
291+
}
292+
293+
return combined;
264294
}
265295

266296
//-----------------------------------------------------------------------------
267297

268298
QIcon createQIcon(const char *iconSVGName, bool useFullOpacity) {
269-
QIcon normalIcon = QIcon::fromTheme(iconSVGName);
299+
static int devPixRatio = getDevPixRatio();
270300

271-
QSize iconSize(0, 0); // Get largest
272-
for (QList<QSize> sizes = normalIcon.availableSizes(); !sizes.isEmpty();
301+
// get icon size
302+
QIcon themeIcon = QIcon::fromTheme(iconSVGName);
303+
QSize iconSize(0, 0);
304+
for (QList<QSize> sizes = themeIcon.availableSizes(); !sizes.isEmpty();
273305
sizes.removeFirst())
274306
if (sizes.first().width() > iconSize.width()) iconSize = sizes.first();
275307

276-
const qreal offOpacity = 0.8;
277-
const qreal disabledOpacity = 0.15;
278-
QString overStr = QString(iconSVGName) + "_over";
279-
QString onStr = QString(iconSVGName) + "_on";
280-
QPixmap normalPm = recolorPixmap(normalIcon.pixmap(iconSize));
281-
QPixmap overPm = recolorPixmap(QIcon::fromTheme(overStr).pixmap(iconSize));
282-
QPixmap onPm = recolorPixmap(QIcon::fromTheme(onStr).pixmap(iconSize));
308+
QString overStr = QString(iconSVGName) + "_over";
309+
QString onStr = QString(iconSVGName) + "_on";
310+
QPixmap themeIconPixmap = recolorPixmap(themeIcon.pixmap(iconSize));
311+
QPixmap overPixmap =
312+
recolorPixmap(QIcon::fromTheme(overStr).pixmap(iconSize));
313+
QPixmap onPixmap = recolorPixmap(QIcon::fromTheme(onStr).pixmap(iconSize));
283314
QIcon icon;
284315

285-
// Off
286-
icon.addPixmap(useFullOpacity ? normalPm : setOpacity(normalPm, offOpacity),
287-
QIcon::Normal, QIcon::Off);
288-
icon.addPixmap(setOpacity(normalPm, disabledOpacity), QIcon::Disabled);
289-
290-
// Over
291-
icon.addPixmap(!overPm.isNull() ? overPm : normalPm, QIcon::Active);
316+
// build icon
317+
for (int devPixRatio = 1; devPixRatio <= 2; devPixRatio++) {
318+
int iconW = themeIconPixmap.width();
319+
int iconH = themeIconPixmap.height();
320+
int canvasW = iconW;
321+
int canvasH = iconH;
322+
int offset = 0;
323+
const qreal normalOpacity = useFullOpacity ? 1 : 0.8;
324+
const qreal disabledOpacity = 0.15;
325+
const qreal onOpacity = 1;
326+
327+
// off
328+
icon.addPixmap(compositePixmap(themeIconPixmap, normalOpacity, canvasW,
329+
canvasH, iconW, iconH),
330+
QIcon::Normal, QIcon::Off);
331+
icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, canvasW,
332+
canvasH, iconW, iconH),
333+
QIcon::Disabled);
334+
335+
// over
336+
icon.addPixmap(
337+
compositePixmap(!overPixmap.isNull() ? overPixmap : themeIconPixmap,
338+
onOpacity, canvasW, canvasH, iconW, iconH),
339+
QIcon::Active);
340+
341+
// on
342+
if (!onPixmap.isNull()) {
343+
icon.addPixmap(
344+
compositePixmap(onPixmap, onOpacity, canvasW, canvasH, iconW, iconH),
345+
QIcon::Normal, QIcon::On);
346+
icon.addPixmap(compositePixmap(onPixmap, normalOpacity, canvasW, canvasH,
347+
iconW, iconH),
348+
QIcon::Disabled, QIcon::On);
349+
} else {
350+
icon.addPixmap(compositePixmap(themeIconPixmap, onOpacity, canvasW,
351+
canvasH, iconW, iconH),
352+
QIcon::Normal, QIcon::On);
353+
icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, canvasW,
354+
canvasH, iconW, iconH),
355+
QIcon::Disabled, QIcon::On);
356+
}
292357

293-
// On
294-
if (!onPm.isNull()) {
295-
icon.addPixmap(onPm, QIcon::Normal, QIcon::On);
296-
icon.addPixmap(setOpacity(onPm, disabledOpacity), QIcon::Disabled,
297-
QIcon::On);
298-
} else {
299-
// If file doesn't exist, let's add an opaque normal pixmap
300-
icon.addPixmap(normalPm, QIcon::Normal, QIcon::On);
301-
icon.addPixmap(setOpacity(normalPm, disabledOpacity), QIcon::Disabled,
302-
QIcon::On);
358+
/* If size is 16x16 (suitable for menu) we composite it onto a separate
359+
* 20x20 pixmap so that it is compatible with toolbars, otherwise it will be
360+
* scaled up and blur. You need to add icons to all QIcon modes otherwise it
361+
* will use the original size, which is undesirable. This is equal to having
362+
* two sets loaded into the icon (16x16 and 20x20) and is dynamically used
363+
* depending on iconSize for toolbars.
364+
*/
365+
if (iconSize == (QSize(16, 16))) {
366+
canvasW = 20 * devPixRatio;
367+
canvasH = 20 * devPixRatio;
368+
offset = 2 * devPixRatio;
369+
370+
// off
371+
icon.addPixmap(compositePixmap(themeIconPixmap, normalOpacity, canvasW,
372+
canvasH, iconW, iconH, offset),
373+
QIcon::Normal, QIcon::Off);
374+
icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, canvasW,
375+
canvasH, iconW, iconH, offset),
376+
QIcon::Disabled);
377+
// over
378+
icon.addPixmap(
379+
compositePixmap(!overPixmap.isNull() ? overPixmap : themeIconPixmap,
380+
onOpacity, canvasW, canvasH, iconW, iconH, offset),
381+
QIcon::Active);
382+
383+
// on
384+
if (!onPixmap.isNull()) {
385+
icon.addPixmap(compositePixmap(onPixmap, onOpacity, canvasW, canvasH,
386+
iconW, iconH, offset),
387+
QIcon::Normal, QIcon::On);
388+
icon.addPixmap(compositePixmap(onPixmap, disabledOpacity, canvasW,
389+
canvasH, iconW, iconH, offset),
390+
QIcon::Disabled, QIcon::On);
391+
} else {
392+
icon.addPixmap(compositePixmap(themeIconPixmap, onOpacity, canvasW,
393+
canvasH, iconW, iconH, offset),
394+
QIcon::Normal, QIcon::On);
395+
icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity,
396+
canvasW, canvasH, iconW, iconH, offset),
397+
QIcon::Disabled, QIcon::On);
398+
}
399+
}
303400
}
304401
return icon;
305402
}

0 commit comments

Comments
 (0)