I don’t know a lot about popup menus I’m afraid, other than the fact they’re notoriously difficult to stylise
Have you looked into the relevant code in the popup menus to see where the sub-menus are spawned, and how they might be styled differently to main menus?
Just wondering, how did you actually implement your own drop shadow using stack blur?
Since the gin stack blur is for images, I assume you’re baking the path into an image and then blurring it?
Love this idea. Stack Blur is very fast compared with the JUCE implementation but not free. I had a few other optimization ideas, but this one sounds nice. Instead of a free function, it would have to be a bit more like JUCE’s DropShadower, a member of a component, holding a path and a cached image…
Yeah I definitely recommend it! I did something very similar to you, but as you said, made it similar to juce::DropShadower. Basically just store a Path object and an associated rendered shadow Image and if the Path ever changes from the one stored, rerender it, etc. Though the stack blur is much faster than Juce’s you still don’t want to be rerendering every paint cycle
Try this out. Usage: blurImage<1>(image); use <2> for a stronger blur. This doesn’t have many options, and I know it won’t cover all the use cases discussed above, but it’s really fast and self-contained.
When set to true, the second template argument does a windows-like aero blur with enhanced contrast, which looks better if you want to overlay a semi-transparent colour on top of the blurred image.
Because both blur parameters are template arguments, the branches are elided, and the values are turned into compile-time constants.
// SPDX-License-Identifier: Zlib
// Copyright (c)2020 by George Yohng
#pragma once
#include "JuceHeader.h"
template<int blurShift, bool enhanceContrast=false>
inline void blurImage(Image &img) {
if (!img.isValid() || !img.getWidth() || !img.getHeight()) return;
img = img.convertedToFormat(Image::ARGB);
Image::BitmapData bm(img, 0, 0, img.getWidth(), img.getHeight(), Image::BitmapData::readWrite);
int h = img.getHeight();
int w = img.getWidth();
for (int y = 0; y < h; y++) {
for (int c = 0; c < 4; c++) {
uint8 *p = bm.getLinePointer(y) + c;
int s = p[0] << 16;
for (int x = 0; x < w; x++, p += 4) {
int px = int(p[0]) << 16;
s += (px - s) >> blurShift;
p[0] = s >> 16;
}
p -= 4;
for (int x = 0; x < w; x++, p -= 4) {
int px = int(p[0]) << 16;
s += (px - s) >> blurShift;
p[0] = s >> 16;
}
}
}
for (int x = 0; x < w; x++) {
for (int c = 0; c < 4; c++) {
uint8 *p = bm.getPixelPointer(x, 0) + c;
int incr = int(bm.getPixelPointer(x, 1) - bm.getPixelPointer(x, 0));
int s = p[0] << 16;
for (int y = 0; y < h; y++, p += incr) {
int px = int(p[0]) << 16;
s += (px - s) >> blurShift;
p[0] = s >> 16;
}
p -= incr;
for (int y = 0; y < h; y++, p -= incr) {
int px = int(p[0]) << 16;
s += (px - s) >> blurShift;
if (enhanceContrast) {
px = s >> 8;
px = ((((98304 - px) >> 7) * px >> 16) * px >> 16); // sine clamp
p[0] = jlimit(0, 255, px);
} else {
p[0] = s >> 16;
}
}
}
}
} // blurImage
I’ve updated the pull request with the above change in case anyone else finds it useful (full disclosure, I didn’t test it myself as I don’t have time).
At some point I need to tidy up the parts of that pull request which were borrowed from other places and rebase it from the develop branch to make merging easier. But, you know, time!
Thanks for this! This should be in JUCE. I’ve alone wasted enough hours trying to make the JUCE drop shadow match the design. Took me far less with this, counting the time to fix the translation. There are many solutions in this thread, but this was the simplest. At least for me.
Any idea why JUCE isn’t improving the drop shadows, even though all the work has already been done by the good devs on this thread?
I wonder if anyone on the current JUCE team is building UI/products with JUCE (as they were in the past). If not, they probably aren’t experiencing the same day to day friction that we do. IMO the lion’s share of work building anything real is the UI implemention. I’d love to see the JUCE team hire a UX/UI/design team member and dogfood some first class UI implementations so these things can receive the attention and priority they deserve.
This one cheats. It only does a single channel, so it works fine for simply shadows, but if you want to blur an ARGB image, it will not be able to do it. Ideally, it should detect the image type and then use the single channel of four channel algorithm.
I can confirm that this works for ARBG images and I am using alpha in those images. If you need the blur to spread even more, you can resample the image down, blur, then resample up again at high quality. You can balance the look and quality of the down/upsample with the performance gained by blurring fewer pixels, so combining these techniques has been really interesting for CPU-based blur and saved me from the complexity of implementing OpenGL (for now).