@@ -929,8 +929,11 @@ CGContextRef juce_getImageContext (const Image& image) | |||||
#endif | #endif | ||||
#if JUCE_MAC | #if JUCE_MAC | ||||
NSImage* imageToNSImage (const Image& image, float scaleFactor) | |||||
NSImage* imageToNSImage (const ScaledImage& scaled) | |||||
{ | { | ||||
const auto image = scaled.getImage(); | |||||
const auto scaleFactor = scaled.getScale(); | |||||
JUCE_AUTORELEASEPOOL | JUCE_AUTORELEASEPOOL | ||||
{ | { | ||||
NSImage* im = [[NSImage alloc] init]; | NSImage* im = [[NSImage alloc] init]; | ||||
@@ -102,7 +102,7 @@ CGContextRef juce_getImageContext (const Image&); | |||||
#endif | #endif | ||||
#if JUCE_MAC | #if JUCE_MAC | ||||
NSImage* imageToNSImage (const Image& image, float scaleFactor = 1.0f); | |||||
NSImage* imageToNSImage (const ScaledImage& image); | |||||
#endif | #endif | ||||
} // namespace juce | } // namespace juce |
@@ -127,15 +127,8 @@ namespace juce | |||||
struct CustomMouseCursorInfo | struct CustomMouseCursorInfo | ||||
{ | { | ||||
CustomMouseCursorInfo() = default; | |||||
CustomMouseCursorInfo (const Image& im, Point<int> hs, float scale = 1.0f) noexcept | |||||
: image (im), hotspot (hs), scaleFactor (scale) | |||||
{} | |||||
Image image; | |||||
ScaledImage image; | |||||
Point<int> hotspot; | Point<int> hotspot; | ||||
float scaleFactor = 1.0f; | |||||
}; | }; | ||||
} // namespace juce | } // namespace juce | ||||
@@ -36,14 +36,14 @@ public: | |||||
{ | { | ||||
} | } | ||||
SharedCursorHandle (const Image& image, Point<int> hotSpot, float scaleFactor) | |||||
: info { image, hotSpot, scaleFactor }, | |||||
SharedCursorHandle (const ScaledImage& image, Point<int> hotSpot) | |||||
: info { image, hotSpot }, | |||||
handle (info), | handle (info), | ||||
standardType (MouseCursor::NormalCursor), | standardType (MouseCursor::NormalCursor), | ||||
standard (false) | standard (false) | ||||
{ | { | ||||
// your hotspot needs to be within the bounds of the image! | // your hotspot needs to be within the bounds of the image! | ||||
jassert (image.getBounds().contains (hotSpot)); | |||||
jassert (image.getImage().getBounds().contains (hotSpot)); | |||||
} | } | ||||
static std::shared_ptr<SharedCursorHandle> createStandard (const MouseCursor::StandardCursorType type) | static std::shared_ptr<SharedCursorHandle> createStandard (const MouseCursor::StandardCursorType type) | ||||
@@ -92,12 +92,17 @@ MouseCursor::MouseCursor (const StandardCursorType type) | |||||
} | } | ||||
MouseCursor::MouseCursor (const Image& image, int hotSpotX, int hotSpotY) | MouseCursor::MouseCursor (const Image& image, int hotSpotX, int hotSpotY) | ||||
: MouseCursor (image, hotSpotX, hotSpotY, 1.0f) | |||||
: MouseCursor (ScaledImage (image), { hotSpotX, hotSpotY }) | |||||
{ | { | ||||
} | } | ||||
MouseCursor::MouseCursor (const Image& image, int hotSpotX, int hotSpotY, float scaleFactor) | MouseCursor::MouseCursor (const Image& image, int hotSpotX, int hotSpotY, float scaleFactor) | ||||
: cursorHandle (std::make_shared<SharedCursorHandle> (image, Point<int> { hotSpotX, hotSpotY }, scaleFactor)) | |||||
: MouseCursor (ScaledImage (image, scaleFactor), { hotSpotX, hotSpotY }) | |||||
{ | |||||
} | |||||
MouseCursor::MouseCursor (const ScaledImage& image, Point<int> hotSpot) | |||||
: cursorHandle (std::make_shared<SharedCursorHandle> (image, hotSpot)) | |||||
{ | { | ||||
} | } | ||||
@@ -103,6 +103,16 @@ public: | |||||
*/ | */ | ||||
MouseCursor (const Image& image, int hotSpotX, int hotSpotY, float scaleFactor); | MouseCursor (const Image& image, int hotSpotX, int hotSpotY, float scaleFactor); | ||||
/** Creates a custom cursor from an image. | |||||
@param image the image to use for the cursor - if this is bigger than the | |||||
system can manage, it might get scaled down first, and might | |||||
also have to be turned to black-and-white if it can't do colour | |||||
cursors. | |||||
@param hotSpot the position of the cursor's hotspot within the image | |||||
*/ | |||||
MouseCursor (const ScaledImage& image, Point<int> hotSpot); | |||||
//============================================================================== | //============================================================================== | ||||
/** Creates a copy of another cursor object. */ | /** Creates a copy of another cursor object. */ | ||||
MouseCursor (const MouseCursor&); | MouseCursor (const MouseCursor&); | ||||
@@ -674,7 +674,9 @@ public: | |||||
private: | private: | ||||
static Cursor makeHandle (const CustomMouseCursorInfo& info) | static Cursor makeHandle (const CustomMouseCursorInfo& info) | ||||
{ | { | ||||
return XWindowSystem::getInstance()->createCustomMouseCursorInfo (info.image, info.hotspot); | |||||
const auto image = info.image.getImage(); | |||||
return XWindowSystem::getInstance()->createCustomMouseCursorInfo (image.rescaled ((int) (image.getWidth() / info.image.getScale()), | |||||
(int) (image.getHeight() / info.image.getScale())), info.hotspot); | |||||
} | } | ||||
static Cursor makeHandle (MouseCursor::StandardCursorType type) | static Cursor makeHandle (MouseCursor::StandardCursorType type) | ||||
@@ -111,7 +111,7 @@ private: | |||||
} | } | ||||
static NSCursor* createCursor (const CustomMouseCursorInfo& info) | static NSCursor* createCursor (const CustomMouseCursorInfo& info) | ||||
{ | { | ||||
return fromNSImage (imageToNSImage (info.image, info.scaleFactor), | |||||
return fromNSImage (imageToNSImage (info.image), | |||||
NSMakePoint (info.hotspot.x, info.hotspot.y)); | NSMakePoint (info.hotspot.x, info.hotspot.y)); | ||||
} | } | ||||
@@ -125,7 +125,7 @@ private: | |||||
{ | { | ||||
case NormalCursor: | case NormalCursor: | ||||
case ParentCursor: c = [NSCursor arrowCursor]; break; | case ParentCursor: c = [NSCursor arrowCursor]; break; | ||||
case NoCursor: return createCursor ({ Image (Image::ARGB, 8, 8, true), {} }); | |||||
case NoCursor: return createCursor ({ ScaledImage (Image (Image::ARGB, 8, 8, true)), {} }); | |||||
case DraggingHandCursor: c = [NSCursor openHandCursor]; break; | case DraggingHandCursor: c = [NSCursor openHandCursor]; break; | ||||
case WaitCursor: c = [NSCursor arrowCursor]; break; // avoid this on the mac, let the OS provide the beachball | case WaitCursor: c = [NSCursor arrowCursor]; break; // avoid this on the mac, let the OS provide the beachball | ||||
case IBeamCursor: c = [NSCursor IBeamCursor]; break; | case IBeamCursor: c = [NSCursor IBeamCursor]; break; | ||||
@@ -537,7 +537,7 @@ public: | |||||
if (! windowRepresentsFile) | if (! windowRepresentsFile) | ||||
[window setRepresentedFilename:juceStringToNS (" ")]; // can't just use an empty string for some reason... | [window setRepresentedFilename:juceStringToNS (" ")]; // can't just use an empty string for some reason... | ||||
[[window standardWindowButton:NSWindowDocumentIconButton] setImage:imageToNSImage (newIcon)]; | |||||
[[window standardWindowButton:NSWindowDocumentIconButton] setImage:imageToNSImage (ScaledImage (newIcon))]; | |||||
} | } | ||||
} | } | ||||
@@ -5197,14 +5197,15 @@ private: | |||||
if (iter != cursorsBySize.end()) | if (iter != cursorsBySize.end()) | ||||
return iter->second; | return iter->second; | ||||
const auto imgW = jmax (1, info.image.getWidth()); | |||||
const auto imgH = jmax (1, info.image.getHeight()); | |||||
const auto img = info.image.getImage(); | |||||
const auto imgW = jmax (1, img.getWidth()); | |||||
const auto imgH = jmax (1, img.getHeight()); | |||||
const auto scale = (float) size / (float) unityCursorSize; | const auto scale = (float) size / (float) unityCursorSize; | ||||
const auto scaleToUse = scale * jmin (1.0f, jmin ((float) unityCursorSize / (float) imgW, | const auto scaleToUse = scale * jmin (1.0f, jmin ((float) unityCursorSize / (float) imgW, | ||||
(float) unityCursorSize / (float) imgH)) / info.scaleFactor; | |||||
const auto rescaled = info.image.rescaled (roundToInt (scaleToUse * (float) imgW), | |||||
roundToInt (scaleToUse * (float) imgH)); | |||||
(float) unityCursorSize / (float) imgH)) / info.image.getScale(); | |||||
const auto rescaled = img.rescaled (roundToInt (scaleToUse * (float) imgW), | |||||
roundToInt (scaleToUse * (float) imgH)); | |||||
const auto hx = jlimit (0, rescaled.getWidth(), roundToInt (scaleToUse * (float) info.hotspot.x)); | const auto hx = jlimit (0, rescaled.getWidth(), roundToInt (scaleToUse * (float) info.hotspot.x)); | ||||
const auto hy = jlimit (0, rescaled.getHeight(), roundToInt (scaleToUse * (float) info.hotspot.y)); | const auto hy = jlimit (0, rescaled.getHeight(), roundToInt (scaleToUse * (float) info.hotspot.y)); | ||||
@@ -5301,7 +5302,7 @@ private: | |||||
16,0,0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,132,117,151,116,132,146,248,60,209,138, | 16,0,0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,132,117,151,116,132,146,248,60,209,138, | ||||
98,22,203,114,34,236,37,52,77,217,247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 }; | 98,22,203,114,34,236,37,52,77,217,247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 }; | ||||
return makeHandle ({ ImageFileFormat::loadFrom (dragHandData, sizeof (dragHandData)), { 8, 7 } }); | |||||
return makeHandle ({ ScaledImage (ImageFileFormat::loadFrom (dragHandData, sizeof (dragHandData))), { 8, 7 } }); | |||||
} | } | ||||
case CopyingCursor: | case CopyingCursor: | ||||
@@ -5312,7 +5313,7 @@ private: | |||||
12,108,212,87,235,174, 15,54,214,126,237,226,37,96,59,141,16,37,18,201,142,157,230,204,51,112,252,114,147,74,83, | 12,108,212,87,235,174, 15,54,214,126,237,226,37,96,59,141,16,37,18,201,142,157,230,204,51,112,252,114,147,74,83, | ||||
5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 }; | 5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 }; | ||||
return makeHandle ({ ImageFileFormat::loadFrom (copyCursorData, sizeof (copyCursorData)), { 1, 3 } }); | |||||
return makeHandle ({ ScaledImage (ImageFileFormat::loadFrom (copyCursorData, sizeof (copyCursorData))), { 1, 3 } }); | |||||
} | } | ||||
case NumStandardCursorTypes: JUCE_FALLTHROUGH | case NumStandardCursorTypes: JUCE_FALLTHROUGH | ||||
@@ -36,7 +36,7 @@ struct StatusItemContainer : public Timer | |||||
{ | { | ||||
//============================================================================== | //============================================================================== | ||||
StatusItemContainer (SystemTrayIconComponent& iconComp, const Image& im) | StatusItemContainer (SystemTrayIconComponent& iconComp, const Image& im) | ||||
: owner (iconComp), statusIcon (imageToNSImage (im)) | |||||
: owner (iconComp), statusIcon (imageToNSImage (ScaledImage (im))) | |||||
{ | { | ||||
} | } | ||||
@@ -51,7 +51,7 @@ struct StatusItemContainer : public Timer | |||||
void updateIcon (const Image& newImage) | void updateIcon (const Image& newImage) | ||||
{ | { | ||||
statusIcon.reset (imageToNSImage (newImage)); | |||||
statusIcon.reset (imageToNSImage (ScaledImage (newImage))); | |||||
setIconSize(); | setIconSize(); | ||||
configureIcon(); | configureIcon(); | ||||
} | } | ||||