/* 
 * 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
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: DNDDraw.c /main/7 1997/03/31 13:33:37 dbl $"
#endif
#endif
/*
 *    file: DNDDraw.c
 *
 *	File containing all the drawing routines needed to run DNDDemo
 *	program.
 *
 */

#include "DNDDemo.h"
static void	RectDraw(Display *, Window , RectPtr );


/* The following character arrays hold the bits for
 * the source and state icons for both 32x32 and 16x16 drag icons.
 * The source is a color palette icon and the state is a paint brush icon.
 */
unsigned char SOURCE_ICON_BITS[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x02,
    0x00, 0x50, 0x55, 0x07, 0x00, 0x28, 0x00, 0x0c, 0x00, 0x94, 0x42, 0x19,
    0x00, 0xca, 0xe5, 0x33, 0x00, 0x85, 0xc6, 0x33, 0x80, 0x42, 0xe7, 0x33,
    0x40, 0x81, 0xc3, 0x31, 0xa0, 0x00, 0x00, 0x38, 0x50, 0x00, 0x00, 0x1c,
    0x28, 0x00, 0x00, 0x0e, 0x90, 0x02, 0x00, 0x07, 0xc8, 0x05, 0x80, 0x03,
    0x90, 0x07, 0xc0, 0x01, 0x48, 0x05, 0xe0, 0x00, 0x90, 0x03, 0x70, 0x00,
    0x08, 0x00, 0x30, 0x00, 0x10, 0x14, 0x30, 0x00, 0x08, 0x2a, 0x30, 0x00,
    0x10, 0x34, 0x30, 0x00, 0x28, 0x2a, 0x60, 0x00, 0x50, 0x9c, 0xe2, 0x00,
    0xa0, 0x40, 0xc4, 0x01, 0x40, 0x01, 0x84, 0x01, 0x80, 0x42, 0x84, 0x03,
    0x00, 0x85, 0x03, 0x03, 0x00, 0x0a, 0x00, 0x03, 0x00, 0xf4, 0xff, 0x03,
    0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00};

unsigned char SOURCE_ICON_MASK[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x0f,
    0x00, 0xfc, 0xff, 0x1f, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x7f,
    0x80, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f,
    0xf0, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f,
    0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x0f,
    0xfc, 0xff, 0xff, 0x07, 0xfc, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0x01,
    0xfc, 0xff, 0xff, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00,
    0xfc, 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0x03,
    0xf8, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
    0xc0, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07,
    0x00, 0xfe, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x03};

unsigned char STATE_ICON_BITS[] = {
    0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
    0xf8, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00,
    0xf0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xc0, 0x0d, 0x00, 0x00,
    0x00, 0x1b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
    0x00, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00,
    0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00,
    0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfc, 0x00,
    0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xe0, 0x03,
    0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x1f,
    0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x38,
    0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xc0};

unsigned char STATE_ICON_MASK[] = {
    0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00,
    0xfc, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00,
    0xfc, 0x07, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00,
    0xe0, 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
    0x00, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00,
    0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00,
    0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfc, 0x03,
    0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
    0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x7f,
    0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe,
    0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf0};

unsigned char INVALID_ICON_BITS[] = {
    0x00, 0xe0, 0x0f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x01,
    0x80, 0xff, 0xff, 0x03, 0xc0, 0x1f, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x0f,
    0xf0, 0x07, 0x00, 0x1f, 0xf8, 0x0f, 0x00, 0x3e, 0xf8, 0x1f, 0x00, 0x3c,
    0xfc, 0x3f, 0x00, 0x7c, 0x3c, 0x7f, 0x00, 0x78, 0x3c, 0xfe, 0x00, 0x78,
    0x1e, 0xfc, 0x01, 0xf0, 0x1e, 0xf8, 0x03, 0xf0, 0x1e, 0xf0, 0x07, 0xf0,
    0x1e, 0xe0, 0x0f, 0xf0, 0x1e, 0xc0, 0x1f, 0xf0, 0x1e, 0x80, 0x3f, 0xf0,
    0x1e, 0x00, 0x7f, 0xf0, 0x3c, 0x00, 0xfe, 0x78, 0x3c, 0x00, 0xfc, 0x79,
    0x7c, 0x00, 0xf8, 0x7f, 0x78, 0x00, 0xf0, 0x3f, 0xf8, 0x00, 0xe0, 0x3f,
    0xf0, 0x01, 0xc0, 0x1f, 0xe0, 0x07, 0xc0, 0x0f, 0xc0, 0x1f, 0xf0, 0x07,
    0x80, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfc, 0x7f, 0x00,
    0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00};

unsigned char SMALL_SOURCE_ICON_BITS[] = {
    0x80, 0x1f, 0x40, 0x60, 0x20, 0x91, 0x90, 0xaa, 0x08, 0x91, 0x08, 0x40,
    0x08, 0x20, 0x08, 0x10, 0x28, 0x10, 0x78, 0x10, 0x28, 0x20, 0x08, 0x41,
    0x90, 0x43, 0x20, 0x21, 0x40, 0x10, 0x80, 0x0f};

unsigned char SMALL_SOURCE_ICON_MASK[] = {
    0x80, 0x1f, 0xc0, 0x7f, 0xe0, 0xff, 0xf0, 0xff, 0xf8, 0xff, 0xf8, 0x7f,
    0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x3f, 0xf8, 0x7f,
    0xf0, 0x7f, 0xe0, 0x3f, 0xc0, 0x1f, 0x80, 0x0f};

unsigned char SMALL_STATE_ICON_BITS[] = {
    0x0f, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x50, 0x00, 0xe0, 0x00,
    0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x18,
    0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00};

unsigned char SMALL_STATE_ICON_MASK[] = {
    0x0f, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x70, 0x00, 0xe0, 0x00,
    0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x18,
    0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00};

unsigned char SMALL_INVALID_ICON_BITS[] = {
    0xe0, 0x03, 0xf8, 0x0f, 0x1c, 0x1c, 0x1e, 0x30, 0x3e, 0x30, 0x73, 0x60,
    0xe3, 0x60, 0xc3, 0x61, 0x83, 0x63, 0x03, 0x67, 0x06, 0x3e, 0x06, 0x3c,
    0x1c, 0x1c, 0xf8, 0x0f, 0xe0, 0x03, 0x00, 0x00};


/* Globals variables */
AppInfo appInfo;


/* This is a string to pixel conversion function. */
Pixel 
GetColor(char *colorstr)
{

    XrmValue    from, to;

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

    if (to.addr != NULL)
        return ((Pixel) *((Pixel *) to.addr));
    else
        return ( (XtArgVal) NULL);

}


/* This procedure is used to initalize the application information structure */
void
InitializeAppInfo(void)
{

    if (!appInfo) {

        appInfo = (AppInfo) XtMalloc(sizeof(AppInfoRec));
        appInfo->rectGC = NULL;
        appInfo->currentColor = 0;
        appInfo->rectDpyTable = NULL;
        appInfo->rectsAllocd = 0;
        appInfo->numRects = 0;
        appInfo->highlightRect = NULL;
        appInfo->clearRect = NULL;
        appInfo->doMove = True;
        appInfo->creatingRect = True;
        appInfo->operation = XmDROP_MOVE;
        appInfo->maxCursorWidth = 64;
        appInfo->maxCursorHeight = 64;
        appInfo->rectX = 0;
        appInfo->rectY = 0;
        appInfo->rectX2 = 0;
        appInfo->rectY2 = 0;

    }

}


/* This procedure sets the color in the GC for drawing the rectangles
 * in a new color.
 */
void
SetColor(Display *display, Pixel color)
{

    /*
     * if the GC already has a foreground of this color,
     * it would be wasteful to reset the color
     */
    if (color != appInfo->currentColor) {
        XSetForeground(display, appInfo->rectGC, (unsigned long) color);
        appInfo->currentColor = color;
    }

}


/* This function draws the rectangle in the color provided */
static void
RectDraw(Display *display, Window window, RectPtr rect)
{

    SetColor(display, rect->color);
    XFillRectangle(display, window, appInfo->rectGC, rect->x,
                   rect->y, rect->width, rect->height);

}


/* This procedure draws the rectangle highlight in a specified color*/
static void
RectDrawHighlight( Widget w, RectPtr rect, Pixel color )
{

    Display *display = XtDisplay(w);
    Window window = XtWindow(w);
    Pixel currentColor = rect->color;
    XGCValues values;

    values.foreground = color;
    XChangeGC(display, appInfo->rectGC, GCForeground, &values);

    XDrawRectangle(display, window, appInfo->rectGC,
                   rect->x + 1, rect->y + 1,
                   rect->width - HIGHLIGHT_THICKNESS,
                   rect->height - HIGHLIGHT_THICKNESS);

    /* Return the GC to it's previous state */
    values.foreground = appInfo->currentColor = currentColor;
    XChangeGC(display, appInfo->rectGC, GCForeground, &values);

}


/* This procedure handles redrawing the rectangles.  It draws
 * them according to the order in the rectangle display table.
 * The rectangles at the top of the table are drawn first.
 */
void
RedrawRectangles(Widget w)
{

    Display *display = XtDisplay(w);
    RectPtr rect;
    Window window = XtWindow(w);
    int i;

    for (i = 0; i < appInfo->numRects; i++) {

        rect = appInfo->rectDpyTable[i];
        /* Only draw the rectangles that haven't been cleared */
        if (rect != appInfo->clearRect) {
            RectDraw(display, window, rect);
        }
        /* Draw the rectangle highlight of the highlight rectangle */
        if (rect == appInfo->highlightRect) {
            RectDrawHighlight(w, rect, GetColor(HIGHLIGHT_COLOR));
        }

    }

}


/* This procedure will clear the current rectangle and redraw any rectangles
 * that were partially cleared by the rectangle that was deleted.
 */
/* ARGSUSED */
void
RectHide(Display *display, Window window, RectPtr rect)
{

    Pixel background, oldColor;
    Arg args[1];

    /* Get the background of the drawing area. */
    XtSetArg(args[0], XmNbackground, &background);
    XtGetValues(drawingArea, args, 1);

    /* Save the old color for restoration purposes. */
    oldColor = rect->color;

    /* Clear the rectangle */
    rect->color = background;
    RectDraw(display, window, rect);
    appInfo->clearRect = rect;

    /* redraw the rest of the rectangles */
    RedrawRectangles(drawingArea);

    /* restore the rectangle color */
    rect->color = oldColor;

}

/* This procedure draws the stipple rectangle that is used in marking
 * the old rectangle position during a rectangle move operation.
 */
/* ARGSUSED */
void
RectDrawStippled(Display *display, Window window, RectPtr rect)
{

    register int x = rect->x;
    register int y = rect->y;
    register Dimension width = rect->width;
    register Dimension height = rect->height;
    XGCValues values;
    XSegment segments[4];

    /* Set the rectangle color */
    values.foreground = appInfo->currentColor = rect->color;
    XChangeGC(display, appInfo->rectGC, GCForeground , &values);

    /* Create the segments for drawing the stippled rectangle */
    segments[0].x1 = segments[2].x1 = x;
    segments[0].y1 = segments[0].y2 = y;
    segments[0].x2 = x + width - 1;
    segments[1].x1 = segments[1].x2 = x + width - 1;
    segments[1].y1 = segments[3].y1 = y;
    segments[3].y2 = y + height;
    segments[2].y1 = segments[2].y2 = y + height - 1;
    segments[3].x1 = segments[3].x2 = x;
    segments[2].x2 = x + width;
    segments[1].y2 = y + height;

    /* Set the line attributes and draw */
    XSetLineAttributes(display, appInfo->rectGC, 1, LineOnOffDash,
        CapButt, JoinMiter);
    XDrawSegments (display, window, appInfo->rectGC, segments, 4);

    /* restore the default line settings */
    values.line_width = HIGHLIGHT_THICKNESS;
    values.line_style = LineSolid;
    XChangeGC(display, appInfo->rectGC, GCLineWidth | GCLineStyle, &values);

}


/* This procedure sets the highlight rectangle and
 * redraws the rectangles.  The expose routine will draw
 * the highlight around the highlighted rectangle.
 */
/* ARGSUSED */
void
RectHighlight(Widget w, RectPtr rect)
{

    if (appInfo->highlightRect != rect) {
        appInfo->highlightRect = rect;
        RedrawRectangles(w);
    }

}

/* This procedure sets the highlight rectangle to NULL and
 * redraws the rectangles.  The expose routine will clear
 * the highlight around the highlighted rectangle.
 */
/* ARGSUSED */
void
RectUnhighlight(Widget w)
{

    if (appInfo->highlightRect) {
        appInfo->highlightRect = NULL;
        RedrawRectangles(w);
    }

}

/* This function creates and initialized a new rectangle */
RectPtr 
RectCreate(Position x, Position y, Dimension width,
Dimension height, Pixel color, Pixmap pixmap)
{

    RectPtr rect;

    rect = (RectPtr)  XtMalloc(sizeof(RectStruct));

    rect->x = x;
    rect->y = y;
    rect->width = width;
    rect->height = height;
    rect->color = color;
    rect->pixmap = pixmap;

    return(rect);

}


/* This procedure will move the rectangle to the end of the rectangle
 * display table (effectively raising it to top of the displayed
 * rectangles).
 */
static void
RectToTop(RectPtr rect)
{

    int    i, j;


    if (rect) {

        /* Get the index to the target rectangle */
        for (i = 0; i < appInfo->numRects; i++) {
            if (appInfo->rectDpyTable[i] == rect)
                break;
        }

        /* Shift the other rectangles downward */
        for (j = i; j < appInfo->numRects - 1; j++)
            appInfo->rectDpyTable[j] = appInfo->rectDpyTable[j + 1];

        /* Place the target rectangle at the end */
        appInfo->rectDpyTable[j] = rect;

    }

}


/* This procedure raises the rectangle to the top of the drawing area */
/* ARGSUSED */
static void
RectRaise(Widget w, RectPtr rect)
{

    RectToTop(rect);
    RedrawRectangles(w);

}


/* This procedure moves the rectangle the the end of the display stack,
 * decrements the number of rectangles, and then frees the rectangle.
 */
void
RectFree(RectPtr rect)
{

    /* if the rectangle is registered */
    if (rect) {

        RectToTop(rect);
        appInfo->numRects--;
        XtFree((char *)rect);

    }

}


/* This procedure added the rectangle to the rectangle display table
 * (reallocing the table if necessary).
 */
void
RectRegister(RectPtr rect, Position x, Position y)
{

    appInfo->numRects++;

    /* rectangles can have their x and y values reset at registration time */
    rect->x = x;
    rect->y = y;

    /* realloc the table if it is too small */
    if (appInfo->numRects > appInfo->rectsAllocd) {

        /* grow geometrically */
        appInfo->rectsAllocd *= 2;
        appInfo->rectDpyTable = (RectPtr *) 
                                 XtRealloc((char *) appInfo->rectDpyTable,
                                           (unsigned) (sizeof(RectPtr) * 
                                           appInfo->rectsAllocd));

    }

    /* Add to end of display table */
    appInfo->rectDpyTable[appInfo->numRects - 1] = rect;

}


/* This function find the top most rectangle at the given x,y position */
RectPtr 
RectFind(Position x, Position y)
{

    RectPtr rect;
    int     i;

    /*
     * Search from the end of the rectangle display table
        * to find the top most rectangle.
        */
    for (i = appInfo->numRects - 1; i >= 0; i--) {

        rect = appInfo->rectDpyTable[i];
        if (rect->x <= x && rect->x + rect->width >= x &&
            rect->y <= y && rect->y + rect->height >= y) {
            return(rect);
        }

    }

    /* If a rectangle is not found return NULL */
    return(NULL);

}


/* This procedure sets the retangle's color */
void
RectSetColor(RectPtr rect, Display *display, Window window, Pixel color)
{

    rect->color = color;
    RectDraw(display, window, rect);

}


/* This function gets the retangle's color */
Pixel
RectGetColor(RectPtr rect)
{
    return(rect->color);
}


/* This procedure sets the retangle's pixmap. The pixmap portion of the
 * rectangle is not currently being used.
 */
/* ARGSUSED */
void
RectSetPixmap(RectPtr rect, Display *display, Window window, Pixmap pixmap)
{

    rect->pixmap = pixmap; /* not currently being looked at */
    RectDraw(display, window, rect);

}


/* This function gets the retangle's pixmap. The pixmap portion of the
 * rectangle is not currently being used.
 */
/* ARGSUSED */
static Pixmap
RectGetPixmap(RectPtr rect)
{
    return (rect->pixmap);
}


/* This procedure gets the retangle's height and width.  */
/* ARGSUSED */
static void
RectGetDimensions(RectPtr rect, Dimension *width, Dimension *height)
{

    *width = rect->width;
    *height = rect->height;

}


/* This function creates the rectangle bitmaps for the icon. */
Pixmap
GetBitmapFromRect(Widget w, RectPtr rect, Pixel background, Pixel foreground,
Dimension *widthRtn, Dimension *heightRtn)
{
    Dimension width, height, maxHeight, maxWidth;
    GC fillGC;
    Pixmap icon_pixmap;
    Display *display = XtDisplay(w);
    XGCValues values;
    unsigned long mask;

    RectGetDimensions(rect, &width, &height);

    /* Get the maximum allowable width and height allowed by the cursor */
    maxWidth = appInfo->maxCursorWidth;
    maxHeight = appInfo->maxCursorHeight;

    /* if the dimensions aren't within the allowable dimensions resize
   * then proportionally
   */
    if (maxWidth < width || maxHeight < height) {

        if (width > height) {
            height = (height * maxWidth) / width;
            width = appInfo->maxCursorWidth;
        } else {
            width = (width * maxHeight) / height;
            height = appInfo->maxCursorHeight;
        }

    }

    /* Create a depth 1 pixmap (bitmap) for use with the drag icon */
    icon_pixmap = XCreatePixmap(display, XtWindow(w), width, height, 1);

    mask = GCFunction | GCForeground | GCBackground;
    values.foreground = 1;
    values.background = 0;
    values.function = GXcopy;
    /* create a GC for drawing into the bitmap */
    fillGC = XCreateGC(display, icon_pixmap, mask, &values);

    /*
     * This draws a filled rectangle.  If only an outline is desired
     * use a XDrawRectangle() call.  Note: the outline does not
     * produce a very nice melt effect.
     */
    XFillRectangle(display, icon_pixmap, fillGC, 0, 0, width, height);

    /* Free the fill GC */
    XFreeGC(display, fillGC);

    *widthRtn = width;
    *heightRtn = height;

    return(icon_pixmap);

}


/***************************************************************************
 ***************************************************************************
                  Functions used in Drawing Outlines:
 ***************************************************************************
 ***************************************************************************/

/*
 * This procedure changes the GC to do rubberband
 * drawing of a rectangle frame .
 */
static void
SetXorGC(Widget w)
{

    unsigned long valueMask = GCFunction | GCForeground | GCLineWidth |
                              GCPlaneMask;
    XGCValues values;
    Pixel bg, fg;


    XtVaGetValues (w, XmNbackground, &bg, XmNforeground, &fg, NULL);

    values.function = GXxor;
    values.plane_mask = fg^bg;   /* Better fix for 5127 */
    values.foreground = bg;
    values.line_width = 1;
    XChangeGC(XtDisplay(w), appInfo->rectGC, valueMask, &values);

}


/* This procedure returns the GC to it's initial state.  */
static void
SetNormGC(Widget w)
{

    unsigned long valueMask = GCFunction | GCLineWidth | GCForeground |
      			      GCPlaneMask;
    XGCValues values;

    values.function = GXcopy;
    values.foreground = appInfo->currentColor;
    values.line_width = HIGHLIGHT_THICKNESS;
    values.plane_mask = 0xFFFFFFFF;
    XChangeGC(XtDisplay(w), appInfo->rectGC, valueMask, &values);

}


/* This procedure returns the values of the current rectangle outline */
static void
OutlineGetDimensions(Position *x, Position *y, Dimension *width,
Dimension *height)
{

    if (appInfo->rectX < appInfo->rectX2) {
        *x = appInfo->rectX;
        *width = appInfo->rectX2 - *x;
    } else {
        *x = appInfo->rectX2;
        *width = appInfo->rectX - *x;
    }

    if (appInfo->rectY < appInfo->rectY2) {
        *y = appInfo->rectY;
        *height = appInfo->rectY2 - *y;
    } else {
        *y = appInfo->rectY2;
        *height = appInfo->rectY - *y;
    }

}


static void
OutlineDraw(Widget w)
{

    Position    x, y;
    Dimension    width, height;

    OutlineGetDimensions(&x, &y, &width, &height);

    XDrawRectangle(XtDisplay(w), XtWindow(w), appInfo->rectGC,
                   x, y, width, height);

}


/* This procedure sets intializes the drawing positions */
static void
OutlineSetPosition(Position x, Position y)
{

    appInfo->rectX = appInfo->rectX2 = x;
    appInfo->rectY = appInfo->rectY2 = y;

}


/* This procedure resets outline end position */
static void
OutlineResetPosition(Position x, Position y)
{

    appInfo->rectX2 = x;
    appInfo->rectY2 = y;

}


/* This action procedure begins creating a rectangle at the x,y position
 * of the button event if a rectangle doesn't already exist at
 * that position.  Otherwise is raises the rectangle to the top
 * of the drawing area.
 */
/* ARGSUSED */
void
StartRect(Widget w, XEvent *event, String *params, Cardinal *num_params)
{

    Display *display = XtDisplay(w);
    RectPtr rect;
    Position x = event->xbutton.x;
    Position y = event->xbutton.y;

    rect = RectFind(x, y);

    /* if there isn't a rectangle at this position, begin creating one */
    if (!rect) {

        appInfo->creatingRect = True;
        /* set gc for drawing rubberband outline for rectangles */
        SetXorGC(w);
        /* set the initial outline positions */
        OutlineSetPosition(x, y);
        /* Draw the rectangle */
        OutlineDraw(w);

    }
    else
        RectRaise(w, rect);

}


/* This action procedure extends the drawing of the outline
 * for the rectangle to be created.
 */
/* ARGSUSED */
void
ExtendRect(Widget w, XEvent *event, String *params, Cardinal *num_params)
{

    if (appInfo->creatingRect) {

        /* erase the old outline */
        OutlineDraw(w);
        /* set the new outline end positions */
        OutlineResetPosition(event->xbutton.x, event->xbutton.y);
        /* redraw the outline */
        OutlineDraw(w);

    }

}


/* This action procedure creates a rectangle depending on the
 * dimensions set in the StartRect and ExtendRect action procs.
 */
/* ARGSUSED */
void
EndRect(Widget w, XEvent *event, String *params, Cardinal *num_params)
{

    Position     x, y;
    Dimension    width, height;
    RectPtr     rect;


    if (appInfo->creatingRect) {

        /* erase the last outline */
        OutlineDraw(w);
        /* return GC to original state */
        SetNormGC(w);

        /* Get the outline dimensions for creating the rectangle */
        OutlineGetDimensions(&x, &y, &width, &height);

        /* we don't want to create zero width or height rectangles */
        if (width == 0 || height == 0){
            appInfo->creatingRect = False;
            return;
        }

        rect = RectCreate(x, y, width, height,
                          GetColor(RECT_START_COLOR), XmUNSPECIFIED_PIXMAP);

        RectDraw(XtDisplay(w), XtWindow(w), rect);
        RectRegister(rect, x, y);
        appInfo->creatingRect = False;

    }

}


/* The procedure assigns new translations the the given widget */
static void
SetupTranslations(Widget widget, char *new_translations)
{

    XtTranslations new_table;

    new_table = XtParseTranslationTable(new_translations);
    XtOverrideTranslations(widget, new_table);

}


/* This procedure handles exposure events and makes a call to 
 * RedrawRectangles() to redraw the rectangles
 * The rectangles at the top of the table are drawn first.
 */
/* ARGSUSED */
static void
HandleExpose(Widget w, XtPointer closure, XtPointer call_data)
{
    RedrawRectangles(w);
}


/* This procedure sets up the drawing area */
static void
CreateDrawingArea(Widget parent)
{

    static char da_translations[] = 
        "#replace <Btn2Down>: StartMove() \n\
        <Btn1Down>: StartRect() \n\
        <Btn1Motion>: ExtendRect() \n\
        <Btn1Up>: EndRect() \n\
        c <Key>t: XtDisplayTranslations()";

    Arg             args[10];
    int             n = 0;
    XtTranslations    new_table;

    new_table = XtParseTranslationTable(da_translations);

    /* create drawing area at the top of the form */
    n = 0;
    XtSetArg(args[n], XmNtranslations, new_table); n++;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNwidth, 295); n++;
    XtSetArg(args[n], XmNheight, 180); n++;
    XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
    XtSetArg(args[n], XmNbackground, GetColor(DRAW_AREA_BG_COLOR)); n++;
    XtSetArg(args[n], XmNforeground, GetColor(DRAW_AREA_FG_COLOR)); n++;
    drawingArea = XmCreateDrawingArea(parent, "drawingArea", args, n);
    XtManageChild(drawingArea);

    /* add expose callback to redisplay rectangles */
    XtAddCallback(drawingArea, XmNexposeCallback, HandleExpose, 
                  (XtPointer) NULL);

    /* add callbacks for UTM */
    XtAddCallback(drawingArea, XmNdestinationCallback, 
		  (XtCallbackProc) handleDestination, (XtPointer) NULL);
    XtAddCallback(drawingArea, XmNconvertCallback,
		  (XtCallbackProc) RectConvert, (XtPointer) NULL);
}


/* This procedure sets up the area for obtaining rectangle colors */
static void
CreateColorPushButtons(Widget parent, Widget separator)
{

    static char label_translations[] = "<Btn2Down>: ColorRect()";
    Widget         bulletinBoard;
    Widget         children[6];
    XmString    csString;
    Arg         args[10];
    int         n = 0;

    /* Creating an empty compound string so the labels will have no text. */
    csString = XmStringCreateSimple("");

    /* Creating 6 color labels */
    n = 0;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(args[n], XmNtopWidget, separator); n++;
    XtSetArg(args[n], XmNtopOffset, 2); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNwidth, 295); n++;
    bulletinBoard = XmCreateBulletinBoard(parent, "buletinBoard", args, n);
    XtManageChild(bulletinBoard);

    n = 0;
    XtSetArg(args[n], XmNx, BOX_X_MARGIN); n++;
    XtSetArg(args[n], XmNy, BOX_Y_MARGIN); n++;
    XtSetArg(args[n], XmNwidth, BOX_WIDTH); n++;
    XtSetArg(args[n], XmNheight, BOX_HEIGHT); n++;
    XtSetArg(args[n], XmNlabelString, csString); n++;
    XtSetArg(args[n], XmNbackground, GetColor(LABEL1_COLOR)); n++;
    XtSetArg(args[n], XmNborderWidth, 1); n++;
    children[0] = XmCreatePushButton(bulletinBoard, "PushButton1", args, n);

    /* add translations for manipulating rectangles */
    SetupTranslations(children[0], label_translations);

    n = 0;
    XtSetArg(args[n], XmNx, BOX_X_MARGIN + BOX_X_OFFSET); n++;
    XtSetArg(args[n], XmNy, BOX_Y_MARGIN); n++;
    XtSetArg(args[n], XmNwidth, BOX_WIDTH); n++;
    XtSetArg(args[n], XmNheight, BOX_HEIGHT); n++;
    XtSetArg(args[n], XmNlabelString, csString); n++;
    XtSetArg(args[n], XmNbackground, GetColor(LABEL2_COLOR)); n++;
    XtSetArg(args[n], XmNborderWidth, 1); n++;
    children[1] = XmCreatePushButton(bulletinBoard, "PushButton1", args, n);

    /* add translations for manipulating rectangles */
    SetupTranslations(children[1], label_translations);

    n = 0;
    XtSetArg(args[n], XmNx, BOX_X_MARGIN + (2 * BOX_X_OFFSET)); n++;
    XtSetArg(args[n], XmNy, BOX_Y_MARGIN); n++;
    XtSetArg(args[n], XmNwidth, BOX_WIDTH); n++;
    XtSetArg(args[n], XmNheight, BOX_HEIGHT); n++;
    XtSetArg(args[n], XmNlabelString, csString); n++;
    XtSetArg(args[n], XmNbackground, GetColor(LABEL3_COLOR)); n++;
    XtSetArg(args[n], XmNborderWidth, 1); n++;
    children[2] = XmCreatePushButton(bulletinBoard, "PushButton3", args, n);

    /* add translations for manipulating rectangles */
    SetupTranslations(children[2], label_translations);

    n = 0;
    XtSetArg(args[n], XmNx, BOX_X_MARGIN); n++;
    XtSetArg(args[n], XmNy, BOX_Y_MARGIN + BOX_Y_OFFSET); n++;
    XtSetArg(args[n], XmNwidth, BOX_WIDTH); n++;
    XtSetArg(args[n], XmNheight, BOX_HEIGHT); n++;
    XtSetArg(args[n], XmNlabelString, csString); n++;
    XtSetArg(args[n], XmNbackground, GetColor(LABEL4_COLOR)); n++;
    XtSetArg(args[n], XmNborderWidth, 1); n++;
    children[3] = XmCreatePushButton(bulletinBoard, "PushButton4", args, n);

    /* add translations for manipulating rectangles */
    SetupTranslations(children[3], label_translations);

    n = 0;
    XtSetArg(args[n], XmNx, BOX_X_MARGIN + BOX_X_OFFSET); n++;
    XtSetArg(args[n], XmNy, BOX_Y_MARGIN + BOX_Y_OFFSET); n++;
    XtSetArg(args[n], XmNwidth, BOX_WIDTH); n++;
    XtSetArg(args[n], XmNheight, BOX_HEIGHT); n++;
    XtSetArg(args[n], XmNtopWidget, children[0]); n++;
    XtSetArg(args[n], XmNlabelString, csString); n++;
    XtSetArg(args[n], XmNbackground, GetColor(LABEL5_COLOR)); n++;
    XtSetArg(args[n], XmNborderWidth, 1); n++;
    children[4] = XmCreatePushButton(bulletinBoard, "PushButton5", args, n);

    /* add translations for manipulating rectangles */
    SetupTranslations(children[4], label_translations);

    n = 0;
    XtSetArg(args[n], XmNx, BOX_X_MARGIN + (2 * BOX_X_OFFSET)); n++;
    XtSetArg(args[n], XmNy, BOX_Y_MARGIN + BOX_Y_OFFSET); n++;
    XtSetArg(args[n], XmNwidth, BOX_WIDTH); n++;
    XtSetArg(args[n], XmNheight, BOX_HEIGHT); n++;
    XtSetArg(args[n], XmNlabelString, csString); n++;
    XtSetArg(args[n], XmNbackground, GetColor(LABEL6_COLOR)); n++;
    XtSetArg(args[n], XmNborderWidth, 1); n++;
    children[5] = XmCreatePushButton(bulletinBoard, "PushButton6", args, n);

    /* add translations for manipulating rectangles */
    SetupTranslations(children[5], label_translations);

    /* Managing the children all at once helps performance */
    XtManageChildren(children, 6);

    /* Add convert callbacks */
    for(n = 0; n < 6; n++)
      XtAddCallback(children[n], XmNconvertCallback, 
		    (XtCallbackProc) ColorConvert, (XtPointer) NULL);

    /* Freeing compound string.  It is no longer necessary. */
    XmStringFree(csString);

}


/* This procedure initalizes the rectangle display table */
void
InitializeRectDpyTable(void)
{
    /*
     * Initialize display table.  This is used to maintain the
     * order in which the rectangles are displayed
     */
    appInfo->rectDpyTable = (RectPtr *) XtMalloc((unsigned)sizeof(RectPtr));

    /* Initialize rectangle counter.  This is used in reallocing the tables */
    appInfo->rectsAllocd = 1;

}


/* This procedure creates the components to be displayed */
void
CreateLayout(void)
{

    Widget    mainWindow, form, separator;
    Arg     args[10];
    int     n = 0;

    /* Create main window */
    mainWindow = XmCreateMainWindow(topLevel, "mainWindow", args, n);
    XtManageChild(mainWindow);

    /* Create form for hold drawing area, separator, and color labels */
    n = 0;
    XtSetArg(args[n], XmNwidth, 300); n++;
    form = XmCreateForm(mainWindow, "form", args, n);
    XtManageChild(form);

    /* Create area for drawing rectangles */
    CreateDrawingArea(form);

    /* Create separator to separate drawing area from color labels */
    n = 0;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(args[n], XmNtopWidget, drawingArea); n++;
    XtSetArg(args[n], XmNtopOffset, 5); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNwidth, 300); n++;
    separator = XmCreateSeparatorGadget(form, "separator", args, n);
    XtManageChild(separator);

    /* Create color labels for changing colors of buttons */
    CreateColorPushButtons(form, separator);

    /* Make form the work window of the main window */
    n = 0;
    XtSetArg(args[n], XmNworkWindow, form); n++;
    XtSetValues(mainWindow, args, n);

}


/* This procedure initializes the GC for drawing rectangles */
void
CreateRectGC(void)
{

    XGCValues    values;

    values.line_style = LineSolid;
    values.line_width = HIGHLIGHT_THICKNESS;
    values.foreground = appInfo->currentColor = GetColor(RECT_START_COLOR);
    appInfo->rectGC = XCreateGC(XtDisplay(topLevel), XtWindow(drawingArea),
                      GCLineStyle | GCLineWidth | GCForeground, &values);

}
