Buffer.loadDialog


#1

I’m busy building a recording GUI and I’m wondering if there’s a way to set where Buffer.loadDialog opens by default? Can it be set in some way to open (or point it) at a particular folder?

Or maybe there’s a better solution?

Thanks in advance.

p.s. Why I’m at it can someone tell me why you get the “WARNING: Called from Meta_Buffer:loadDialog, method Meta_File:openDialog is deprecated and will be removed”. Is there a newer/different version of loadDialogue somewhere that I haven’t noticed?


#2

No.

Buffer.loadDialog uses File.openDialog (which should be changed to Dialog.openPanel). Unfortunately, this way does not allow the user to specify a starting path. Oh, I’m wrong… Dialog.openPanel does support a starting path. But Buffer.loadDialog doesn’t expose that as an option.

In my last GUI project, I’m using FileDialog directly. I always have to look up some of the arguments (explained well in the help file, so, not really a problem) but it has a number of features not supported by openDialog.

// fileMode: 1 = single existing file (use 0 for saving)
// acceptMode: 0 = opening; 1 = saving
FileDialog(okFunc, cancelFunc, fileMode: 1, acceptMode: 0, stripResult: false, path)

// For example:
FileDialog({ |path| path.postcs }, fileMode: 1, acceptMode: 0, stripResult: false)
-->
[ "/home/dlm/export-1.wav" ]

// EDIT: But this is probably a little easier
Dialog.openPanel({ |path| path.postcs }, path: Platform.resourceDir);
-->
"/usr/local/share/SuperCollider/README.md"

Or stripResult: true to get just the path as a string, without the array container (which is for the case of selecting multiple files at once).

The one tricky thing you might run into with this is that Buffer.loadDialog gives you the buffer object (with bufnum) Right Now but waits until you answer the dialog to fill it. You might have other code that needs to wait until the buffer number is available. I’d do it this way:

var buffer;

{
	var cond = Condition.new;
	Dialog.openPanel({ |path|
		buffer = Buffer.read(s, path[0]);
		cond.unhang;  // resume after 'hang'
	}, path: "/path/to/starting/folder");
	cond.hang;  // wait for dialog
	s.sync;
	// now the buffer is ready
}.fork(AppClock);

FWIW I think that many such convenience methods ought to be deprecated and eventually removed. As you found, it has limitations.

p.s. Why I’m at it can someone tell me why you get the “WARNING: Called from Meta_Buffer:loadDialog, method Meta_File:openDialog is deprecated and will be removed”.

That’s another reason a/ why we as a community should be careful about adding convenience methods in the first place and b/ why we should probably prune some of them away.

Issue 3506 explains why openDialog and saveDialog were deprecated (which I think was a good move). However, the change in #3507 didn’t catch other places in the class library where the old methods were used.

That is: Having Buffer.loadDialog adds a maintenance cost to the project, for (I would argue) little-to-no gain. Usually you don’t see the cost, except in a case like this, where the deprecation was incomplete.

I’ll put in a PR to fix it.

hjh


#3

Hi James, big thanks, as always some very useful information. I’ll go and give all that a try.

Thanks again.


#4

Just one thing to be aware of:

FileDialog has the disadvantage of randomly hanging up on some systems (that is, mine :frowning: ) with no way to recover other than killing sclang.

Your mileage may vary but for me, bug #3807 is quite critical. Unfortunately it doesn’t get any attention at the moment, presumably because not many suffer from it - even though it is thought to be caused by a rather fundamental design problem (details in the bug record).


#5

FileDialog is the only way to prompt the user for a file location.

Dialog {

	*openPanel { arg okFunc, cancelFunc, multipleSelection = false, path;
		var fileMode;
		if( multipleSelection ) { fileMode = 3 } { fileMode = 1 };
		^FileDialog.new( okFunc, cancelFunc, fileMode, 0, multipleSelection.not, path );
	}

	*savePanel { arg okFunc, cancelFunc, path;
		^FileDialog.new( okFunc, cancelFunc, 0, 1, true, path );
	}
}

There’s no advantage or disadvantage over any other class. That’s all you’ve got.

hjh


#6

Hi James, I don’t know if I understood correctly, but when I run the above code (as suggested) I indeed get to choose a file, but then I just get this: FAILURE IN SERVER /b_allocRead wrong argument type? Any suggestions?


#7

My mistake. I originally wrote the example with FileDialog, then realized I could do it with Dialog.openPanel. But I didn’t update the function.

	Dialog.openPanel({ |path|
		buffer = Buffer.read(s, path);
		cond.unhang;  // resume after 'hang'
	}, path: "/path/to/starting/folder");

hjh


#8

Perfect, that works now, thanks.