Using Declares to Set Font Size

Hey guys,

I have a situation where I’m using declares to change the size of a pop-up menu since adjusting height doesn’t work in OS X. The attached code snippet adjusts the size of the pop-up menu just fine. But what isn’t working is the code to adjust the size of the font in the control. And I can’t set the size using Xojo as then the size of the control gets reset. I think I got this code from Mitch or maybe it’s been distributed around…

I’d like to know why the font code does not appear to work. I’m not good with declares. Looking on the Apple Developer Pages, these declares seem to be correct. The only one that is questionable to me is the SystemFontOfSize as the Objective-C API looks like:

+ (NSFont *)systemFontOfSize:(CGFloat)fontSize 
                      weight:(CGFloat)weight;

And the declare below doesn’t include anything about the weight. Maybe it’s not needed? Not sure.

Or is the font size in a Pop-Up menu not adjustable? Would seem silly as you can adjust the control size - that works fine.

Thanks in advance…

  Declare Function NSClassFromString Lib "Cocoa" (className as CFStringRef) As Ptr
  declare sub setSize lib "Cocoa" selector "setControlSize:" _
  ( ObjectHandle as Integer, inSize as NSControlSize )
  Declare function getCell lib "Cocoa" selector "cell" ( handle as integer ) as Integer
  
  if c isa progressBar or c isa ProgressWheel then
    setSize( c.handle, inSize )
    
  else
// Set the size of the control.
    setSize( getCell( c.handle ), inSize )
    
    // - Now we also update the text font to match
// - This is the code that is not working...
    Dim fontSize as single
    
    select case inSize
    case NSControlSize.NSRegularControlSize
      declare function systemFontSize lib "Cocoa" selector "systemFontSize" _
      ( classRef as Ptr ) as single
      fontSize = systemFontSize( NSClassFromString( "NSFont" ) )
      
    else
      // + (CGFloat)smallSystemFontSize
      declare function smallSystemFontSize lib "Cocoa" selector "smallSystemFontSize" _
      ( classRef as Ptr ) as single
      fontSize = smallSystemFontSize( NSClassFromString( "NSFont" ) )
    end select
    
    // + (NSFont *)systemFontOfSize:(CGFloat)fontSize
    declare function systemFontOfSize lib "Cocoa" selector "systemFontOfSize:" _
    ( classRef as Ptr, inSize as single ) as Ptr
    Dim ref as Ptr = systemFontOfSize( NSClassFromString( "NSFont" ), fontSize )
    
    if ref <> nil then
      // - (void)setFont:(NSFont *)fontObject
      declare sub setFont lib "Cocoa" selector "setFont:" _
      ( NSControlHandle as integer, font as Ptr )
      setFont( c.handle, ref )
    end if
    
  end if

[quote=324624:@Jon Ogden] declare function systemFontSize lib “Cocoa” selector “systemFontSize” _
( classRef as Ptr ) as single[/quote]
If you’re targeting 64bit you’ll need to use CGFloats (becomes Double on 64bit)

[quote=324624:@Jon Ogden] setFont( c.handle, ref )
[/quote]
Should this be
setFont( getCell(c.handle) , ref )

Also, set a breakpoint and check that fontSize > 0 and ref <> nil

Thanks, Jim! Yes, It is 64 bit so good call. And I’ll change the setFont call too.

This was EXACTLY the problem. Changing this fixed everything.

This did not work. End up making the text microscopic.

@Tim Parnell can probably tell you who wrote the above code based up on the Graphology of it :wink:

OK guys, I need some further help with this…

I’d like to get the resulting size of the control in pixels (particularly the height). Xojo’s height property does not report the correct value once you set the height using the declares.

So looking at the OS X developer reference there’s a CellSize property of the cell that you grab in the code above. But in Xojo the GetCell function is returning an integer not the object. How can I get a property of that object such as the size?

Thanks!

The getCell method returns an integer to keep it aligned with Xojo’s handle which is an integer as well – so the result is in reality the ptr to the cell. You are mixing integers and Ptrs in your declares, and although they are basically the same, it makes handling a bit complicated.

Assuming the cell is indeed a TextCell you’d have to change the Font property of the cell which is an NSFont object. For setting the property it would be (untested):

Declare Sub setFont lib "Cocoa" selector "setFont:" (cell As integer, font as Integer)

You’d have to do something like

declare function systemFontOfSize lib "Cocoa" selector "systemFontOfSize:" _ ( classRef as Ptr, inSize as CGFloat ) as Integer

Dim MyFont As Integer = systemFontOfSize (NSClassFromString("NSFont"), yourFontSize [As Double]) Dim MyCell As integer = getCell(yourCell.handle) setFont (MyCell, MyFont)

Or change the relevant parts to pointer and pass Ptr(your cell.handle) to getCell.

If this doesn’t work or confuses you: Could you upload a project?

EDIT: for getting the Fontsize, the declare would be

[code]Declare Function font lib “Cocoa” selector “font” (id as Integer) As Integer
Declare Function fontsize lib “Cocoa” selector “pointSize” (id as Integer) As CGFloat

Dim MyFontSize As Double = fontsize(font(mycell))[/code]

Thanks Eric, but I must not have explained myself well enough. The declare code I provided works. I’m not sure about mixing integers and ptrs. in the code. I did not write the code - someone else did.

In my particular instance, I am using this code to set the size of a pop-up menu to one of the smaller sizes that OS X provides. My original question was in regard to adjusting the text size in the pop-up. That was fixed when I updated the code to use Double instead of Single precision real number values.

Now, my question is since I have adjusted the size of my control (in this case a pop-up menu), I want to get the size of that control in pixels. The CellSize property will likely have what I want but since the GetCell function returns just the pointer to the cell. So how can I get the CellSize property or whatever the actual height is of the control? Xojo does not report the correct height.

Thanks.

Oh I see! Sorry for getting you wrong!
You will not find these values in the cell, The cell is just a light-weight view class that resizes with the control embedding it. (You could, although it’s just a rough model and not perfectly true, compare the cell to the graphics object of a Canvas.)
Instead, the control’s size depends on the control itself. While the control class gives you just the ControlSize enumeration, NSControls inherit from NSView, and in NSView you find the Frame property which is of the structure type

Structure NSRect Origin as NSPoint Size_ as NSSize End Structure with

Structure NSPoint x as CGFloat y as CGFloat End Structure and

Structure NSSize width as CGFloat height as CGFloat End Structure

The declares are

Declare Function getFrame lib "Cocoa" selector "frame" (id as Integer) As NSRect

and

Declare Sub setFrame lib "Cocoa" selector "setFrame:" (id as integer, value as NSRect)

Just pass the handle of the control to them.

Ulrich aka Eric :wink:

[quote=326008:@Ulrich Bogun]Oh I see! Sorry for getting you wrong!
You will not find these values in the cell, The cell is just a light-weight view class that resizes with the control embedding it. (You could, although it’s just a rough model and not perfectly true, compare the cell to the graphics object of a Canvas.)
Instead, the control’s size depends on the control itself. While the control class gives you just the ControlSize enumeration, NSControls inherit from NSView, and in NSView you find the Frame property which is of the structure type

Structure NSRect Origin as NSPoint Size_ as NSSize End Structure with

Structure NSPoint x as CGFloat y as CGFloat End Structure and

Structure NSSize width as CGFloat height as CGFloat End Structure

The declares are

Declare Function getFrame lib "Cocoa" selector "frame" (id as Integer) As NSRect

and

Declare Sub setFrame lib "Cocoa" selector "setFrame:" (id as integer, value as NSRect)

Just pass the handle of the control to them.

Ulrich aka Eric ;)[/quote]

So if I understand this right, I set up a structure in Xojo. And I’d have to use Double instead of CGFloat.

Then to get the frame, I use the getFrame method. It will return the value of NSRect into my structure so I can then look inside the structure to get the sizes.

Do I have that right?

And if I am just grabbing the size, I don’t need to use the SetFrame declare - correct?

For the structure, you need to use CGFloat or it won’t work on 32 Bit. You can use CGFloat on the Xojo side as well – I only developed the habit of using Doubles in Xojo code, because CGFloat was deprecated the moment it was introduced in Xojo. Once all Apple systems are 64 Bit only, there is no need to for it anymore, because all those properties will be Doubles then.

And yes: If you only want to read the structure, you don’t need the set Declare. Just get it and read the value.size_.Height or whatever you like to inspect.

[quote=326024:@Ulrich Bogun]For the structure, you need to use CGFloat or it won’t work on 32 Bit. You can use CGFloat on the Xojo side as well – I only developed the habit of using Doubles in Xojo code, because CGFloat was deprecated the moment it was introduced in Xojo. Once all Apple systems are 64 Bit only, there is no need to for it anymore, because all those properties will be Doubles then.

And yes: If you only want to read the structure, you don’t need the set Declare. Just get it and read the value.size_.Height or whatever you like to inspect.[/quote]

I’ve got 64 bit structures already defined. Didn’t know we could use GCFloat.

Anyhow, so I have it “working” but I’m confused…

The standard height of a Xojo pop-up menu is 20 pixels.

Using the declares in my first post, I set the size of the pop-up menu to NSControlSize.NSMiniControlSize. So the height of the control is SMALLER than 20 points.

But when running the declare you gave me to get the size, it is returning 22 pixels! That is larger than Xojo’s default size…

So I don’t understand that at all…

  1. the size is likely in points not pixels and will depend on what screen you’re on and its backing store scale factor

  2. Apples artwork for the popup has only come in a limited set of sizes (it used to only be 2 but in later versions its harder to check as they are tossing more & more of it into CAR files) so really double check that it looks decent when you do this and you dont get ugly scaling effects

[quote=326026:@Norman Palardy]1) the size is likely in points not pixels and will depend on what screen you’re on and its backing store scale factor

  1. Apples artwork for the popup has only come in a limited set of sizes (it used to only be 2 but in later versions its harder to check as they are tossing more & more of it into CAR files) so really double check that it looks decent when you do this and you dont get ugly scaling effects[/quote]

OK. So the control does look fine.

What’s the method for converting points to pixels? I know, my Google isn’t broke. :slight_smile:

And this doesn’t make sense…

22 points equates to 29 pixels which is even worse…

Did you calculate typographic points into pixels? They are note the same – a point in macOS is usually 1 pixel or 2 pixels, depending on the screen and HiDPI settings.

I checked this with a custom control available in AppleLib (which are not that many currently): Just a textfield, but created as a native mac Control. It was set to a height of 27 in Xojo, and if I check its frame the height is 54 because I run this on a Retina screen where the Scalefactor is 2. Might I guess that the Height of 22 points you get is 11 in Xojo?

Well, it’s definitely larger than 11. This pop-up menu sits in a row of a listbox. The height of the rows is 17. And the pop-up menu fits just into the row - being just under the height of the row. What is interesting is that if I were to consider it as 22 pixels and convert it to points, I get 16. That seems about the right height. 11 seems way too small…

The frame property gives you the dimensions of a view in relation to its superview. Maybe you should replace getFrame by getBounds:

Declare Function getBounds lib "Cocoa" selector "bounds" (id as Integer) As NSRect

which gives you the dimensions in the control’s own space.
(Just wildly guessing at the moment, but who knows how embedding the popup into a listbox may change the frame …)

OK. I’ll try that…

[quote=326052:@Ulrich Bogun]The frame property gives you the dimensions of a view in relation to its superview. Maybe you should replace getFrame by getBounds:

Declare Function getBounds lib "Cocoa" selector "bounds" (id as Integer) As NSRect

which gives you the dimensions in the control’s own space.
(Just wildly guessing at the moment, but who knows how embedding the popup into a listbox may change the frame …)[/quote]

Gives the exact same answer - 22 in my case. :frowning:

Has to be an answer that makes sense…