#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;

/* 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;
Screen		*scr;

/* 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);

/* 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,GetPixel(toplevel,"white")); n++;
   XtSetArg(args[n],XmNforeground,GetPixel(toplevel,"red")); 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);

/* Si se tapa nuestra ventana, o se mueve se deberÕa controlar para evitar efectos indeseados */
   XtAddCallback(draw,XmNexposeCallback,(XtCallbackProc)Redibu,NULL);

/* Para conocer las dimensiones de la pantalla*/
   scr=XtScreen(toplevel);
   printf("Ancho %ld, Alto %ld \n",scr->width,scr->height);

   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;
{
	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;
int		x,y;
   
/* extracciÆn de parÄmetros necesarios para dibujar. Sobre GC, el contexto grÄfico podrÕamos definir nuestras preferencias, aquÕ tomo uno por defecto */

    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) XDrawLine(dpy,win,gc,px,py,verti[0].x,verti[0].y);
			   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;
     }	
}

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,rutina,(XtPointer)dato);

   XtManageChild(boton);
   XmStringFree(label);

   return(boton);
}

Widget MCreaCascadeButton(padre,str,mnemo,panel)
char	*str,mnemo;
Widget	panel,padre;
{
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);

}
