Retina and mask

[quote=264401:@Greg O’Lone]In that case, you should go read:

http://blog.xojo.com/a-journey-of-a-thousand-pixels
http://blog.xojo.com/advanced-retina/hidpi-bitmapforcaching-and-scalefactorchanged

[/quote]
These links should be in the HiDPISupport.pdf. I only knew about and read the pdf (several times) and was still uncertain but those blog posts clarified much of what had confused me.

You’ve discovered a bug. Passing a picture from CopyMask or New Picture to ApplyMask crashes, but a picture from BitmapForCaching doesn’t. So you will have to build these pictures manually after all :stuck_out_tongue:

A bug I’d say, but the bug might be that ContainerControl even has ScaleFactor. I don’t see it mentioned in the pdf or language reference.

Hello,
Xojo 2016v1: while the function below works OK in a canvas, I’m not able to get the expected results when applying SystemIcons to PushButtons and SegmentedControls (macoxlib needed), because, with Support Retina enabled, the images do not get scaled.
Any help will be appreciated. Thanks.
BTW I tried both Will’s code and Greg’s code, but when I get the pictures scaled nicely in Retina mode, they are not scaled in non-Retina mode. Obviously I’m messing up something.

The pictures are called in this way:

  1. Canvas//always works OK
    Sub Paint(g As Graphics, areas() As REALbasic.Rect)
    dim p as Picture = SystemIcons.StopProgressFreestandingTemplate
    g.DrawPicture setHiDPI(g,p), 0,0
    #Pragma Unused areas
    End Sub

  2. PushButton//picture not scaled when Support Retina is enabled
    Sub Open()
    dim p as Picture = SystemIcons.StopProgressFreestandingTemplate
    p = setHiDPI(p.Graphics,p)
    me.Image = p
    End Sub

  3. SegmentedControl//picture not scaled when Support Retina is enabled
    Sub Open()
    dim p as Picture = SystemIcons.StopProgressFreestandingTemplate
    p = setHiDPI(p.Graphics,p)
    dim sg as SegmentedControlItem
    sg = me.Items(0)
    sg.Icon = p
    End Sub

The function is an adaptation of Greg’s code. Uncommenting “Dim pp” etc. things do not get better.

Function setHiDPI(g as Graphics, p as picture) As Picture
// Set the appropriate resolution
//Dim pp as New Picture(p.Width * g.ScaleX, p.Height * g.ScaleY)
//or
//Dim pp As Picture = g.BitmapForCaching(p.Width * g.ScaleX, p.Height * g.ScaleY)
'pp.Graphics.DrawPicture(p, 0, 0)
'p = pp

p.HorizontalResolution = 72 * g.ScaleX
p.VerticalResolution = 72 * g.ScaleY

// Set the scale factor so drawing to it will be correct
p.Graphics.ScaleX = g.ScaleX
p.Graphics.ScaleY = g.ScaleY

// Very important to remember the mask!
if p.mask <> nil then
p.Mask.Graphics.ScaleX = g.ScaleX
p.Mask.Graphics.ScaleY = g.ScaleY
end if

// Return the new picture
Return p

End Function

I just wonder what is the status of that issue. I have a specific project where I use a custom control made of a Canvas. I can’t manage to make it support Retina. Whatever I do, Graphics.Drawpicture() always uses the x1 picture and Graphics.DrawString() draws blurry text. I have tried everything on this thread… :-/ Will the Graphics.Drawpicture() and Graphics.DrawString() functions support Retina? Do they already but not fully? Thanks!..

A way that seems to work (but have not tried with picture yet) is to paint everything into a picture and then draw this into the graphics object. Taken from a Window.Paint event (for other controls, the first line should address Truewindow.BitmapForCaching instead of me):

Dim p As Picture = me.BitmapForCaching(me.Width, me.Height) p.Graphics.DrawOval 0,0,me.Width, me.Height Dim Ausgabe As Text = "TestText" Dim textlength as integer = p.Graphics.StringWidth (Ausgabe) p.Graphics.DrawString Ausgabe, me.Width/2 - textlength /2, me.Height / 2 g.DrawPicture p, 0,0, g.Width, g.Height, 0,0, p.Width, p.Height

Some declares can help, but they’re not that easy. There’s a ton of masking options in CoreGraphics, you can create CGPath and use that as a mask or take an image and use that as a mask when drawing to a canvas.

  • Paths need to be created from bottom up as the macOS insists that 0,0 is the bottom left hand corner (while Xojo uses 0,0 as the top left).
  • Images are harder as they need to be converted to grayscale and then drawn in using special functions.
  • Heck you can even stroke text to get a path and then use that as a mask. Iconographer uses this to draw gradients over the text. But Text is even harder as you have to use CoreText to do it.

I use masking a lot in our applications, but it nearly always takes a little while to get right due to the conflicts in vertical directions. And of course this doesn’t help with Windows at all.

For system icons, I wouldn’t recommend rasterizing them, instead I would (of course) recommend using something like the Retina Kit to draw them as this then asks the OS to draw the icons and the OS will use the correct resolution.

This may be the only way to do it with native Xojo code, I wouldn’t recommend it as you’re creating a picture, drawing it and then releasing it the paint event. If you want to use this method, I would suggest creating a picture on open and then recreating it on ScaleFactorChanged event, this will save you some time in the paint event. If you need to update it, update it outside of the paint event.

No they do so fully
We use the heck out of them in the IDE
BUT your graphics objects have to be set up right
A 1x graphics object will have its scaleX and scaleY set to 1
A 2x one has them set to 2 etc

So whatever they are derived from (a picture presumably) you have to make sure its a 1x or 2x (or 3x picture) so you get the right kind of graphics object (see picture HorizontalResolution and VerticalResolution)

And definitely read Greg’s posts about this

[quote=264401:@Greg O’Lone]http://blog.xojo.com/a-journey-of-a-thousand-pixels
http://blog.xojo.com/advanced-retina/hidpi-bitmapforcaching-and-scalefactorchanged [/quote]

100% agreement, Sam. It’s always better to buffer screen content in case it needs to be redrawn without changes in size. I should have added this, thanks!