home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <math.h>
-
- #include <Xm/Xm.h>
- #include <X11/Intrinsic.h>
- #include <Xm/MainW.h>
- #include <Xm/RowColumn.h>
- #include <Xm/PushB.h>
- #include <Xm/Frame.h>
- #include <Xm/LabelG.h>
- #include <Xm/SeparatoG.h>
- #include <Xm/CascadeB.h>
- #include <Xm/SelectioB.h>
- #include <Xm/TextF.h>
-
- #include <X11/cursorfont.h>
-
- #include "XmPgplot.h"
- #include "cpgplot.h"
-
- /* Make the demo backwardly compatible with Motif 1.1 */
-
- #if XmVersion <= 1001
- #ifndef XmFONTLIST_DEFAULT_TAG
- #define XmFONTLIST_DEFAULT_TAG XmSTRING_DEFAULT_CHARSET
- #endif
- #endif
-
- /*
- * Make the demo backwardly compatible with older versions of X.
- */
- #if XtSpecificationRelease <= 4
- #define XtSetLanguageProc(a,b,c) (void)((a),(b),(c))
- #endif
-
- /*
- * Gray-scale images of multiple analytic 2D functions will be supported.
- * Each 2D function will be encapsulated in a C function of the
- * following type.
- */
- #define IMAGE_FN(fn) float (fn)(float x, float y)
- /*
- * Define a macro for prototyping and defining XtCallbackProc functions.
- */
- #define CALL_FN(fn) void (fn)(Widget w, XtPointer client_data, XtPointer call_data)
- /*
- * List the prototypes of the available 2D-function functions.
- */
- static IMAGE_FN(sinc_fn);
- static CALL_FN(sinc_callback);
- static IMAGE_FN(gaus_fn);
- static CALL_FN(gaus_callback);
- static IMAGE_FN(ring_fn);
- static CALL_FN(ring_callback);
- static IMAGE_FN(sin_angle_fn);
- static CALL_FN(sin_angle_callback);
- static IMAGE_FN(cos_radius_fn);
- static CALL_FN(cos_radius_callback);
- static IMAGE_FN(star_fn);
- static CALL_FN(star_callback);
-
- /* Set the default image size */
-
- enum {MAP_SIZE=129};
-
- /* Set the number of points plotted per slice */
-
- enum {SLICE_SIZE=100};
-
- /*
- * Declare a type to hold a single X,Y coordinate.
- */
- typedef struct {
- float x, y; /* World coordinates */
- } Vertex;
-
- /*
- * Declare the object type that will contain the context of the
- * image and slice plots.
- */
- typedef struct {
- Widget w_image; /* The gray-scale image widget */
- Widget w_slice; /* The slice-plot image widget */
- float *image; /* The gray-scale image array */
- float *slice; /* The slice compilation array */
- float scale; /* Coversion factor pixels -> coords */
- int image_size; /* The number of pixels along each side of the image */
- int slice_size; /* The length of the slice array */
- int xa,xb; /* Min and max X pixel coordinates */
- int ya,yb; /* Min and max Y pixel coordinates */
- float datamin; /* The minimum data value in image[] */
- float datamax; /* The maximum data value in image[] */
- IMAGE_FN(*fn); /* The function to be displayed */
- Vertex va; /* The start of the latest slice line */
- Vertex vb; /* The end of the latest slice line */
- Widget w_top; /* The top-level widget of the application */
- Cursor busy; /* The cursor to display when un-responsive */
- } Image;
-
- /*
- * Image object contructor and destructor functions.
- */
- static Image *new_Image(unsigned image_size, unsigned slice_size,
- IMAGE_FN(*fn), Widget parent, Widget w_top);
- static Image *del_Image(Image *im);
-
- /*
- * Image and slice display functions.
- */
- static void display_fn(Image *im, IMAGE_FN(*fn));
- static void display_image(Image *im, int id);
- static void display_slice(Image *im, Vertex *va, Vertex *vb);
- static void display_help(Image *im);
-
- /*
- * The following structure is used to describe menu fields to
- * CreateOptionMenu() and CreatePulldownMenu().
- * Note that title options are denoted by setting callback=NULL,
- * and that separators are specified by setting label=NULL.
- */
- typedef struct {
- char *label; /* The MenuItem label text */
- XtCallbackProc callback; /* Function to be called when field is selected */
- } MenuItem;
-
- static Widget CreateOptionMenu(char *name, char *label, Widget parent, int nopt,
- MenuItem *opts, XtPointer client_data);
- static Widget CreatePulldownMenu(char *name, char *label, Widget parent,
- int nfield, MenuItem *fields,
- XtPointer client_data);
- static Widget CreateMainMenuBar(Image *im, Widget w_main);
- static Widget CreatePopupPromptDialog(Widget w, char *name, char *prompt,
- char *value,
- XtCallbackProc ok_fn, XtPointer ok_data);
-
- static void start_slice_callback(Widget w, XtPointer client_data,
- XtPointer call_data);
- static void end_slice_callback(Widget w, XtPointer client_data,
- XtPointer call_data);
- static CALL_FN(quit_callback);
- static CALL_FN(help_callback);
- static CALL_FN(save_image_as_callback);
- static CALL_FN(save_image_callback);
- static CALL_FN(destroy_widget_callback);
-
- /*.......................................................................
- * A demo program showing an example of how to use PGPLOT with Motif.
- *
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
- int main(int argc, char *argv[])
- {
- XtAppContext app;/* Application context returned by XtVaAppInitialize */
- Widget w_top; /* The top-level widget of the application */
- Widget w_main; /* The geometry management widget of the application */
- Widget w_work; /* The work-area widget of the main window */
- Image *im; /* Image object container */
- /*
- * Initialize Motif.
- */
- XtSetLanguageProc(NULL, NULL, NULL);
- w_top = XtVaAppInitialize(&app, "ImageSlice", NULL, 0,
- #if XtSpecificationRelease <= 4
- (Cardinal *)
- #endif
- &argc, argv, NULL,
- XmNinput, True,
- XmNkeyboardFocusPolicy, XmPOINTER,
- NULL);
- /*
- * Use the standard Motif management widget layout.
- */
- w_main = XtVaCreateManagedWidget("main", xmMainWindowWidgetClass, w_top,
- XmNscrollBarDisplayPolicy, XmAS_NEEDED,
- XmNscrollingPolicy, XmAUTOMATIC,
- XmNheight, 695,
- XmNwidth, 420,
- NULL);
- /*
- * Create a row-column widget to contain the two PGPLOT widgets and
- * an option-menu button.
- */
- w_work = XtVaCreateManagedWidget("work", xmRowColumnWidgetClass, w_main,
- XmNorientation, XmVERTICAL,
- XmNnumColumns, 1,
- NULL);
- /*
- * Install the row-column widget as the work area of the main window.
- */
- XtVaSetValues(w_main, XmNworkWindow, w_work, NULL);
- /*
- * Create the two PGPLOT widgets and the image container object.
- */
- im = new_Image(MAP_SIZE, SLICE_SIZE, ring_fn, w_work, w_top);
- if(!im)
- return 1;
- /*
- * Create the application menu-bar.
- */
- {
- Widget w_bar = CreateMainMenuBar(im, w_main);
- XtManageChild(w_bar);
- };
- /*
- * Display the widgets.
- */
- XtRealizeWidget(w_top);
- /*
- * Open the widgets to PGPLOT.
- */
- if(cpgopen(xmp_device_name(im->w_image)) <= 0 ||
- cpgopen(xmp_device_name(im->w_slice)) <= 0)
- return 1;
- /*
- * Display the initial image.
- */
- display_fn(im, ring_fn);
- /*
- * Interact with the user.
- */
- XtAppMainLoop(app);
- return 0;
- }
-
- /*.......................................................................
- * Allocate and return an initialized Image container object.
- * This function creates two PGPLOT widgets. One will be used to display
- * a gray-scale image. The other will be used to display a slice through
- * the image.
- *
- * Note that the widgets are not opened to PGPLOT and nothing
- * will be displayed until display_fn() is first
- * called. These operations must be postponed until after the widgets have
- * been realized.
- *
- * Input:
- * image_size unsigned The number of pixels along each side of the
- * square image array. This must be an odd
- * number (so that there can be a central pixel).
- * slice_size unsigned The dimension of the slice array (>=2).
- * fn IMAGE_FN(*) The initial display function.
- * parent Widget The widget in which to create the PGPLOT widgets.
- * w_top Widget The top-level widget of the application.
- * Output:
- * return Image * The new image container, or NULL on error.
- */
- static Image *new_Image(unsigned image_size, unsigned slice_size,
- IMAGE_FN(*fn), Widget parent, Widget w_top)
- {
- Image *im; /* The pointer to the container to be returned */
- Widget w_frame; /* A frame widget */
- int i;
- /*
- * Check the arguments.
- */
- if(image_size < 1 || image_size % 2 == 0) {
- fprintf(stderr, "new_Image: Illegal image size requested.\n");
- return NULL;
- };
- if(slice_size < 2) {
- fprintf(stderr, "new_Image: Illegal slice size requested.\n");
- return NULL;
- };
- if(!fn) {
- fprintf(stderr, "new_Image: NULL display function intercepted.\n");
- return NULL;
- };
- /*
- * Allocate the container.
- */
- im = (Image *) malloc(sizeof(Image));
- if(!im) {
- fprintf(stderr, "new_Image: Insufficient memory.\n");
- return NULL;
- };
- /*
- * Before attempting any operation that might fail, initialize the
- * Image container at least up to the point at which it can safely be
- * passed to del_Image().
- */
- im->w_image = NULL;
- im->w_slice = NULL;
- im->image = NULL;
- im->slice = NULL;
- im->image_size = image_size;
- im->slice_size = slice_size;
- im->scale = 40.0f/image_size;
- im->xa = -(int)image_size/2;
- im->xb = image_size/2;
- im->ya = -(int)image_size/2;
- im->yb = image_size/2;
- im->fn = fn;
- im->busy = None;
- im->w_top = w_top;
- /*
- * Now allocate the 2D image array as a 1D array to be indexed in
- * as a FORTRAN array.
- */
- im->image = (float *) malloc(sizeof(float) * image_size * image_size);
- if(!im->image) {
- fprintf(stderr, "new_Image: Insufficient memory.\n");
- return del_Image(im);
- };
- /*
- * Initialize the image array.
- */
- for(i=0; i<image_size*image_size; i++)
- im->image[i] = 0.0f;
- /*
- * Allocate an array to be used when constructing slices through the
- * displayed image.
- */
- im->slice = (float *) malloc(sizeof(float) * slice_size);
- if(!im->slice) {
- fprintf(stderr, "new_Image: Insufficient memory.\n");
- return del_Image(im);
- };
- /*
- * Initialize the slice array.
- */
- for(i=0; i<slice_size; i++)
- im->slice[i] = 0.0f;
- /*
- * Create an etched-in frame widget to provide a border for the
- * image window.
- */
- w_frame = XtVaCreateManagedWidget("image_frame", xmFrameWidgetClass,
- parent,
- XmNshadowType, XmSHADOW_IN,
- NULL);
- /*
- * Create the image-display widget.
- */
- im->w_image = XtVaCreateManagedWidget("image", xmPgplotWidgetClass,
- w_frame,
- XmNheight, 400,
- XmNwidth, 400,
- XmpNmaxColors, 50,
- NULL);
- /*
- * Create a pulldown menu of optional 2-D image functions.
- */
- {
- static MenuItem functions[] = {
- {"Display Functions", NULL}, /* Title */
- {NULL, NULL}, /* Separator */
- {"R=Polar radius", NULL}, /* Label */
- {"A=Polar angle", NULL}, /* Label */
- {NULL, NULL}, /* Separator */
- {"cos(R)sin(A)", ring_callback},
- {"sinc(R)", sinc_callback},
- {"exp(-R^2/20.0)", gaus_callback},
- {"sin(A)", sin_angle_callback},
- {"cos(R)", cos_radius_callback},
- {"(1+sin(6A))exp(-R^2/100)", star_callback},
- };
- Widget menu = CreateOptionMenu("functions", "Select a display function:",
- parent,
- sizeof(functions)/sizeof(functions[0]),
- functions, (XtPointer) im);
- if(menu == NULL)
- return del_Image(im);
- XtManageChild(menu);
- };
- /*
- * Create an etched-in frame widget to provide a border for the
- * slice-plot window.
- */
- w_frame = XtVaCreateManagedWidget("slice_frame", xmFrameWidgetClass,
- parent,
- XmNshadowType, XmSHADOW_IN,
- NULL);
- /*
- * Create the slice-display widget.
- */
- im->w_slice = XtVaCreateManagedWidget("slice", xmPgplotWidgetClass,
- w_frame,
- XmNheight, 200,
- XmNwidth, 400,
- XmpNmaxColors, 16,
- NULL);
- /*
- * Get the standard X busy cursor.
- */
- im->busy = XCreateFontCursor(XtDisplay(im->w_top), XC_watch);
- return im;
- }
-
- /*.......................................................................
- * Delete an Image container previously returned by new_Image().
- *
- * Input:
- * im Image * The container to be deleted (or NULL).
- * Output:
- * return Image * The deleted container (always NULL).
- */
- Image *del_Image(Image *im)
- {
- if(im) {
- if(im->image)
- free(im->image);
- if(im->w_image)
- XtDestroyWidget(im->w_image);
- if(im->w_slice)
- XtDestroyWidget(im->w_slice);
- if(im->busy != None)
- XFreeCursor(XtDisplay(im->w_top), im->busy);
- free(im);
- };
- return NULL;
- }
-
- /*.......................................................................
- * Display a new function in the image window.
- *
- * Input:
- * im Image * The image context object.
- * fn IMAGE_FN(*) The function to be displayed.
- */
- static void display_fn(Image *im, IMAGE_FN(*fn))
- {
- int ix, iy; /* The pixel coordinates being assigned */
- float vmin; /* The minimum pixel value in the image */
- float vmax; /* The maximum pixel value in the image */
- float *pixel;/* A pointer to pixel (ix,iy) in im->image */
- /*
- * Check arguments.
- */
- if(!fn) {
- fprintf(stderr, "display_fn: NULL function.\n");
- return;
- };
- /*
- * Disarm the cursor while the image-plot is incomplete.
- */
- xmp_disarm_cursor(im->w_image);
- /*
- * Install the new function.
- */
- im->fn = fn;
- /*
- * Fill the image array via the current display function.
- */
- pixel = im->image;
- vmin = vmax = im->fn(im->xa * im->scale, im->ya * im->scale);
- for(iy = im->ya; iy <= im->yb; iy++) {
- for(ix = im->xa; ix <= im->xb; ix++) {
- float value = im->fn(ix * im->scale, iy * im->scale);
- *pixel++ = value;
- if(value < vmin)
- vmin = value;
- if(value > vmax)
- vmax = value;
- };
- };
- /*
- * Record the min and max values of the data array.
- */
- im->datamin = vmin;
- im->datamax = vmax;
- /*
- * Display the new image.
- */
- display_image(im, xmp_device_id(im->w_image));
- /*
- * Arm the cursor for user selection of the start position of the
- * first slice line through this image.
- */
- xmp_arm_cursor(im->w_image, XMP_NORM_CURSOR, 0.0f, 0.0f,
- start_slice_callback, im);
- /*
- * Display instructions in the slice window.
- */
- display_help(im);
- return;
- }
-
- /*.......................................................................
- * Display the current image function in a specified PGPLOT device.
- *
- *
- * Input:
- * im Image * The image context object.
- * id int The id of the PGPLOT device to display.
- */
- static void display_image(Image *im, int id)
- {
- /*
- * Since rendering a gray-scale image takes a few seconds
- * display the busy cursor.
- */
- XDefineCursor(XtDisplay(im->w_top), XtWindow(im->w_top), im->busy);
- XFlush(XtDisplay(im->w_top));
- /*
- * Select the specified PGPLOT device and display the image array.
- */
- cpgslct(id);
- cpgask(0);
- cpgpage();
- cpgsch(1.0f);
- cpgvstd();
- cpgwnad(im->xa * im->scale, im->xb * im->scale,
- im->ya * im->scale, im->yb * im->scale);
- {
- float tr[6]; /* Coordinate definition matrix */
- tr[0] = (im->xa - 1) * im->scale;
- tr[1] = im->scale;
- tr[2] = 0.0f;
- tr[3] = (im->ya - 1) * im->scale;
- tr[4] = 0.0f;
- tr[5] = im->scale;
- cpggray(im->image, im->image_size, im->image_size,
- 1, im->image_size, 1, im->image_size, im->datamax, im->datamin, tr);
- };
- cpgbox("BCNST", 0.0f, 0, "BCNST", 0.0f, 0);
- cpglab("X", "Y", "Image display demo");
- /*
- * Revert to the normal X cursor.
- */
- XDefineCursor(XtDisplay(im->w_top), XtWindow(im->w_top), None);
- return;
- }
-
- /*.......................................................................
- * Display a new slice in the slice window.
- *
- * Input:
- * im Image * The image context object.
- * va Vertex * The vertex of one end of the slice line.
- * vb Vertex * The vertex of the opposite end of the slice line.
- */
- static void display_slice(Image *im, Vertex *va, Vertex *vb)
- {
- float xa; /* The start X value of the slice */
- float dx; /* The X-axis world-coordinate width of one slice pixel */
- float ya; /* The start Y value of the slice */
- float dy; /* The Y-axis world-coordinate width of one slice pixel */
- float smin;/* The minimum slice value */
- float smax;/* The maximum slice value */
- float slice_length; /* The world-coordinate length of the slice */
- float ymargin; /* The Y axis margin within the plot */
- int i;
- /*
- * Determine the slice pixel assignments.
- */
- xa = va->x;
- dx = (vb->x - va->x) / im->slice_size;
- ya = va->y;
- dy = (vb->y - va->y) / im->slice_size;
- /*
- * Make sure that the slice has a finite length by setting a
- * minimum size of one pixel.
- */
- {
- float min_delta = im->scale / im->slice_size;
- if(fabs(dx) < min_delta && fabs(dy) < min_delta)
- dx = min_delta;
- };
- /*
- * Construct the slice in im->slice[] and keep a tally of the
- * range of slice values seen.
- */
- for(i=0; i<im->slice_size; i++) {
- float value = im->fn(xa + i * dx, ya + i * dy);
- im->slice[i] = value;
- if(i==0) {
- smin = smax = value;
- } else if(value < smin) {
- smin = value;
- } else if(value > smax) {
- smax = value;
- };
- };
- /*
- * Determine the length of the slice.
- */
- {
- float xlen = dx * im->slice_size;
- float ylen = dy * im->slice_size;
- slice_length = sqrt(xlen * xlen + ylen * ylen);
- };
- /*
- * Determine the extra length to add to the Y axis to prevent the
- * slice plot hitting the top and bottom of the plot.
- */
- ymargin = 0.05 * (im->datamax - im->datamin);
- /*
- * Set up the slice axes.
- */
- cpgslct(xmp_device_id(im->w_slice));
- cpgask(0);
- cpgpage();
- cpgbbuf();
- cpgsch(2.0f);
- cpgvstd();
- cpgswin(0.0f, slice_length, im->datamin - ymargin, im->datamax + ymargin);
- cpgbox("BCNST", 0.0f, 0, "BCNST", 0.0f, 0);
- cpglab("Radius", "Image value", "A 1D slice through the image");
- /*
- * Draw the slice.
- */
- for(i=0; i<im->slice_size; i++) {
- if(i==0)
- cpgmove(0.0f, im->slice[0]);
- else
- cpgdraw(slice_length * (float)i / (float)im->slice_size, im->slice[i]);
- };
- cpgebuf();
- return;
- }
-
- /*.......................................................................
- * Display usage instructions in the slice window.
- *
- * Input:
- * im Image * The image object.
- */
- static void display_help(Image *im)
- {
- /*
- * Clear the slice plot and replace it with instructional text.
- */
- cpgslct(xmp_device_id(im->w_slice));
- cpgask(0);
- cpgpage();
- cpgsch(3.5f);
- cpgsvp(0.0, 1.0, 0.0, 1.0);
- cpgswin(0.0, 1.0, 0.0, 1.0);
- cpgmtxt("T", -2.0, 0.5, 0.5,
- "To see a slice through the image, move the");
- cpgmtxt("T", -3.0, 0.5, 0.5,
- "mouse into the image display window and select");
- cpgmtxt("T", -4.0, 0.5, 0.5,
- " the two end points of a line.");
- }
-
- /*.......................................................................
- * A sinc(radius) function.
- *
- * Input:
- * x,y float The coordinates to evaluate the function at.
- * Output:
- * return float The function value at the specified coordinates.
- */
- static IMAGE_FN(sinc_fn)
- {
- const float tiny = 1.0e-6f;
- float radius = sqrt(x*x + y*y);
- return (fabs(radius) < tiny) ? 1.0f : sin(radius)/radius;
- }
-
- /*.......................................................................
- * Callback to select the sinc_fn() fucntion.
- */
- static CALL_FN(sinc_callback)
- {
- display_fn((Image *) client_data, sinc_fn);
- }
-
- /*.......................................................................
- * A exp(-(x^2+y^2)/20) function.
- *
- * Input:
- * x,y float The coordinates to evaluate the function at.
- * Output:
- * return float The function value at the specified coordinates.
- */
- static IMAGE_FN(gaus_fn)
- {
- return exp(-((x*x)+(y*y))/20.0f);
- }
-
- /*.......................................................................
- * Callback to select the gaus_fn() fucntion.
- */
- static CALL_FN(gaus_callback)
- {
- display_fn((Image *) client_data, gaus_fn);
- }
-
- /*.......................................................................
- * A cos(radius)*sin(angle) function.
- *
- * Input:
- * x,y float The coordinates to evaluate the function at.
- * Output:
- * return float The function value at the specified coordinates.
- */
- static IMAGE_FN(ring_fn)
- {
- return cos(sqrt(x*x + y*y)) * sin(x==0.0f && y==0.0f ? 0.0f : atan2(x,y));
- }
-
- /*.......................................................................
- * Callback to select the ring_fn() fucntion.
- */
- static CALL_FN(ring_callback)
- {
- display_fn((Image *) client_data, ring_fn);
- }
-
- /*.......................................................................
- * A sin(angle) function.
- *
- * Input:
- * x,y float The coordinates to evaluate the function at.
- * Output:
- * return float The function value at the specified coordinates.
- */
- static IMAGE_FN(sin_angle_fn)
- {
- return sin(x==0.0f && y==0.0f ? 0.0f : atan2(x,y));
- }
-
- /*.......................................................................
- * Callback to select the sin_angle_fn() fucntion.
- */
- static CALL_FN(sin_angle_callback)
- {
- display_fn((Image *) client_data, sin_angle_fn);
- }
-
- /*.......................................................................
- * A cos(radius) function.
- *
- * Input:
- * x,y float The coordinates to evaluate the function at.
- * Output:
- * return float The function value at the specified coordinates.
- */
- static IMAGE_FN(cos_radius_fn)
- {
- return cos(sqrt(x*x + y*y));
- }
-
- /*.......................................................................
- * Callback to select the cos_radius_fn() fucntion.
- */
- static CALL_FN(cos_radius_callback)
- {
- display_fn((Image *) client_data, cos_radius_fn);
- }
-
- /*.......................................................................
- * A (1+sin(6*angle))*exp(-radius^2 / 100)function.
- *
- * Input:
- * x,y float The coordinates to evaluate the function at.
- * Output:
- * return float The function value at the specified coordinates.
- */
- static IMAGE_FN(star_fn)
- {
- return (1.0 + sin(x==0.0f && y==0.0f ? 0.0f : 6.0*atan2(x,y)))
- * exp(-((x*x)+(y*y))/100.0f);
- }
-
- /*.......................................................................
- * Callback to select the star_fn() fucntion.
- */
- static CALL_FN(star_callback)
- {
- display_fn((Image *) client_data, star_fn);
- }
-
- /*.......................................................................
- * Create an option menu.
- *
- * Input:
- * name char * The name of the menu.
- * label char * The instructive label to place to the left of
- * the option menu.
- * parent Widget The widget in which to place the option menu.
- * nopt int The number of option fields.
- * opts MenuItem * An array of nopt option fields.
- * client_data XtPointer The client_data argument to be passed to each
- * callback function.
- * Output:
- * return Widget The menu, or NULL on error.
- */
- static Widget CreateOptionMenu(char *name, char *label, Widget parent,
- int nopt, MenuItem *opts, XtPointer client_data)
- {
- Widget w_menu; /* The option menu to be returned */
- Widget w_pulldown; /* The pulldown-menu of the option menu widget */
- int i;
- /*
- * Check arguments.
- */
- if(nopt < 1 || !opts) {
- fprintf(stderr, "CreateOptionMenu: No options.\n");
- return NULL;
- };
- /*
- * Create a pulldown menu.
- */
- w_pulldown = XmCreatePulldownMenu(parent, "pulldown", NULL, 0);
- /*
- * Create the option-menu button to attach the menu to.
- */
- {
- XmString label_str = XmStringCreateSimple(label);
- Arg args[5]; /* Resource arguments for XmCreateOptionMenu() */
- int narg = 0;
- XtSetArg(args[narg], XmNsubMenuId, w_pulldown); narg++;
- XtSetArg(args[narg], XmNlabelString, label_str); narg++;
- w_menu = XmCreateOptionMenu(parent, name, args, narg);
- XmStringFree(label_str);
- };
- /*
- * Install the option fields.
- */
- for(i=0; i<nopt; i++) {
- MenuItem *opt = opts + i;
- if(opt->label) {
- /*
- * Add an option field.
- */
- if(opt->callback) {
- Widget widget = XtVaCreateManagedWidget(opt->label,
- xmPushButtonWidgetClass, w_pulldown, NULL);
- XtAddCallback(widget, XmNactivateCallback, opt->callback, client_data);
- /*
- * Add a title widget.
- */
- } else {
- Widget widget = XtVaCreateManagedWidget(opt->label,
- xmLabelGadgetClass, w_pulldown,
- XmNalignment, XmALIGNMENT_BEGINNING,
- NULL);
- };
- /*
- * Add a separator widget.
- */
- } else {
- XtVaCreateManagedWidget("separator", xmSeparatorGadgetClass, w_pulldown,
- NULL);
- };
- };
- return w_menu;
- }
-
- /*.......................................................................
- * Create a pulldown menu.
- *
- * Input:
- * name char * The name of the menu.
- * label char * The label for the menubar button.
- * parent Widget The widget in which to place the pulldown menu.
- * nfield int The number of menu fields.
- * fields MenuItem * An array of nfield menu fields.
- * client_data XtPointer The client_data argument to be passed to each
- * callback function.
- * Output:
- * return Widget The cascade button of the menu, or NULL on error.
- */
- static Widget CreatePulldownMenu(char *name, char *label, Widget parent,
- int nfield, MenuItem *fields,
- XtPointer client_data)
- {
- Widget w_pulldown; /* The pulldown-menu */
- Widget w_cascade; /* The cascade button to be returned */
- int i;
- /*
- * Check arguments.
- */
- if(nfield < 1 || !fields) {
- fprintf(stderr, "CreatePulldownMenu: No fields.\n");
- return NULL;
- };
- /*
- * Create a pulldown menu.
- */
- w_pulldown = XmCreatePulldownMenu(parent, "pulldown", NULL, 0);
- /*
- * Create the cascade button that invokes the menu.
- */
- {
- XmString label_str = XmStringCreateSimple(label);
- w_cascade = XtVaCreateManagedWidget(name,
- xmCascadeButtonWidgetClass, parent,
- XmNsubMenuId, w_pulldown,
- XmNlabelString, label_str,
- NULL);
- XmStringFree(label_str);
- };
- /*
- * Install the menu fields.
- */
- for(i=0; i<nfield; i++) {
- MenuItem *field = fields + i;
- if(field->label) {
- /*
- * Add a button widget.
- */
- if(field->callback) {
- Widget widget = XtVaCreateManagedWidget(field->label,
- xmPushButtonWidgetClass, w_pulldown, NULL);
- XtAddCallback(widget, XmNactivateCallback, field->callback,
- client_data);
- /*
- * Add a title widget.
- */
- } else {
- Widget widget = XtVaCreateManagedWidget(field->label,
- xmLabelGadgetClass, w_pulldown,
- XmNalignment, XmALIGNMENT_BEGINNING,
- NULL);
- };
- /*
- * Add a separator widget.
- */
- } else {
- XtVaCreateManagedWidget("separator", xmSeparatorGadgetClass, w_pulldown,
- NULL);
- };
- };
- return w_cascade;
- }
-
- /*.......................................................................
- * This callback is called when the user selects the start position
- * of a slice line.
- *
- * Input:
- * Widget widget The PGPLOT widget that had a cursor event.
- * client_data XtPointer The optional client data pointer passed to
- * xmp_arm_cursor().
- * call_data XtPointer The pointer to the context of the event
- * as a (XmpCursorCallbackStruct *) cast to
- * (XtPointer).
- */
- static void start_slice_callback(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- XmpCursorCallbackStruct *cursor = (XmpCursorCallbackStruct *) call_data;
- Image *im = (Image *) client_data;
- im->va.x = cursor->x;
- im->va.y = cursor->y;
- /*
- * Display a line-oriented rubber-band cursor to get the end vertex of the
- * line.
- */
- cpgslct(xmp_device_id(im->w_image));
- xmp_arm_cursor(im->w_image, XMP_LINE_CURSOR, im->va.x, im->va.y,
- end_slice_callback, im);
- }
-
- /*.......................................................................
- * This callback is called when the user selects the end position
- * of a slice line.
- *
- * Input:
- * Widget widget The PGPLOT widget that had a cursor event.
- * client_data XtPointer The optional client data pointer passed to
- * xmp_arm_cursor().
- * call_data XtPointer The pointer to the context of the event
- * as a (XmpCursorCallbackStruct *) cast to
- * (XtPointer).
- */
- static void end_slice_callback(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- XmpCursorCallbackStruct *cursor = (XmpCursorCallbackStruct *) call_data;
- Image *im = (Image *) client_data;
- im->vb.x = cursor->x;
- im->vb.y = cursor->y;
- /*
- * Re-arm the cursor for the start of the next line.
- */
- xmp_arm_cursor(im->w_image, XMP_NORM_CURSOR, 0.0f, 0.0f,
- start_slice_callback, im);
- /*
- * Draw the slice wrt the new line.
- */
- display_slice(im, &im->va, &im->vb);
- }
-
- /*.......................................................................
- * Create the menu bar of the application.
- *
- * Input:
- * im Image * The image object of the application.
- * w_main Widget The main widget of the application.
- * Output:
- * return Widget The menu-bar widget or NULL on error.
- */
- static Widget CreateMainMenuBar(Image *im, Widget w_main)
- {
- Widget w_bar; /* The menu-bar widget */
- /*
- * Create the menu bar with File and Help menus.
- */
- w_bar = XmCreateMenuBar(w_main, "menubar", NULL, 0);
- /*
- * Install the File menu.
- */
- {
- static MenuItem file_fields[] = {
- {"Save image as", save_image_as_callback},
- {NULL, NULL}, /* Separator */
- {"Quit", quit_callback}
- };
- CreatePulldownMenu("file_menu", "File", w_bar,
- sizeof(file_fields)/sizeof(file_fields[0]),
- file_fields, (XtPointer) im);
- };
- /*
- * Install the Help menu.
- */
- {
- static MenuItem help_fields[] = {
- {"Usage", help_callback}
- };
- Widget w_help = CreatePulldownMenu("help_menu", "Help", w_bar,
- sizeof(help_fields)/sizeof(help_fields[0]),
- help_fields, (XtPointer) im);
- XtVaSetValues(w_bar, XmNmenuHelpWidget, w_help, NULL);
- };
- return w_bar;
- }
-
- /*.......................................................................
- * The file-menu "Quit" callback function.
- */
- static CALL_FN(quit_callback)
- {
- exit(0);
- }
-
- /*.......................................................................
- * The help-menu callback function.
- */
- static CALL_FN(help_callback)
- {
- Image *im = (Image *) client_data;
- display_help(im);
- }
-
- /*.......................................................................
- * The File-menu "save image as" callback.
- */
- static CALL_FN(save_image_as_callback)
- {
- Image *im = (Image *) client_data;
- Widget w_dialog = CreatePopupPromptDialog(w, "device",
- "Enter a PGPLOT device string:",
- "image.ps/vps",
- save_image_callback, (XtPointer) im);
- /*
- * Add a null translation for the letter '?'. This prevents users from
- * enterring a PGPLOT '?' query string.
- */
- {
- char *bindings ="s <Key>\?:";
- XtTranslations translations = XtParseTranslationTable(bindings);
- XtOverrideTranslations(XmSelectionBoxGetChild(w_dialog, XmDIALOG_TEXT),
- translations);
- };
- /*
- * Display the dialog.
- */
- XtManageChild(w_dialog);
- XtPopup(XtParent(w_dialog), XtGrabNone);
- }
-
- /*.......................................................................
- * The callback for the dialog created by save_image_as_callback().
- */
- static CALL_FN(save_image_callback)
- {
- int device_id; /* The PGPLOT ID of the new PGPLOT device */
- Image *im = (Image *) client_data;
- XmSelectionBoxCallbackStruct *sel =
- (XmSelectionBoxCallbackStruct *) call_data;
- /*
- * Translate the device specification into a normal C string.
- */
- {
- char *device = NULL;
- if(XmStringGetLtoR(sel->value, XmFONTLIST_DEFAULT_TAG, &device)) {
- /*
- * Open the specified device.
- */
- device_id = cpgopen(device);
- XtFree(device);
- if(device_id > 0) {
- display_image(im, device_id);
- cpgclos();
- };
- }
- };
- /*
- * Discard the popup widget.
- */
- XtDestroyWidget(w);
- return;
- }
-
- /*.......................................................................
- * Create a popup prompt-dialog with a specified prompt and initial value.
- *
- * Input:
- * w Widget The widget of the button that invoked the dialog.
- * name char * The name to give the popup. Note that
- * XmCreatePromptDialog() appends _prompt to this.
- * prompt char * The dialog prompt string.
- * value char * The initial value to display, or NULL.
- * ok_fn XtCallbackProc The callback function for the OK button.
- * ok_data XtPointer The callback client_data argument.
- * Output:
- * return Widget The dialog widget.
- */
- static Widget CreatePopupPromptDialog(Widget w, char *name, char *prompt,
- char *value,
- XtCallbackProc ok_fn, XtPointer ok_data)
- {
- Widget w_dialog; /* The dialog widget to be returned */
- /*
- * Create the dialog.
- */
- {
- XmString prompt_str = XmStringCreateSimple(prompt);
- Arg args[5];
- int n = 0;
- XtSetArg(args[n], XmNselectionLabelString, prompt_str); n++;
- XtSetArg(args[n], XmNautoUnmanage, False); n++;
- w_dialog = XmCreatePromptDialog(w, name, args, n);
- XmStringFree(prompt_str);
- };
- /*
- * Arrange to ignore the Cancel button.
- */
- XtAddCallback(w_dialog, XmNcancelCallback, destroy_widget_callback, NULL);
- /*
- * Install the provided Ok callback and its client_data.
- */
- if(ok_fn)
- XtAddCallback(w_dialog, XmNokCallback, ok_fn, ok_data);
- /*
- * De-sensitize the Help button.
- */
- XtSetSensitive(XmSelectionBoxGetChild(w_dialog, XmDIALOG_HELP_BUTTON), False);
- /*
- * Install the initial text-field value.
- */
- if(value) {
- XtVaSetValues(XmSelectionBoxGetChild(w_dialog, XmDIALOG_TEXT),
- XmNvalue, value,
- XmNcursorPosition, (XmTextPosition) strlen(value),
- NULL);
- };
- /*
- * Add emacs-like keybindings.
- */
- {
- char *bindings ="\
- c <Key>a: beginning-of-line()\n\
- c <Key>e: end-of-line()\n\
- c <Key>b: backward-character()\n\
- c <Key>f: forward-character()\n\
- c <Key>u: select-all() delete-selection()\n\
- c <Key>d: delete-next-character()\
- ";
- XtTranslations translations = XtParseTranslationTable(bindings);
- XtOverrideTranslations(XmSelectionBoxGetChild(w_dialog, XmDIALOG_TEXT),
- translations);
- };
- return w_dialog;
- }
-
- /*.......................................................................
- * A callback that destroys its widget.
- */
- static CALL_FN(destroy_widget_callback)
- {
- XtDestroyWidget(w);
- }
-