/* $XConsortium: xmanimate.c /main/5 1995/07/15 20:44:58 drk $ */
/*
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 * 
 */
/*
 * HISTORY
 */
/***************************************************************************
* Motifanim.
* ---------
* This program displays a animation made of a succession of pixmaps drawn
*    side by side in a scrolled drawingarea; there are also control 
*    buttons for managing the animation (start, speed, stop, step ...)
* This program reads two uid files: 'motifanim.uid', describing the general
*    interface of the buttons, label etc, and a <NAME>.uid file, describing
*    the data for the animation itself (essentially a set of icons to
*    be read using MrmFetchIconLiteral. <NAME> can be set at run time
*    in the command line and is supposed to define the following value:
*         anim_width     : width of the drawing area receiving animation
*         anim_height    : height of the drawing area receiving animation
*         anim_number    : number of icons in the animation (N)
*         <NAME>icon<N>  : name of the icon pixmap, for instance 'dogicon1'
*         anim_backcolor : color of the drawing area receiving animation
*         anim_step      : horizontal offset added before each animation step
* See dog.uil, the default <NAME>, for an example of such a file.
* -----------------------------------
* Authors: Daniel Dardailler, 90 (this version - last updated 94)
*          Vincent Bouthors,  89 (Egerie version)
*          Daniel Dardailler, 88 (xdog version)
****************************************************************************/

#include <stdio.h>
#include <Xm/Xm.h>          /* Motif Toolkit */
#include <Xm/Scale.h>
#include <Mrm/MrmPublic.h>   /* Mrm */
#include <Xmd/RegEdit.h>   
#include <Xmd/Help.h>   
#include <stdlib.h>

static MrmHierarchy	s_MrmHierarchy;	   /* MRM database hierarch id */

static char *vec[2]={"xmanimate.uid"};     /* MRM database file list   */
static int vecnum = sizeof(vec) / sizeof(char*);
       /* the second uid file name (vec[1]), containing animation
	  data, is taken at run time in command line option -anim */

static MrmCode		class, return_type ;

       /* forward declaration of interface procedures */
static void p_motifanim_start();
static void p_motifanim_stop();
static void p_motifanim_step();
static void p_motifanim_speed();
static void p_motifanim_draw();
static void p_motifanim_exit();
static void p_motifanim_help();
static void InitAnim();

       /* binding of uil procedure names with C functions */
static MRMRegisterArg	regvec[] = {
	{"p_motifanim_start",(XtPointer)p_motifanim_start},
	{"p_motifanim_stop",(XtPointer)p_motifanim_stop},
	{"p_motifanim_step",(XtPointer)p_motifanim_step},
	{"p_motifanim_speed",(XtPointer)p_motifanim_speed},
	{"p_motifanim_exit",(XtPointer)p_motifanim_exit},
	{"p_motifanim_draw",(XtPointer)p_motifanim_draw},
	{"p_motifanim_help",(XtPointer)p_motifanim_help}
	};
static MrmCount regnum = XtNumber(regvec);


static Display 	*display;
static XtAppContext    app_context;

/** 
--  Animation variables 
**/
static int scalespeed, max_scale ; /* init with widget values */
static short width ;

static Boolean stop = True ;

static int xanim = 50,
           yanim = 25,
           ianim = 0 ;

static int speed_factor = 20 ;                /* reinitialized with argv */
static char * anim_name = "dog";              /* reinitialized with argv */

#define MAXIMAGES 10
static unsigned int wanim[MAXIMAGES], hanim[MAXIMAGES] ;

static Pixmap panim[MAXIMAGES] ;   /* initalized with uil value by fetching */
static int nimage, step_size  ;    /* initalized with uil value by fetching */

static GC gc ;
static Widget drawingArea;
static int speedcount ;

#define APP_CLASS "XmdAnimate"

static String fallbacks[] = {
"*help_manager.helpFile: xmanimate",
NULL
};

/******************************************************************
 *  Main program: motifanim [-anim anim_name] [-speed speed_factor]
 */
int main(argc, argv)
     int    argc;
     String argv[];
{
     /*
     *  Declare the variables to contain the two widget ids
     */
    Widget toplevel, motifanimmain = NULL ;
    Arg arglist[1] ;
    char uidanimfile[100] ;
    int n;


    MrmInitialize ();
    XtSetLanguageProc(NULL, NULL, NULL);
    toplevel = XtVaOpenApplication(&app_context, APP_CLASS,
				 NULL , 0, &argc, argv, fallbacks, 
                                 sessionShellWidgetClass, 
                                 NULL);

    /**  Plug in Editres protocol  */
    XmdRegisterEditres(toplevel);

    /*
     *  Parsing of the remaining animation options
     */

    while (*++argv) {
	if (!strcmp(*argv,"-anim")) {
	    if (*++argv)  anim_name = *argv ; 
	} else
	if (!strcmp(*argv,"-speed")) {
	    if (*++argv)  speed_factor = atoi(*argv) ; 
	}
    }
		

    /*
     *  Build the secong uid file and open the Mrm.hierarchy (2 files)
     */ 
    strcpy(uidanimfile,anim_name);
    strcat(uidanimfile,".uid");
    vec[1] = uidanimfile ;
    if (MrmOpenHierarchy (vecnum,	 /* number of files	    */
			vec, 		 /* files     	    */
			NULL,		 /* os_ext_list (null)   */
			&s_MrmHierarchy) /* ptr to returned id   */
			!= MrmSUCCESS) {
	printf ("can't open hierarchy defined by %s and %s\n",vec[0],vec[1]);
	exit(0);
     }

    if (MrmRegisterNames (regvec, regnum)
			!= MrmSUCCESS) {
	printf("can't register names\n");
	exit(0) ;
    }

    if (MrmFetchWidget (s_MrmHierarchy,
			"motifanim_main",
			toplevel,
			&motifanimmain,
			&class)
			!= MrmSUCCESS) {
	printf("can't fetch interface\n");
	exit(0);
    }

    XtManageChild(motifanimmain);
    
    XtRealizeWidget(toplevel);

    /*
     *  Call the routine that will fetch the animation variables.
     */
    
    InitAnim() ;


    XtAppMainLoop(app_context);

    /* UNREACHABLE */
    return (0);
}


static void InitAnim()
/********/
{

    XGCValues gcv;
    int i,dum ;
    char uiliconname[100];
    int * pint ;
    Window wdum ;

    /* fetch the number of animation icons from Mrm hierarchy */
    if (MrmFetchLiteral(s_MrmHierarchy,
			"anim_number",
			XtDisplay(drawingArea),
			(XtPointer *)&pint,
			&return_type) != MrmSUCCESS) {
	printf("Can't fetch literal anim_number in %s.uid\n",anim_name);
	exit(0) ;
    }

    nimage = (*pint > MAXIMAGES)?(MAXIMAGES-1):(*pint-1);

    /* fetch the step value from Mrm hierarchy */
    if (MrmFetchLiteral(s_MrmHierarchy,
			"anim_step",
			XtDisplay(drawingArea),
			(XtPointer *)&pint,
			&return_type) != MrmSUCCESS) {
	printf("Can't fetch literal anim_step in %s.uid\n",anim_name);
	exit(0) ;
    }

    step_size = *pint ;

    /* fetch the icon pixmaps from Mrm hierarchy */
    for (i = 0 ; i <= nimage ; i++) {
	sprintf(uiliconname, "%sicon%d",anim_name, i+1);
	if (MrmFetchIconLiteral(s_MrmHierarchy,
			uiliconname,
			XtScreen(drawingArea),
			XtDisplay(drawingArea),
			BlackPixel(XtDisplay(drawingArea),
				   DefaultScreen(XtDisplay(drawingArea))),
			WhitePixel(XtDisplay(drawingArea),
				   DefaultScreen(XtDisplay(drawingArea))),
			&panim[i]) != MrmSUCCESS) {
	    fprintf(stderr, "Can't fetch uiliconname %s\n", uiliconname);
	    exit (-1);
	}
	/* get the icons geometry with X standard requests */
	XGetGeometry(XtDisplay(drawingArea),panim[i],&wdum,
		     &dum,&dum,&wanim[i],&hanim[i],
		     (unsigned int*)&dum,(unsigned int*)&dum);
    }

    /* to avoid event accumulation during animation */
    gcv.graphics_exposures = False ; 
    gc = XCreateGC(XtDisplay(drawingArea), XtWindow(drawingArea), 
		   GCGraphicsExposures, &gcv);
    speedcount = 0 ;
}



/**
  Background Work Procedure: it return the current value of stop
  and then is automatically removed when stop = true.
**/
static Boolean fstep(client_data)
/************************/
     XtPointer client_data ;       /* scalespeed */
{
    speedcount += (int)*(int*)client_data ;
    if (speedcount >= (max_scale*speed_factor)) {
	speedcount = 0 ;
	XClearArea(XtDisplay(drawingArea), XtWindow(drawingArea),
		   xanim, yanim, wanim[ianim], hanim[ianim] , False);
	xanim = (xanim > width)?(-wanim[ianim]):(xanim+step_size) ;
	ianim = (ianim == nimage)?0:(ianim+1);
	XCopyArea(XtDisplay(drawingArea), panim[ianim], XtWindow(drawingArea),
		  gc, 0, 0, wanim[ianim], hanim[ianim], 
		  xanim, yanim);
	XSync(XtDisplay(drawingArea),False);
    }
    return stop ;
}

/** The callbacks **/
/*******************/

static void 
p_motifanim_help (Widget w, XtPointer client_data, XtPointer call_data) 
{
    static Widget help_widget = NULL ;

    if (!help_widget)
	help_widget = XmdCreateHelpDialog(w, "help_manager", NULL, 0);

    XtManageChild(help_widget);   
}


static void p_motifanim_start( widget, tag, callback_data )
	Widget	widget;
	char    *tag;
	XmAnyCallbackStruct *callback_data;
{
    XtAppAddWorkProc(app_context,fstep, (XtPointer)&scalespeed);
    stop = False ;
}

static void p_motifanim_stop( widget, tag, callback_data )
	Widget	widget;
	char    *tag;
	XmAnyCallbackStruct *callback_data;
{
    stop = True ;
}

static void p_motifanim_step( widget, tag, callback_data )
	Widget	widget;
	char    *tag;
	XmAnyCallbackStruct *callback_data;
{
    int max = (max_scale*speed_factor) ;

    fstep(&max) ;
}

static void p_motifanim_speed( widget, tag, callback_data )
	Widget	widget;
	int    *tag;
	XmScaleCallbackStruct *callback_data;
{
    Arg arg ;

    if (*tag == 0) {
	XmScaleGetValue(widget,&scalespeed);
	XtSetArg(arg,XmNmaximum,&max_scale);
	XtGetValues(widget,&arg,1);
    }
    else scalespeed = callback_data->value ;
}

static void p_motifanim_draw( widget, tag, callback_data )
	Widget	widget;
	int    *tag;
	XmAnyCallbackStruct *callback_data;
{
    Arg arg ;

    if (*tag == 0) {
	XtSetArg(arg,XmNwidth,&width);
	XtGetValues(widget,&arg,1);
	drawingArea = widget ; 
    } else {
	XCopyArea(XtDisplay(drawingArea), panim[ianim], 
		  XtWindow(drawingArea),
		  gc, 0, 0, wanim[ianim], hanim[ianim], 
		  xanim, yanim);
    }

}

static void p_motifanim_exit( widget, tag, callback_data )
	Widget	widget;
	char    *tag;
	XmAnyCallbackStruct *callback_data;
{
    exit(0);
}
