#include <stdio.h>

/* necesarios para las operaciones de crear cada widget */ 
#include <Xm/Form.h>
#include <Xm/DrawingA.h>
#include <Xm/RowColumn.h>
#include <Xm/CascadeB.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>

/* para acceder a los distintos cursores predefinidos */
#include <X11/cursorfont.h>


Widget		toplevel,form,draw,menu,panel,boton;	/* Widget del shell */

/* el tipo cadena de Motif */
XmString        label;

/* altura anchura */
int		width, height;

/*Fondo y pincel*/
int		Fondo,Pincel;

/* tipo de operaciÆn de dibujo, puntos del polÕgono, punto anterior */
int             tipo=-1,npuntos=0,px,py;
/* puntero a los puntos del polÕgono */
XPoint		*verti;

/* variable empleada para cambiar el cursor en un widget */
Cursor          pua;

GC		gc;
XGCValues       valgc;

Display		*dpy;
Window		win;

/* prototipos */
void Decide();
void Pinta();
void Redibu();
void Salir();
Widget MCreaPushButton();
Widget MCreaCascadeButton();

/* color */
static XtArgVal GetPixel(shell,color)
Widget shell;
char *color;
{
XrmValue from,to;

from.size=strlen(color)+1;
if (from.size < sizeof(String)) from.size=sizeof(String);
from.addr=color;
to.addr=NULL;
XtConvert(shell,XmRString,&from,XmRPixel,&to);

return((XtArgVal) *((XtArgVal *)to.addr));
}

/**********************************************************************/

main(argc, argv)
int	argc;
char	**argv;	
{
Arg	args[10];
int 	n;
XtAppContext	app_context;

/* CreaciÆn del shell y la conexiÆn al server */

  toplevel=XtAppInitialize(&app_context,"",NULL,0,&argc,argv,NULL,args,0);

   width=height=650;

   n=0;
   XtSetArg(args[n],XmNwidth,width); n++;
   XtSetArg(args[n],XmNheight,height); n++;
   XtSetArg(args[n],XmNbackground,GetPixel(toplevel,"brown")); n++;
   XtSetArg(args[n],XmNnoResize,True); n++;
   form=XmCreateForm(toplevel,"",args,n);

   XtManageChild(form);

/* CreaciÆn de una barra de menÇ, anclada a form por tres lados */

   n=0;
   XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
   XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
   XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
   menu=XmCreateMenuBar(form,"",args,n);

/* de la barra descolgarÄ otro menÇ */
   panel=XmCreatePulldownMenu(menu,"",NULL,0);

/* el menÇ descolgado tendrÄ varias opciones (descendientes), que serÄn botones Gadgets porque no tendrÄn descendientes en este caso, cada creaciÆn tiene una estrutura similar */

   /* transformamos una cadena a la del tipo Motif */
   
   MCreaPushButton(panel,"Punto",'P',Decide,0);   
   MCreaPushButton(panel,"Linea",'L',Decide,1);   
   MCreaPushButton(panel,"Poligono",'o',Decide,2);   
   MCreaPushButton(panel,"Relleno",'R',Decide,3);   

/* Creamos los botones de cascada, con algunos de ellos nos interesa guardar el Widget creado por lo que utilizo boton para su posterior reutilizacion */

   MCreaCascadeButton(menu,"Dibujo",'D',panel);
   boton=MCreaCascadeButton(menu,"Salir",'S',NULL);
   XtAddCallback(boton,XmNactivateCallback,Salir,NULL);
   boton=MCreaCascadeButton(menu,"Ayuda",'A',NULL);

   n=0;
   XtSetArg(args[n],XmNmenuHelpWidget,boton);n++;
   XtSetValues(menu,args,n);

   XtManageChild(menu);
   
   Fondo=GetPixel(toplevel,"white");
   Pincel=GetPixel(toplevel,"red");

/* CreacÆn de un Ärea de dibujo con sus caracterÕsticas */

   n=0;
   XtSetArg(args[n],XmNwidth,width); n++;
   XtSetArg(args[n],XmNheight,height); n++;
   XtSetArg(args[n],XmNbackground,Fondo); n++;
   XtSetArg(args[n],XmNforeground,Pincel); n++;

/* La anclamos por arriba con la barra de menÇ */

   XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
   XtSetArg(args[n],XmNtopWidget,menu); n++;

   XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
   XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
   draw=XmCreateDrawingArea(form,"",args,n);
   XtManageChild(draw);

   n=0;
   XtSetArg(args[n],XmNbackground,&valgc.background); n++;
   XtSetArg(args[n],XmNforeground,&valgc.foreground); n++;
   XtGetValues(draw,args,n);
   gc=XtGetGC(draw,GCForeground | GCBackground,&valgc);

/* Controlar los eventos de ratÆn sobre el Ärea de dibujo con Pinta */
   XtAddEventHandler(draw,ButtonPressMask,True,(XtEventHandler)Pinta,NULL);
   XtAddEventHandler(draw,ButtonReleaseMask,True,(XtEventHandler)Pinta,NULL);
   XtAddEventHandler(draw,PointerMotionMask,True,(XtEventHandler)Pinta,NULL);



/* Si se tapa nuestra ventana, o se mueve se deberÕa controlar para evitar efectos indeseados */
   XtAddEventHandler(draw,ExposureMask,True,(XtEventHandler)Redibu,NULL);

   XtRealizeWidget(toplevel);

/* Definimos otro tipo de cursor en la zona que afecte a la barra de menÇ, esto debe hacerse tras la instrucciÆn de activar el toplevel */

   dpy=XtDisplay(draw);
   win=XtWindow(draw);
   pua=XCreateFontCursor(dpy,XC_hand2);
   XDefineCursor(dpy,XtWindow(menu),pua);

   XtAppMainLoop(app_context);
}	

void Decide(w,client_data,call_data)
Widget	w;
XtPointer	client_data;
XtPointer	call_data;
{

/* Hay varios casos, 0 dibuja puntos, 1 lÕneas, 2 y 3 polÕgonos, pero en 3 rellenos */
    switch (tipo=(int)client_data)
    {
    case 2:
    case 3:
	free(verti);
	verti=(XPoint *)malloc(30*sizeof(XPoint));
    case 1:
	npuntos=0;
	break;
    default:
	break;
    }
}

/*void Redibu(w,client_data,call_data)
Widget	w;
XtPointer	client_data;
XtPointer	call_data;*/

void Redibu(w,client_data,event)
Widget	w;
XtPointer	client_data;
XEvent		*event;
{
XExposeEvent	*evento;

	evento=(XExposeEvent *)event;

	printf("AquÕ deberÕamos redibujar\n");
}

void Salir()
{
/* Libero memoria y contexto grafico y terminamos de forma limpia */
	free(verti);
	XtReleaseGC(draw,gc);
	exit(1);
}

void Pinta(w,client_data,event)
Widget	w;
XtPointer	client_data;
XEvent		*event;
{
XButtonEvent    *evento;
XMotionEvent    *Motionevento;
int		x,y;
   
   
   switch(event->type){
/* extracciÆn de parÄmetros necesarios para dibujar. Sobre GC, el contexto grÄfico podrÕamos definir nuestras preferencias, aquÕ tomo uno por defecto */


    case ButtonPress:
    	evento=(XButtonEvent *)event;
	
    	x=evento->x;
    	y=evento->y;

/* SegÇn el botÆn pulsado, y en cada caso segÇn el tipo de dibujo */
    	switch (evento->button)
    	{
		case Button1:

	    		switch (tipo)
			{
		   		case 0:
					XDrawPoint(dpy,win,gc,x,y);
				break;
		  		case 2:/* almacena puntos del polÕgono */
		   		case 3:/* antes de dibujar la lÕnea */
					verti[npuntos].x=x;
					verti[npuntos].y=y;
		    		case 1:/* dibuja lÕneas desde el segundo punto */
					if (npuntos++>0)
			   			XDrawLine(dpy,win,gc,x,y,px,py);
					else
			   			XDrawPoint(dpy,win,gc,x,y);
       					px=x;
					py=y;
					break;
   		     		
   		 		default:
					break;
			}    
			break;
		case Button2:
/* SÆlo para polÕgonos, lo cierra y dibuja */
	    		switch (tipo)
			{
		    	case 2:
		    	case 3:
				verti[npuntos]=verti[0];
				if (tipo==2) XDrawLines(dpy,win,gc,verti,++npuntos,CoordModeOrigin);
			   	else
			       	XFillPolygon(dpy,win,gc,verti,++npuntos,Complex,CoordModeOrigin);
				XFree(verti);
				npuntos=0;
				break;
   		 	default:
				break;
		}    
		break;
		case Button3:
	/* Poder comenzar otra lÕnea poligonal */
	    		switch (tipo)
			{
		    	case 1:
				npuntos=0;
				break;
   		 	default:
				break;
			}    
			break;

		default: break;
     	}	
     	
     	break;
     	case ButtonRelease:
     		evento=(XButtonEvent *)event;
     		printf("Suelto\n");
     		
     		break;
     	case MotionNotify:
     		Motionevento=(XMotionEvent *)event;
     		
     		x=Motionevento->x;
    		y=Motionevento->y;
    		
  
     		printf("x %d; y%d\n",Motionevento->x,Motionevento->y);
     		break;
     	default:
     		break;		
     
     }
}

Widget MCreaPushButton(padre,str,mnemo,rutina,dato)
Widget	padre;
char	*str,mnemo;
void	(*rutina)();
int	dato;
{
int	n;
Arg	args[10];
XmString	label;
Widget	boton;

   label=XmStringCreateSimple(str);
   n=0;
   XtSetArg(args[n],XmNlabelString,label);n++;
   XtSetArg(args[n],XmNmnemonic,mnemo);n++;

   boton=XmCreatePushButtonGadget(padre,"",args,n);

/* Cuando se active el botÆn se ejecutarÄ la rutina Decide, con parÄmetro 0 */
   XtAddCallback(boton,XmNactivateCallback,(XtCallbackProc)rutina,(XtPointer)dato);

   XtManageChild(boton);
   XmStringFree(label);

   return(boton);
}

Widget MCreaCascadeButton(padre,str,mnemo,panel)
Widget	padre;
char	*str,mnemo;
Widget	panel;
{
Arg	args[10];
XmString	label;
Widget	boton;
int	n;

   label=XmStringCreateSimple(str);
   n=0;
   XtSetArg(args[n],XmNlabelString,label);n++;
   XtSetArg(args[n],XmNmnemonic,mnemo);n++;
   XtSetArg(args[n],XmNsubMenuId,panel);n++;
   boton=XmCreateCascadeButton(padre,"",args,n);

   XtManageChild(boton);
   XmStringFree(label);

   return(boton);

}

