GUI

General User Interface

Es una interfase grafica que te permite acceder y controlar parámetros del código sin tener que ir directamente a él. Al ser una interfase la podemos ubicar como un punto intermedio entre el código y el usuario. SuperCollider provee los elementos mas comunes de una interfase como son botones, controles, perillas, campos numéricos y de texto, manipulacion de fuentes, colores, menus y tiene además cierto potencial gráfico. Las Clases que se usan para hacer GUIs tienen varios métodos que nos sirven para definir su comportamiento y  apariencia.
A continuación veremos las principales Clases para hacer uso la GUI.

SCWindow(name, bounds, resizable, border, server, scroll)
Es una clase que  crea una ventana sobre la cual podemos empezar a construir nuestra interfase.

name - Nombre. Un string (entre comillas) o un symbol (antecedido por una diagonal \). Este texto será el nombre que queremos que se vea en nuestra ventana. (no confundir con la variable asignada al nuestra instancia de SCWindow).

bounds - Límites. Las dimensiones de la ventana. Para esto necesitamos la clase Rect que, a traves de cuatro argumentos, nos permite definir la posición y el tamaño de la ventana. 

resizable - Redimensionable. Un boleano (true / false) indicando si la ventana se puede redimensionar (hacer mas grande o mas chica). Default - true

border - Borde. Un boleano (true / false) indicando si la ventana tendrá o no la pestaña superior que contiene el name y los botones para cerrar y minimizar y maximizar. /* ¡¡¡CUIDADO!!! */ Si quitas el border no podras cerrar la ventana a menos que lo hagas desde el código. Default - true.
 
server - Un argumento idiota. Solo sirve para proveer compatibilidad con SwingOSC. O sea qu no le hagan caso. Default - agagaggu

scroll - Pergamino. Un boleano (true / false) indicando si la ventana tendrá la capacidad de mostrar su contenido como pergamino en caso de que este exceda las dimensiones de la ventana. Si damos true a este argumento el argumento resizable queda anulado. Default - false.

Ejemplo 1

a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front

Para empezar asignamos la SCWindow a una variable para poder referirnos a la instancia que estamos creando. Nuestra ventana se llama "la ventanita del amor". Sus dimensiones estan dadas con la clase Rect que, a traves de cuatro argumentos, nos permite definir la posición y el tamaño de la ventana (ver ejamplo 2). Los demás argumentos los dejamos con los valores predeterminados (default)

Ejemplo 2

Rect(posición en x, posición en y, tamaño en x, tamaño en y)

Las cordenadas en la pantalla tienen su origen en la esquina inferior izquierda. (O sea que ahi es el (0,0)). Por el contrario, las cordenadas en la SCWindow tienen su origen en la esquina superior izquierda. En el ejemplo 1 tenemos una ventana que tiene su borde izquierdo a 100 pixeles de distancia del marco izquierdo de la pantalla, su borde inferior esta a 100 pixeles del marco inferior de la pantalla y tiene de ancho 400 pixeles y de alto 300 pixeles.

SCButton(parent, bounds)
Es una clase que  crea un botón dentro de nuestra ventana.

parent - Ventana en la que queremos que se cree el botón. Nos referimos a la ventana con la variable que le hallamos asignado.
bounds - Dimensiones del botón. Se necesita la clase Rect.

Existen algunos métodos básicos para configurar nuestro SCButton.

states - Sirve para detrminar cuántos estados tiene nuestro botón: 1 estado, 2 estados, 5 estados... cuántos estados quieres? Al mismo tiempo determina el texto, el color del texto y el color del fondo para cada estado. Los cambios de estado se originan al apretar el botón.

action - Es una función que determina la acción que se realizará al cambiar a un estado específico. 

Ejemplo 3

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;
b=SCButton(a, Rect(100,10,150,100));
b.states=[["nO", Color.white, Color.black]];
b.action={|val| val.value.postln; "tengo miedo".postln};
)

En el ejemplo 3 creamos nuevamente una instancia a de SCWindow y una instancia b de SCButton. Colocamos el botón en la ventana a. A través de la clase Rect colocamos el botón a 100 pixeles hacia la derecha y a 10 pixeles hacia abajo. Le damos 150 pixeles de ancho y 100 de alto. Después, mediante el método states, determinamos los estados que va a tener nuestro boton. Para esto hacemos un array dentro del cual colocamos arrays para cada estado. Cada array de estado tiene tres elementos : 
1 - el texto ente comillas, 
2 - el color del texto y 
3 - el color del fondo. 
Los coloes los designamos mediante la clase Color. Es recomendable ir al archivo de ayuda para ver cómo funciona esta clase. En el ejemplo 3 tenemos un estado que despliega el texto "nO" de color blanco sobre negro. El siguiente método es action. Toda la accion del botón va dentro de llaves {}. Dentro de las llaves primero creamos un argumento que puede tener el nombre que queramos. En este caso usamos val. Se puede crear con pipes |val| o escribiendo arg val;
Después podemos escribir las acciones que queramos separadas por ;

Ejemplo 4

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;
b=SCButton(a, Rect(100,100,150,100));
b.states=[["nO", Color.white, Color.black], ["Si", Color.black, Color.red]];
b.action={|val| if(val.value==0, {"tengo hambre".postln}, {"se me enterro una yema".postln})};
)

En el Ejemplo 4 tenemos 2 estados en el método states. Por eso tenemos un array cuyos elementos son dos arrays. En el método action hemos incluido un if que evalúa al argumnto val. Necesitamos usar el método value (val.value) para poder evaluarlo. En el ejemplo hemos decidio que si val es 0 entonces se escribe "tengo hambre" y si no es 0 escribe "se me enterro una yema". Los estados se empiezan a contar a partir del 0. Asi que en este caso tenemos el estado 0 y el estado 1.

Ejemplo 4.5

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;
b=SCButton(a, Rect(100,100,150,100));
b.font=Font("BrushScriptMT", 70);
b.states=[["nO", Color.white, Color.black], ["Si", Color.black, Color.red]];
b.action={|val| if(val.value==0, {"tengo hambre".postln}, {"se me enterro una yema".postln})};
)

En el ejemplo 4.5 agregamos el metodo Font para cambier las caracteristicas de la letra. Ver el archivo de ayuda de Font y poner especial atencion en el segundo ejemplo.

Ejemplo 5

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;
b=SCButton(a, Rect(100,100,150,100));
b.states=[["nO", Color.white, Color.black], ["Si", Color.black, Color.red]];
b.action={|val| 
				if(val.value==0, {
											{Pulse.ar(XLine.kr(60,2000,0.125, doneAction:2),0.5,0.5)}.play
											}, 
											{
											{Saw.ar(SinOsc.kr(10,0,100,300))*Line.kr(1,0,0.5,doneAction:2)}.play 
											}
					)
				};
)

En el ejemplo 5 asignamos Synths a las acciones del boton de igual manera que lo hicimos con los textos en el ejemplo 4. También podemos encender Tdefs y detenerlos como se muestra en el ejemplo 6.

Ejemplo 6

(
Tdef(\escrupuloso, {var cuenta=0;
					  inf.do{
					  		  switch(cuenta%4,0,{{Pulse.ar(XLine.kr(60,2000,0.125, doneAction:2),0.5,0.5)}.play},
					  		  			     1,{{Saw.ar(SinOsc.kr(10,0,100,300))*Line.kr(1,0,0.25,doneAction:2)}.play},
					  		  			     2,{{Pulse.ar(XLine.kr(60,400,0.125, doneAction:2),0.5,0.5)}.play},
					  		  			     3,{{Saw.ar(SinOsc.kr(10,0,100,rrand(300,1000)))*Line.kr(1,0,0.25,doneAction:2)}.play}
					  		  		);
					  		  	cuenta=cuenta+1;
					  		  	0.2.wait;
					  		  	}
					  	}).quant_(0);
)

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;
b=SCButton(a, Rect(100,100,150,100));
b.states=[["nO", Color.white, Color.black], ["Si", Color.black, Color.red]];
b.action={|val| 
				if(val.value==1, {
											Tdef(\escrupuloso).play;
											"El escrupuloso anda".postln;
											}, 
											{
											Tdef(\escrupuloso).stop;
											"El escrupuloso no va".postln;
											}
					)
				};
)

Agregemos ahora otro boton para darle mas funcionalidad a la GUI. En el ejemplo 7 ponemos un boton que nos dispare un Synth.

Ejemplo 7

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;

b=SCButton(a, Rect(50,100,150,100));
b.states=[["nO", Color.white, Color.black], ["Si", Color.black, Color.red]];
b.action={|val| 
				if(val.value==1, {
											Tdef(\escrupuloso).play;
											"El escrupuloso anda".postln;
											}, 
											{
											Tdef(\escrupuloso).stop;
											"El escrupuloso no va".postln;
											}
					)
				};
				
c=SCButton(a, Rect(210,100,150,100));
c.states=[["WepA!!", Color.white, Color.black]];
c.action={{RHPF.ar(Saw.ar(30),rrand(200,1000),0.1,2.5)*Line.kr(1,0,0.41,doneAction:2)}.play};
)

Observar como en el ejemplo 7 al nuevo boton se le asigno una variable propia, en este caso c, y la posición dada por el Rect tiene coordenadas diferentes para que no se encime con el boton b.

Para cambiar el propiedades de un objeto en una ventana desde afuera usamos el metodo .valueAction como en el ejemplo 8

Ejemplo 8

(
a=SCWindow("la ventanita del amor", Rect(100,100,400,300)).front;
b=SCButton(a, Rect(100,10,150,100));
b.states=[["nO", Color.white, Color.black],["bueno", Color.red, Color.white]];
b.action={|val| val.value.postln; "tengo miedo".postln};
)

b.valueAction=1
b.valueAction=0

Cabe mencionar que si queremos cambiar estas propiedades desde un Tdef de manera automatica necesitamos poner entre llaves {} la linea que realizara esta accion

Esto no sirve

(
Tdef(\vaya, {
					inf.do{|i|
								b.valueAction=i%2;
								0.5.wait;
								}
					})
)				

Tdef(\vaya).play

Pero esto si

(
Tdef(\vaya, {
					inf.do{|i|
								{b.valueAction=i%2}.defer;
								0.5.wait;
								}
					})
)				

Tdef(\vaya).play
Tdef(\vaya).stop