Page 1 of 2

API call help

Posted: Tue Aug 09, 2011 12:44 am
by spacebuddy
I am trying to call an API (NSOpenPanel) but running into problems.

I want to replace OpenFileRequester with NSOPenPanel. Any API gurus here :D

Re: API call help

Posted: Tue Aug 09, 2011 10:44 am
by Fred
Unfortunately, NSOPenPanel is Cocoa (objectiveC) and this is not accessible trough PB. The 'easier' is your really need it is to write a small wrapper in ObjectiveC which expose a C function and then call it from PB

Re: API call help

Posted: Tue Aug 09, 2011 4:47 pm
by wilbert
Fred is right, it's Cocoa.

Re: API call help

Posted: Tue Aug 09, 2011 5:05 pm
by Polo
By the way... ;)

How would you convert a PB string to a NSString?

This is what I do:

Code: Select all

void function (const char* pbstring)
{
NSString string = [NSString stringWithUTF8String: string];
}
When PB is in non unicode mode, it works if there aren't any special character in the PB String (ie éèë...)
When PB is in unicode mode, it only gets the first letter of the PB string into the NSString.

Any solution? :)

Re: API call help

Posted: Tue Aug 09, 2011 5:12 pm
by wilbert
Polo wrote:How would you convert a PB string to a NSString?
It's easier to use

NSString * string = [NSString stringWithFormat:@"%S", pbstring];

when unicode is used and

NSString * string = [NSString stringWithFormat:@"%s", pbstring];

when unicode is not used. That way you can use a static variable you set once that contains the format ( @"%S" or @"%s" ) and use the same convert function all the time.

Re: API call help

Posted: Tue Aug 09, 2011 5:13 pm
by Polo
Using Cocoa panels in PB, that's quite easy, just link your app with cocoa

ImportC "/System/Library/Frameworks/Cocoa.framework/Cocoa"
EndImport
ImportC "/System/Library/Frameworks/AppKit.framework/AppKit"
EndImport

(last one is just in case :) )

Create a static library with Xcode with the ObjC code you need, like this for instance, and import the C function in PB.
(you'd still need to handle the string conversion to make the panel customisable, which i didn't in the example below)

Code: Select all

void mOpenFileRequester()
{
NSString *title = "Requester title";
NSString *directory = "";
NSString *file = "";
NSString *extensions = "";

currentwin=[NSApp keyWindow];
if ( !currentwin ) [NSApp activateIgnoringOtherApps:YES];
    
NSOpenPanel *panel=[NSOpenPanel openPanel];
[panel setTitle:title];
		
if ( [panel runModalForDirectory:directory file:file types:extensions]==NSFileHandlingPanelOKButton )
{
  NSString *fileselected=[[panel filename] UTF8String];
}
	
if ( currentwin ) [currentwin makeKeyWindow];
}

Re: API call help

Posted: Tue Aug 09, 2011 5:20 pm
by Polo
Cheers wilbert, works great!

Re: API call help

Posted: Wed Jan 04, 2012 8:14 pm
by Khorus
I'd like to do the same (calling a Cocoa API). I need to access CoreMIDI to do some real-time MIDI. I used the WinAPI on Windows but it looks like a different game on MacOS X. Thanks!

Re: API call help

Posted: Thu Nov 07, 2013 9:26 pm
by Wolfram
Hi,

can some give me a easy example of this code. I'm a beginner and have no experience with C.

Thanks!

Re: API call help

Posted: Fri Nov 08, 2013 7:17 am
by wilbert
Wolfram wrote:can some give me a easy example of this code. I'm a beginner and have no experience with C.
I'm not sure what your goal is.
Polo gave a small piece of Objective-C code a few posts above if that's what you are looking for.

When it comes to the question this thread started with, it's no longer relevant. At that time, PureBasic for OS X was Carbon based.
The current 5.2x LTS version is Cocoa based and allows you to interact using the CocoaMessage() command.

Re: API call help

Posted: Fri Nov 08, 2013 8:15 am
by Danilo
Wolfram wrote:can some give me a easy example of this code. I'm a beginner and have no experience with C.
PB help says:
Note: The 'Pattern$' and 'PatternPosition' parameters have no effect on Mac OSX (the requester always displays all files).
So here a version with patterns, based on Polo's Objective-C code:

Code: Select all

Macro CreateCocoaObject(objectName,withMethod="alloc")
    CocoaMessage(0,0,objectName+" "+withMethod)
EndMacro


#showHiddenFiles        = 1
#allowMultipleSelection = 1 << 1
#returnAbsoluteNames    = 1 << 2

#NSFileHandlingPanelOKButton     = 1
#NSFileHandlingPanelCancelButton = 0

Procedure OpenFileRequester_(List out.s(), title.s, defaultdirectory.s="", pattern.s="", message.s="", flags=0)
    ClearList(out())
    NSApp = CreateCocoaObject("NSApplication")
    If NSApp
        currentwin = CocoaMessage(0,NSApp,"keyWindow")
        If Not currentwin
            CocoaMessage(0,NSApp,"activateIgnoringOtherApps:",#YES)
        EndIf
        
        panel = CreateCocoaObject("NSOpenPanel","openPanel")
        If panel
            ;
            ; set title
            ;
            CocoaMessage(0,panel,"setTitle:$",@title)
            
            ;
            ; set optional message text
            ;
            If message
                CocoaMessage(0,panel,"setMessage:$",@message)
            EndIf
            
            ;
            ; set allowed patterns, separated by '|'
            ;
            If pattern <> ""
                i = 1
                nextPattern.s = StringField(pattern,i,"|")
                fileTypesArray = CocoaMessage(0,0,"NSArray arrayWithObject:$", @nextPattern)
                Repeat
                    i + 1
                    nextPattern = StringField(pattern,i,"|")
                    If nextPattern
                        fileTypesArray = CocoaMessage(0,fileTypesArray, "arrayByAddingObject:$", @nextPattern)
                    EndIf
                Until nextPattern = ""
                CocoaMessage(0,panel,"setAllowedFileTypes:",fileTypesArray)
            EndIf
            
            ;
            ; show hidden files?
            ;
            If flags & #showHiddenFiles
                CocoaMessage(0,panel,"setShowsHiddenFiles:",#YES)
            EndIf
            
            ;
            ; allow multiple selection?
            ;
            If flags & #allowMultipleSelection
                CocoaMessage(0,panel,"setAllowsMultipleSelection:",#YES)
            EndIf
            
            ;
            ; set default directory
            ;
            url = CocoaMessage(0,0,"NSURL URLWithString:$",@defaultdirectory)
            CocoaMessage(0,panel,"setDirectoryURL:",url)
            
            ;
            ; run
            ;
            If CocoaMessage(0,panel,"runModal") = #NSFileHandlingPanelOKButton
            
                ;
                ; get results
                ;
                results = CocoaMessage(0,panel,"URLs")
                If results
                    count = CocoaMessage(0, results, "count")
                    If count
                        For i = 0 To count-1
                            NSURL = CocoaMessage(0,results,"objectAtIndex:",i)
                            If NSURL
                                If Not flags & #returnAbsoluteNames
                                    ;
                                    ; return file names
                                    ;
                                    string = CocoaMessage(0,NSURL,"fileSystemRepresentation")
                                    If string
                                        fileName.s = PeekS(string,-1,#PB_UTF8)
                                        If AddElement(out())
                                            out() = fileName
                                        EndIf
                                    EndIf
                                Else
                                    ;
                                    ; return absolute names
                                    ;
                                    string = CocoaMessage(0,NSURL,"absoluteString")
                                    If string
                                        utf8 = CocoaMessage(0,string,"UTF8String")
                                        If utf8
                                            fileName.s = PeekS(utf8,-1,#PB_UTF8)
                                            If AddElement(out())
                                                out() = fileName
                                            EndIf
                                        EndIf
                                    EndIf
                                EndIf
                            EndIf
                        Next i
                    EndIf
                EndIf
            EndIf
        EndIf
    EndIf
    If currentwin
        CocoaMessage(0,currentwin,"makeKeyWindow")
    EndIf
    ProcedureReturn count
EndProcedure




NewList files.s()

num = OpenFileRequester_( files(),
                          "Please choose file(s) to load",
                          "/users/",
                          "pb|pbi|prefs|rtf|txt",
                          "Optional message:"+#CR$+"Please open a file for loading."+#CR$+"Second message line",
                          #allowMultipleSelection |
                          #showHiddenFiles )

Debug num

ForEach files()
    Debug files()
Next
Polo's example used "runModalForDirectory:file:types:" method, and it was marked deprecated in OS X v10.6.
My version uses newer methods, but I think it requires at least OS X v10.6.

Re: API call help

Posted: Fri Nov 08, 2013 10:05 pm
by Wolfram
Many Thanks!

but I get an Error if I try to load a File
Object dose not respond to method "fileSystemRepresentation"

Re: API call help

Posted: Sat Nov 09, 2013 6:59 am
by wilbert
Wolfram wrote:Object dose not respond to method "fileSystemRepresentation"
The fileSystemRepresentation method requires OS X 10.9 (Mavericks).

Re: API call help

Posted: Sat Nov 09, 2013 8:06 am
by Danilo
Wolfram wrote:but I get an Error if I try to load a File
Object dose not respond to method "fileSystemRepresentation"
Does it work for you with flag '#returnAbsoluteNames'?
In this case you get results like "file:///users/danilo/todo.rtf", but it could
be different URL for Network files.

Re: API call help

Posted: Sat Nov 09, 2013 8:15 am
by wilbert
Here's also a simplified version of Danilo's approach returning all absolute names in one string separated by |
Minimum requirement is OS X 10.6

Code: Select all

#showHiddenFiles        = 1 << 0
#allowMultipleSelection = 1 << 1

Procedure.s OpenFileRequester_(title.s, defaultdirectory.s = "", pattern.s = "", message.s = "", flags = 0)
  Protected NSPanel, NSArray, NSString
  
  NSPanel = CocoaMessage(0, 0, "NSOpenPanel openPanel")
  NSArray = CocoaMessage(0, CocoaMessage(0, 0, "NSString stringWithString:$", @pattern), "componentsSeparatedByString:$", @"|")
  
  CocoaMessage(0, NSPanel, "setTitle:$", @title)
  CocoaMessage(0, NSPanel, "setDirectoryURL:", CocoaMessage(0, 0, "NSURL URLWithString:$", @defaultdirectory))
  CocoaMessage(0, NSPanel, "setAllowedFileTypes:", NSArray)
  CocoaMessage(0, NSPanel, "setMessage:$", @message)
  
  If flags & #showHiddenFiles
    CocoaMessage(0, NSPanel, "setShowsHiddenFiles:", #YES)
  EndIf
  
  If flags & #allowMultipleSelection
    CocoaMessage(0, NSPanel, "setAllowsMultipleSelection:", #YES)
  EndIf
  
  If CocoaMessage(0, NSPanel, "runModal")
    NSString = CocoaMessage(0, CocoaMessage(0, NSPanel, "URLs"), "componentsJoinedByString:$", @"|")
    ProcedureReturn PeekS(CocoaMessage(0, NSString, "UTF8String"), -1, #PB_UTF8)
  Else
    ProcedureReturn ""
  EndIf
  
EndProcedure


Debug OpenFileRequester_("Please choose file(s) to load",
                         "/users/",
                         "pb|pbi|prefs|rtf|txt",
                         "Optional message:"+#CR$+"Please open a file for loading."+#CR$+"Second message line",
                         #allowMultipleSelection |
                         #showHiddenFiles )