Is there a way to easily open up a dialogue to load files from your harddrive into an OF app. It does not need to be cross platform but for Macosx. Any way of doing this?
The search didn’t really tell me anything about it.
Is there a way to easily open up a dialogue to load files from your harddrive into an OF app. It does not need to be cross platform but for Macosx. Any way of doing this?
The search didn’t really tell me anything about it.
that would be a great addon actually –
there is some different ways to do this i saw as a poked around, but nothing as simple as the windows.
here’s what I found,
http://www.xsquawkbox.net/info/src/PlatformUtils.mac.c
that I threw into testApp.cpp (at the top) like this:
#include "testApp.h"
#include <Carbon/Carbon.h>
#include <string.h>
static OSErr FSSpecToPathName(const FSSpec * inFileSpec, char * outPathname);
static DialogPtr sDialog = NULL;
int GetFilePathFromUser(const char * inPrompt, char * outFileName);
/* Get FilePathFromUser puts up a nav services dialog box and converts the results
to a C string path. */
int GetFilePathFromUser(const char * inPrompt, char * outFileName)
{
OSErr err;
NavReplyRecord reply;
NavDialogOptions options;
FSSpec fileSpec;
reply.version = kNavReplyRecordVersion;
err = NavGetDefaultDialogOptions(&options);
if (err != noErr)
return 0;
options.message[0] = strlen(inPrompt);
memcpy(options.message+1,inPrompt, options.message[0]);
memcpy(options.actionButtonLabel, "\pConvert", 8);
options.dialogOptionFlags &= ~kNavAllowMultipleFiles;
err = NavGetFile(NULL, &reply, &options, NULL, NULL, NULL, NULL, NULL);
if ((err != noErr) && (err != userCanceledErr))
return 0;
if (!reply.validRecord)
goto bail;
/* Convert the result from an AEDesc to a Mac file spec. */
err = AEGetNthPtr(&reply.selection, 1, typeFSS, NULL, NULL, &fileSpec, sizeof(fileSpec), NULL);
if (err != noErr)
goto bail;
/* Then convert the FSSpec to a full path. */
err = FSSpecToPathName(&fileSpec, outFileName);
if (err != noErr)
goto bail;
NavDisposeReply(&reply);
return 1;
bail:
NavDisposeReply(&reply);
return 0;
}
void DoUserAlert(const char * inMsg)
{
Str255 p1;
size_t sl;
sl = strlen(inMsg);
if (sl > 255)
sl = 255;
p1[0] = sl;
memcpy(p1+1, inMsg, sl);
StandardAlert(kAlertStopAlert, p1, "\p", NULL, NULL);
}
void ShowProgressMessage(const char * inMsg)
{
Handle item;
Str255 pStr;
Rect r;
DialogItemType t;
pStr[0] = strlen(inMsg);
memcpy(pStr+1, inMsg, pStr[0]);
if (sDialog == NULL)
{
/* If our dialog isn't up, put it up. */
sDialog = GetNewDialog(128, NULL, (WindowRef) -1L);
ShowWindow(GetDialogWindow(sDialog));
}
GetDialogItem(sDialog, 1, &t, &item, &r);
SetDialogItemText(item, pStr);
}
int ConfirmMessage(const char * inMsg, const char * proceedBtn, const char * cancelBtn)
{
Str255 pStr, proStr, clcStr;
AlertStdAlertParamRec params;
short itemHit;
pStr[0] = strlen(inMsg);
memcpy(pStr+1,inMsg,pStr[0]);
proStr[0] = strlen(proceedBtn);
memcpy(proStr+1, proceedBtn, proStr[0]);
clcStr[0] = strlen(cancelBtn);
memcpy(clcStr+1, cancelBtn, clcStr[0]);
params.movable = false;
params.helpButton = false;
params.filterProc = NULL;
params.defaultText = proStr;
params.cancelText = clcStr;
params.otherText = NULL;
params.defaultButton = 1;
params.cancelButton = 2;
params.position = kWindowDefaultPosition;
StandardAlert(kAlertCautionAlert, pStr, "\p", ¶ms, &itemHit);
return (itemHit == 1);
}
/*
* FSSpecToPathName
*
* This routine builds a full path from a file spec by recursing up the directory
* tree to the route, prepending each directory name.
*
*/
OSErr FSSpecToPathName(const FSSpec * inFileSpec, char * outPathname)
{
short vRefNum = inFileSpec->vRefNum;
long startDirID = inFileSpec->parID;
CInfoPBRec paramRec;
Str255 dirName; /* This will contain the name of the directory we get info about. */
OSErr err = noErr;
paramRec.dirInfo.ioCompletion = nil;
paramRec.dirInfo.ioNamePtr = (StringPtr)(&dirName);
paramRec.dirInfo.ioDrParID = startDirID;
/* Start by putting a directory separator and the file name on the path. */
outPathname[0] = ':';
memcpy(outPathname+1, inFileSpec->name+1, inFileSpec->name[0]);
outPathname[inFileSpec->name[0]+1] = 0;
do {
paramRec.dirInfo.ioVRefNum = vRefNum;
paramRec.dirInfo.ioFDirIndex = -1;
paramRec.dirInfo.ioDrDirID = paramRec.dirInfo.ioDrParID;
if (!(err = PBGetCatInfoSync(¶mRec)))
{
/* For each directory we get info about, prepend a : and the directory name.
But for the root directory, do NOT prepend the colon. */
short newPart = dirName[0] + ((paramRec.dirInfo.ioDrDirID != fsRtDirID) ? 1 : 0);
memmove(outPathname+newPart, outPathname, strlen(outPathname)+1);
if (paramRec.dirInfo.ioDrDirID != fsRtDirID)
{
outPathname[0] = ':';
memcpy(outPathname+1, dirName+1, dirName[0]);
} else
memcpy(outPathname, dirName+1, dirName[0]);
}
} while ((err == noErr) && (paramRec.dirInfo.ioDrDirID != fsRtDirID));
return err;
}
then to use:
//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
char path[1024];
if (GetFilePathFromUser("please pick a file", path)){
printf("user picked: %s \n", path);
} else {
printf("user cancelled \n");
}
}
currently I am getting back mac paths, like
user picked: Macintosh HD:Users:zach:Downloads:myLine2.cpp
but I guess that you could either change that to be a unix path by hand, or by altering “FSSpecToPathName”
hope that helps!
best,
zach
thanks zach, I will check that out. It would be a great addon indeed!
I will propably use this to load images. can I only replace the “:” in the mac path to “/” so of will understand it? does ofImage support paths anyways?
EDIT: Okay I just got it. A unix path to something on my desktop would be:
/Users/matthiasdorfelt/Desktop/blubb.jpg
it also works with ofImage, great!
here is another post with some solutions for an open dialog in os x.
http://forum.openframeworks.cc/t/file-dialog/955/0
Does anybody have similar code for saving files to the harddrive?
nobody?
edit:
just found something in the other thread:
Questions over questions:
I would like to tell the open Dialogue only to accept .jpg and .png files. Right now I would just check it afterwards. Is there a way to tell it to only accept certain file types?
And what would I have to change to be able to select multiple files at once?
Thanks!
Okay, I figgured it out myself. Was quite alot of pain since apples documentation is pretty bad (especially the search function ):
this function allows me to select multiple images at once and return me the according paths so I can load the via OFs loadImage:
struct path{
char p[1024];
};
vector<path> GetOpenFilesFromUser()
{
NavDialogCreationOptions dialogOptions;
NavDialogRef dialog;
NavReplyRecord replyRecord;
vector<FSRef> fileAsFSRef;
vector<path> files;
OSStatus status;
// Get the standard set of defaults
status = NavGetDefaultDialogCreationOptions(&dialogOptions);
require_noerr( status, CantGetNavOptions );
// Make the window app-wide modal
dialogOptions.modality = kWindowModalityAppModal;
// Create the dialog
status = NavCreateGetFileDialog(&dialogOptions, NULL, NULL, NULL, NULL, NULL, &dialog);
require_noerr( status, CantCreateDialog );
// Filter, so you can only select .jpg or .png
CFMutableArrayRef identifiers = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
CFArrayAppendValue(identifiers, kUTTypeJPEG);
CFArrayAppendValue(identifiers, kUTTypePNG);
CFArrayAppendValue(identifiers, kUTTypeTIFF);
status = NavDialogSetFilterTypeIdentifiers(dialog, identifiers);
require_noerr( status, CantRunDialog );
// Show it
status = NavDialogRun(dialog);
require_noerr( status, CantRunDialog );
// Get the reply
status = NavDialogGetReply(dialog, &replyRecord);
require( ((status == noErr) || (status == userCanceledErr)), CantGetReply );
// If the user clicked "Cancel", just bail
if ( status == userCanceledErr ) goto UserCanceled;
// Get File Count
long numFiles;
AECountItems(&(replyRecord.selection), &numFiles);
// Get the files
for(int i=0; i<numFiles; i++){
FSRef f;
path p;
fileAsFSRef.push_back(f);
status = AEGetNthPtr(&(replyRecord.selection), i+1, typeFSRef, NULL, NULL, &fileAsFSRef.at(i), sizeof(FSRef), NULL);
//Convert to Path
FSRefMakePath( &fileAsFSRef.at(i), ( UInt8 * ) p.p, sizeof( p ) );
files.push_back(p);
//cout<<files.back().p<<endl;
}
require_noerr( status, CantExtractFSRef );
// Cleanup
CantExtractFSRef:
UserCanceled:
verify_noerr( NavDisposeReply(&replyRecord) );
CantGetReply:
CantRunDialog:
NavDialogDispose(dialog);
CantCreateDialog:
CantGetNavOptions:
return files;
}
I am pretty sure that this is not the best way but it works fast and good for me.
Very useful! Works great in 0.06 too.
It would be good to get this going cross platform, but I hate COM! Anyone with any experience?
Cheers,
JGL
I’ve been playing around with this kind of Cocoa dialog for a while, and the problem I have is that it jams the rest of the application while it’s running…
I’d like to be able to use the standard Mac dialog to open video files, but I don’t want it to stop a video that is already playing.
Has anyone had any luck getting a dialog box to open in a thread?
From what I can see this isn’t as simple as using the ofxThread method, as Cocoa requires it’s own threading (NSThread) and memory management (NSAutoReleasePool)…???
Any suggestions would be most welcome.
I’ve had this issues as well. It has something to do with the runloop/clock system in OSX. There are 3 different clocks that come in to play depending on what “mode” the application is in.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSModalPanelRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
I forget exactly what NSEventTrackingRunLoopMode means, but NSDefaultRunLoopMode is during standard operation, NSModalPanelRunLoopMode is the one you’re actually looking for as it kicks in when the open file panel shows up. As for how to get this to drive the GLUT/OF timer, I can’t say but this is certainly where you should start looking.