NSSearchField

Here’s a function to create an NSGradient… I don’t think initWithColorsAndLocations can be used. It seems to be similar to how a paramArray works in Xojo, but I don’t see a way to bridge it aside from having declares for every possible number of colors you might use. This function takes an array of doubles and an array of colors and make an NSGradient from them. You can use it to fill a bezierPath with “drawInBezierPath:angle:” selector of NSGradient.

[code]Function MakeNSGradient(pts() as double,colors() as Color) As ptr
#if TargetCocoa
//pts are doubles in the range 0-1
//colors() must have the same number of items as pts()

declare function NSClassFromString lib "Cocoa" (className as cfStringRef) as ptr
declare function alloc lib "Cocoa" selector "alloc" (classRef as ptr) as ptr
declare function autorelease lib "Cocoa" selector "autorelease" (obj as ptr) as ptr
//NSArray stuff
Declare Function arrayWithCapacity lib "Cocoa" selector "arrayWithCapacity:" (class_ref as ptr,numItems as integer) as ptr
Declare Sub addObject lib "Cocoa" selector "addObject:" (obj_ref as ptr,anObject as Ptr)
//NSColorSpace stuff
Declare Function deviceRGBColorSpace lib "Cocoa" selector "deviceRGBColorSpace" (class_ref as ptr) as ptr
//NSColor stuff
declare Function colorWithSRGBRedgreenbluealpha lib "Cocoa" selector "colorWithSRGBRed:green:blue:alpha:"_
(cls as ptr,red as single,green as single,blue as single, alpha as single) as ptr
//NSGradientStuff
Declare Function initWithColorsatLocationscolorSpace lib "Cocoa" selector "initWithColors:atLocations:colorSpace:"_
(obj_ref as ptr,colorArray as ptr,locations as ptr,colorSpace as ptr) as Ptr

//colorstops memoryblock as singles
dim m As new MemoryBlock(4*(pts.Ubound+1))  
for i as integer=0 to pts.Ubound 
  m.SingleValue(i*4)=pts(i)
next

//we need an NSArray of NSColors
dim a As ptr=arrayWithCapacity(NSClassFromString("NSMutableArray"),colors.Ubound+1)
for i as integer=0 to colors.ubound
  addObject(a,colorWithSRGBRedgreenbluealpha(NSClassFromString("NSColor"),colors(i).red/255,colors(i).Green/255,colors(i).Blue/255,1.0))
next

//Using deviceRGBColorSpace assuming this is for display
dim deviceRGB As ptr=deviceRGBColorSpace(NSClassFromString("NSColorSpace"))


dim myNSGradient As ptr=initWithColorsatLocationscolorSpace(autorelease(alloc(NSClassFromString("NSGradient"))),a,m,deviceRGB)
Return myNSGradient

#endif
End Function
[/code]

Thanks, Jim. Yes, I forwarded the constructor from InitWithColorsAndLocations to initWithColorsatLocationscolorSpace too.
So my implementation is almost done (I started setting up NSBezierPath in MacOSLib in the meantime to try out the Bezier fill functions).

Only GetColorLocationatIndex is not working yet – it seems to be needed to pass the values as byrefs but I could‘t figure out yet how to return the values. That “pointer to a pointer to a value” thing (**) keeps my mind spinning in circles.

I don‘t want to overstress your generosity in sharing your knowledge, but is it even possible to implement it like here?

Thanks a lot again!
Uli

[code]Sub GetColor(byref getColor as NSColor, byref location as Single, atIndex as Integer)
// Returns information about the color stop at the specified index in the receiver’s color array.

// Note: This is not working yet!

#if TargetMacOS
Declare sub getColorlocationatIndex lib CocoaLib selector “getColor:location:atIndex:” (id as ptr, getColor as ptr, location as single, atIndex as Integer)

getColorlocationatIndex ( self, GetColor, location, atIndex )

#endif
End Sub[/code]

It should work if you use byref in the declare…

Declare sub getColorlocationatIndex lib CocoaLib selector "getColor:location:atIndex:" (id as ptr, getColor as ptr, location as single, atIndex as Integer)
should be

Declare sub getColorlocationatIndex lib CocoaLib selector "getColor:location:atIndex:" (id as ptr, byref getColor as ptr, location as single, atIndex as Integer)

Thanks Jim! I had missed that and tried it in between myself, but without luck. Compiler gives me a “Parameters are not compatible with this function” at the Sub‘s call, but just highlighting the sub‘s name, so I can only guess that getColor should be the problem as it is the only parameter I have to handle via a Ptr.

[code]Attributes( getColor = “is not working yet” ) Sub GetColor(byref getColor as NSColor, byreflocation as Single, atIndex as Integer)
// Returns information about the color stop at the specified index in the receiver’s color array.

// Note: This is not working yet!

#if TargetMacOS
Declare sub getColorlocationatIndex lib CocoaLib selector “getColor:location:atIndex:” (id as ptr, byref getColor as ptr, byref location as single, atIndex as Integer)

getColorlocationatIndex ( self, GetColor, location, atIndex )

#endif
End Sub[/code]

Anyway, NSBezierPath has grown a big step, but there are a few calls with similar problems. I‘m mighty impressed how easy (the steps I understood so far) have been. And how much of what I always thought the graphics apps would do is implemented in the OS. Wish someone would grab that code and build a new Freehand around it :wink:

Found it – this is how it works:

[code]Sub GetColor(byref getColor as NSColor, byref location as Single, atIndex as Integer)
// Returns information about the color stop at the specified index in the receiver’s color array.

#if TargetMacOS
dim colorptr as ptr = getcolor
Declare sub getColorlocationatIndex lib CocoaLib selector “getColor:location:atIndex:” (id as ptr, byref colorptr as ptr, byref location as single, atIndex as Integer)
getColorlocationatIndex ( self, colorptr, location, atIndex )
GetColor = cocoa.NSObjectFromNSPtr (colorptr, true, true)
#endif
End Sub[/code]

Now I just need to find out how to make something work for a byref‘ed array – but NSGradient Class is complete now. Thanks a lot!

Hi Jim,

I noticed under Yosemite there are a few redraw problems – see the right part of the Searchfield after scaling the window.

The dark border seems to be too much. I tried to cancel the custom draw routines in the subclass but had no luck with it. Could you give me a hint on how to accomplish this?

What’s more, I cam uncertain if this is Yosemite behavior or due to your draw tweaks: When I enter text into the field and remove it, the Searchfieldcell “closes” and shows a “Search” text centered. Shouldn’t this occur by default?

Never mind, Jim. Could handle that – don’t know why it occurred in the first place because your example was without line and I just copied the class.
Only drawback is the control will not close with an animation when the close button is hit. But that’s not so important.

I posted this in a different thread which was completely unanswered, so I thought I would post it here, as it is also relevant here:

Since upgrading to the new OS - when I add a macoslib NSSearchField to my window - it initially appears with an erroneous focus ring (very faint and lighter blue color), and also acts as if I have clicked inside it (displaying the small x button). If I click on my listbox, the NSSearchField goes back to normal (displaying the placeholder text).

Is this normal behaviour with NSSearchFields on the new OS?

The erroneous focusring is not – Jim’s implementation shows the broad ring with animation on first getfocus event.

The look like it had been clicked inside (with placeholder text, but x button and menu) seems to be Mac OS X default.
I kicked off the modifications in the subclass here to have an unmodified class and cell class, but it behaves the same. Only when you enter text and remove it with the x, the closing animation appears (if you skip Jim’s own drawing routine and get back to the original – which doesn’t let you modify the colors but brings back the animation).

To illustrate what I mean:

Here the standard focus ring. I can only give the advice to change the system’s appearance to graphite instead of blue –I don’t like the colors:

and after the closing animation:

Ulrich,
I didn’t quite understand your last 2 posts.

Did you mean that in the new OS, it is normal for an NSSearchField to start off as per the first image in your screenshot?
If so, has this changed, as it seems to be the opposite of what I remember?

If you have an NSSearchField in a toolbar - it initially appears as in your second screenshot.
If you have the NSSearchField in a window, it appears as in your first screenshot.

I would imagine that all NSSearchFields should initially appear as in your second screenshot?

Thanks.

Hi Richard,

sorry for writing not that clearly, but you understood me right though :wink:

I would have thought the NSSearchfields would appear “closed” (the second image) everywhere like you said, but I experience the same like you for windows. Haven’t tried it on toolbars – interesting there’s a difference. For a default button to appear prominently, the parent (window) calls a method, it’s not a button property. I wonder if it’s the same for Searchfields?

With kicking out I meant that Jim has built a NSSearchfieldcell subclass where he catches the draw method and replaces it by an own, enabling the control to show different colors which the system’s class does not. I removed that modifications to see if the Searchfield would behave differently then. This is true for the “closed” state when you enter text and hit the “x” but makes no difference to their initial look.

The strange thing is… if I click on my listbox - the NSSearchField changes to that of your second screenshot.
But if I set focus to any controls - the NSSearchField does not change??

Very strange.

Yes, there are a few differences where I am uncertain if it’s missing system behavior or if Apple has customized their own controls (which they often do). For example when you click into AppleMail’s search field, the focusring animation is played each time it gets the focus. On Jim’s implementation it only animates it on the first event, afterwards the focusring shows up instantaneously.

Just checked mail. I have also noticed that if you QUICKLY click the grey coloured x button in the search field - nothing happens.
You have to slowly click for the NSSearchField to close.

Have you tried a different NSSearchField implementation?

If you’re using Jim’s try the MacOSLib, if you’re using MacOSLib, try Jim’s or try the MBS instead…

There’s only one place I’m currently using a NSSearchField, but that’s in a toolbar and it’s only enabled when on a certain screen, it appears to work as expected on Yosemite (mind you, I don’t expect much from Yosemite).

Ulrich, how did you get rid of that black border in Yosemite?

Uff, Richard: This is so long ago I don’t remember exactly. I think what I had done was to remove the custom draw methods and return to the OS built-in – so I lost ways to color the items but have a Searchfield that looks completely standard.
But I abandoned the idea of independent OS X enhanced controls in favor for an own core MacOSLib kind of library extending most classes via extensions and have not redone the Searchfield yet, so I have no current code available.

Ok np. I was guessing that would be the answer.

On a side note.
When I import the custom NSSearchfield in a project I can debug and build an application and don’t get a black outline. Whenever I close and then reopen the project the border appears. So there’s at least a workaround :stuck_out_tongue:

You should be able to remove all references to “MyCocoaCellSubclass”. That will drop the custom background color, but will get you the cool new animations under Yosemite.

I think the black border problem is due to the fact that Apple changed the shape of the search box from an oval to a rounded rectangle…