/*****************************************************************************
*   Program to draw EE diagrams.					     *
*									     *
* This module handles object modification.				     *
*									     *
* Written by:  Gershon Elber			IBM PC Ver 1.0,	Oct. 1989    *
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
#include <dos.h>
#include "Program.h"
#include "EECreate.h"
#include "EELibs.h"
#include "EEModify.h"
#include "EERedraw.h"
#include "EEString.h"
#include "EELayer.h"
#include "Primary.h"	/* Primary Drawing Layers Designation Numbers */

#define UNDELETE_STACK_SIZE 10

static char *EditMenuStrs[] =
{
    "Done",
    "",
    "EditPartName",
    "Un/DrawChipName",
    "ReposPartName",
    "ReposChipName",
    "RePosLibItem"
};
#define EDIT_MENU_SIZE (sizeof(EditMenuStrs) / sizeof(char *))

static int
    UnDeleteStackPtr = 0;
static DrawGenericStruct
    *LastSnappedStruct = NULL;
static DrawGenericStruct *UnDeleteStack[UNDELETE_STACK_SIZE];
static int PickedBoxMinX, PickedBoxMinY, PickedBoxMaxX, PickedBoxMaxY;
static IntrCursorShapeStruct Cursor;
static IntrPopUpMenuStruct
    *EditPopUpMenu = NULL;

static void MoveStructs(DrawPickedStruct *DrawStructs, int Dx, int Dy);
static void MoveOneStruct(DrawGenericStruct *DrawStructs, int Dx, int Dy);
static int PlaceStruct(DrawGenericStruct *DrawStruct);
static DrawGenericStruct *CopyStructLocal(DrawGenericStruct *DrawStruct);

/*****************************************************************************
* Routine to move an object(s) to a new position.			     *
* If DrawStruct is of type DrawPickedStruct, a list of objects picked is     *
* assumed, otherwise exactly one structure is assumed been picked.	     *
*****************************************************************************/
BooleanType MoveStruct(DrawGenericStruct *DrawStruct)
{
    BooleanType RetVal;

    /* Remove this structure(s) from display and global structure list.	     */
    DeleteStruct(DrawStruct);

    RetVal = PlaceStruct(DrawStruct);	    /* Place it in its new position. */

    UnDeleteStruct();		     /* And undelete it in its new position. */

    return RetVal;
}

/*****************************************************************************
* Routine to copy a new entity of an object and reposition it.		     *
* If DrawStruct is of type DrawPickedStruct, a list of objects picked is     *
* assumed, otherwise exactly one structure is assumed been picked.	     *
*****************************************************************************/
BooleanType CopyStruct(DrawGenericStruct *DrawStruct)
{
    BooleanType RetVal;

    DrawGenericStruct *NewDrawStruct;
    DrawPickedStruct *PickedItem,
        *PickedList = NULL;

    NewDrawStruct = CopyStructLocal(DrawStruct);

    if ((RetVal = PlaceStruct(NewDrawStruct)) != FALSE) {
	/* Draw the new structure and chain it in: */
	if (NewDrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	    RedrawStructList(NewDrawStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	    PickedList = (DrawPickedStruct *) NewDrawStruct;
	    while (PickedList) {
		PickedList -> PickedStruct -> Pnext =
                			EEActiveWindow -> EEDrawList;
		EEActiveWindow -> EEDrawList = PickedList -> PickedStruct;

		PickedItem = PickedList;
		PickedList = PickedList -> Pnext;
		MyFree((VoidPtr) PickedItem);
	    }
	}
	else {
	    RedrawOneStruct(NewDrawStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	    NewDrawStruct->Pnext = EEActiveWindow -> EEDrawList;
	    EEActiveWindow -> EEDrawList = NewDrawStruct;
	}
    }
    else
	FreeStruct(NewDrawStruct);

    /* Free the original DrawPickedStruct chain: */
    if (DrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	PickedList = (DrawPickedStruct *) DrawStruct;

	while (PickedList != NULL) {
	    PickedItem = PickedList;
	    PickedList = PickedList -> Pnext;
	    MyFree((VoidPtr) PickedItem);
	}
    }

    return RetVal;
}

/*****************************************************************************
* Routine to delete an object from global drawing object list.		     *
*****************************************************************************/
void DeleteStruct(DrawGenericStruct *DrawStruct)
{
    int i;
    DrawGenericStruct
	*DrawList = EEActiveWindow -> EEDrawList;
    DrawPickedStruct
	*PickedList = NULL;

    /* Effectively hides the cursor to prevent from its	interference with   */
    /* the erased object(s).						    */
    IntrPushCursorType();

    if (DrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	PickedList = (DrawPickedStruct *) DrawStruct;
	while (PickedList) {
	    if (PickedList -> PickedStruct == EEActiveWindow -> EEDrawList)
		EEActiveWindow -> EEDrawList =
                    EEActiveWindow -> EEDrawList -> Pnext;
	    else {
		DrawList = EEActiveWindow -> EEDrawList;
		while (DrawList -> Pnext) {
		    if (DrawList -> Pnext == PickedList -> PickedStruct) {
			DrawList -> Pnext = DrawList -> Pnext -> Pnext;
			break;
		    }
		    DrawList = DrawList -> Pnext;
		}
	    }

	    PickedList = PickedList -> Pnext;
	}

	RedrawStructList(DrawStruct, GR_COPY_PUT, EE_ERASE_COLOR);
    }
    else {
	if (DrawStruct == EEActiveWindow -> EEDrawList)
	    EEActiveWindow -> EEDrawList =
                EEActiveWindow -> EEDrawList -> Pnext;
	else {
	    DrawList = EEActiveWindow -> EEDrawList;
	    while (DrawList -> Pnext) {
		if (DrawList -> Pnext == DrawStruct) {
		    DrawList -> Pnext = DrawList -> Pnext -> Pnext;
		    break;
		}
		DrawList = DrawList -> Pnext;
	    }
	}

	RedrawOneStruct(DrawStruct, GR_COPY_PUT, EE_ERASE_COLOR);
    }

    if (UnDeleteStackPtr >= UNDELETE_STACK_SIZE - 1) {
	/* Delete last deleted item, and shift stack. */
	FreeStruct(UnDeleteStack[0]);
	for (i = 0; i < UnDeleteStackPtr; i++)
	    UnDeleteStack[i] = UnDeleteStack[i + 1];
	UnDeleteStack[UnDeleteStackPtr] = DrawStruct;
    }
    else
	UnDeleteStack[UnDeleteStackPtr++] = DrawStruct;

    IntrPopCursorType();			    /* Reenable the cursor. */
}

/*****************************************************************************
* Routine to cut an object from global drawing object list.		     *
*   This routine is the same as delete but the original list is NOT removed. *
*****************************************************************************/
void CutStruct(DrawGenericStruct *DrawStruct)
{
    int i;
    DrawPickedStruct *PickedItem, *PickedList;
    DrawGenericStruct *DrawStructCopy;

    /* Make a copy of the original picked item. */
    DrawStructCopy = CopyStructLocal(DrawStruct);

    if (DrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	/* Delete the picked wrapper if this is a picked list. */
        for (PickedList = (DrawPickedStruct *) DrawStruct; PickedList != NULL; ) {
	    PickedItem = PickedList;
	    PickedList = PickedList -> Pnext;
	    MyFree((VoidPtr) PickedItem);
	}
    }

    /* And push it into the delete stack: */
    if (UnDeleteStackPtr >= UNDELETE_STACK_SIZE - 1) {
	/* Delete last deleted item, and shift stack. */
	FreeStruct(UnDeleteStack[0]);
	for (i = 0; i < UnDeleteStackPtr; i++)
	    UnDeleteStack[i] = UnDeleteStack[i + 1];
	UnDeleteStack[UnDeleteStackPtr] = DrawStructCopy;
    }
    else
	UnDeleteStack[UnDeleteStackPtr++] = DrawStructCopy;
}

/*****************************************************************************
* Routine to undelete a structure from the undelete stack.		     *
*****************************************************************************/
BooleanType UnDeleteStruct(void)
{
    DrawGenericStruct *DrawStruct;
    DrawPickedStruct  *PickedItem,
	*PickedList = NULL;

    if (UnDeleteStackPtr == 0) {
	Cursor.CursorType = INTR_CURSOR_ARROW;
	IntrQueryContinue("No struct to undelete", EEPopUpFrameColor,
        		  EEPopUpBackColor, EEPopUpForeColor,
                          EEPopUpXorColor, EEWindowsFrameWidth, &Cursor,
                          INTR_WNDW_PLACE_CENTER);
        return FALSE;
    }
    else {
	DrawStruct = UnDeleteStack[--UnDeleteStackPtr];
	if (DrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	    RedrawStructList(DrawStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	    for (PickedList = (DrawPickedStruct *) DrawStruct;
		 PickedList != NULL; ) {
		PickedList -> PickedStruct -> Pnext =
                    EEActiveWindow -> EEDrawList;
		EEActiveWindow -> EEDrawList = PickedList -> PickedStruct;

		PickedItem = PickedList;
		PickedList = PickedList -> Pnext;
		MyFree((VoidPtr) PickedItem);
	    }
	}
	else {
	    RedrawOneStruct(DrawStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	    DrawStruct -> Pnext = EEActiveWindow -> EEDrawList;
	    EEActiveWindow -> EEDrawList = DrawStruct;
	}
        return TRUE;
    }
}

/*****************************************************************************
* Routine to paste a structure from the undelete stack.			     *
*   This routine is the same as undelete but original list is NOT removed.   *
*****************************************************************************/
BooleanType PasteStruct(void)
{
    DrawGenericStruct *DrawStruct;
    DrawPickedStruct  *PickedItem,
	*PickedList = NULL;

    if (UnDeleteStackPtr == 0) {
	Cursor.CursorType = INTR_CURSOR_ARROW;
	IntrQueryContinue("No struct to paste", EEPopUpFrameColor,
        		  EEPopUpBackColor, EEPopUpForeColor,
                          EEPopUpXorColor, EEWindowsFrameWidth, &Cursor,
                          INTR_WNDW_PLACE_CENTER);
        return FALSE;
    }
    else {
	DrawStruct = CopyStructLocal(UnDeleteStack[UnDeleteStackPtr - 1]);
        if (DrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE)
	    MoveStructs((DrawPickedStruct *) DrawStruct, EESnapDistance,
            						 EESnapDistance);
        else
	    MoveOneStruct(DrawStruct, EESnapDistance, EESnapDistance);
        PlaceStruct(DrawStruct);
	if (DrawStruct -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	    RedrawStructList(DrawStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	    for (PickedList = (DrawPickedStruct *) DrawStruct;
		 PickedList != NULL; ) {
		PickedList -> PickedStruct -> Pnext =
                    EEActiveWindow -> EEDrawList;
		EEActiveWindow -> EEDrawList = PickedList -> PickedStruct;

		PickedItem = PickedList;
		PickedList = PickedList -> Pnext;
		MyFree((VoidPtr) PickedItem);
	    }
	}
	else {
	    RedrawOneStruct(DrawStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	    DrawStruct -> Pnext = EEActiveWindow -> EEDrawList;
	    EEActiveWindow -> EEDrawList = DrawStruct;
	}
        return TRUE;
    }
}

/*****************************************************************************
* Routine to drop a structure from the undelete top of stack.		     *
*****************************************************************************/
void DropStruct(void)
{
    if (UnDeleteStackPtr == 0) {
	Cursor.CursorType = INTR_CURSOR_ARROW;
	IntrQueryContinue("No struct to drop", EEPopUpFrameColor,
        		  EEPopUpBackColor, EEPopUpForeColor,
                          EEPopUpXorColor, EEWindowsFrameWidth, &Cursor,
                          INTR_WNDW_PLACE_CENTER);
    }
    else {
	IntrDrawMessage("Dropping top of stack", EEPopUpForeColor,
            					 EEPopUpBackColor);
	FreeStruct(UnDeleteStack[--UnDeleteStackPtr]);
        delay(200);
	IntrEraseMessage();
    }
}

/*****************************************************************************
* Routine to place a given object.					     *
*****************************************************************************/
static BooleanType PlaceStruct(DrawGenericStruct *DrawStruct)
{
    int x, y;
    BooleanType
        RetVal = FALSE;

    delay(250);		    /* Make sure no events are waiting in the queue. */
    IntrInputFlush();

    IntrSetIdleFunction(AutoPanActiveWindow);

    switch (DrawStruct -> StructType) {
	case DRAW_POLYLINE_STRUCT_TYPE:
	    RetVal = PlacePolylineStruct((DrawPolylineStruct *) DrawStruct);
            break;
	case DRAW_CONNECTION_STRUCT_TYPE:
	    GRCurrentCursorX = GRMapX(((DrawConnectionStruct *) DrawStruct) -> PosX);
	    GRCurrentCursorY = GRMapY(((DrawConnectionStruct *) DrawStruct) -> PosY);
	    RetVal = PlaceConnectionStruct((DrawConnectionStruct *) DrawStruct);
            break;
	case DRAW_TEXT_STRUCT_TYPE:
	    GRCurrentCursorX = GRMapX(((DrawTextStruct *) DrawStruct) -> PosX);
	    GRCurrentCursorY = GRMapY(((DrawTextStruct *) DrawStruct) -> PosY);
	    RetVal = PlaceTextStruct((DrawTextStruct *) DrawStruct);
            break;
	case DRAW_LIB_ITEM_STRUCT_TYPE:
	    GRCurrentCursorX = GRMapX(((DrawLibItemStruct *) DrawStruct) -> PosX);
	    GRCurrentCursorY = GRMapY(((DrawLibItemStruct *) DrawStruct) -> PosY);
	    RetVal = PlaceLibItem((DrawLibItemStruct *) DrawStruct);
            break;
	case DRAW_PICK_ITEM_STRUCT_TYPE:
	    /* Place a box instead: */
	    IntrPushCursorType();
            Cursor.CursorType = INTR_CURSOR_BOX;
            GRCurrentCursorX = (GRMapX(PickedBoxMaxX) - GRMapX(PickedBoxMinX)) / 2;
            GRCurrentCursorY = (GRMapY(PickedBoxMaxY) - GRMapY(PickedBoxMinY)) / 2;
            Cursor.Width = (GRMapX(PickedBoxMaxX) - GRMapX(PickedBoxMinX)) / 2;
            Cursor.Height = (GRMapY(PickedBoxMaxY) - GRMapY(PickedBoxMinY)) / 2;
	    IntrSetCursorType(&Cursor);

	    GRCurrentCursorX = GRMapX((PickedBoxMinX + PickedBoxMaxX) / 2);
	    GRCurrentCursorY = GRMapY((PickedBoxMinY + PickedBoxMaxY) / 2);

	    IntrDrawMessage("Place picked box", EEPopUpForeColor,
            					EEPopUpBackColor);
	    /* Move all object is the selected block out of drawing area: */
	    MoveStructs((DrawPickedStruct *) DrawStruct, -10000, -10000);

	    if (IntrGetEventWaitSA(&x, &y) == INTR_EVNT_SELECT) {
		x = EE_SNAP(GRInvMapX(x));
		y = EE_SNAP(GRInvMapY(y));

		MoveStructs((DrawPickedStruct *) DrawStruct,
			    x - (PickedBoxMaxX + PickedBoxMinX) / 2 + 10000,
			    y - (PickedBoxMaxY + PickedBoxMinY) / 2 + 10000);

		IntrPopCursorType();
		IntrEraseMessage();
		RetVal = TRUE;
	    }
	    else {
		MoveStructs((DrawPickedStruct *) DrawStruct, 10000, 10000);

		IntrPopCursorType();
		IntrEraseMessage();
		RetVal = FALSE;
	    }
            break;
    }

    IntrSetIdleFunction(NULL);

    return RetVal;
}

/*****************************************************************************
* Given list of structures as DrawPickStruct list move them all by Dx, Dy    *
* (given in drawing space).						     *
*****************************************************************************/
static void MoveStructs(DrawPickedStruct *DrawStructs, int Dx, int Dy)
{
    /* Make sure we will stay on the snap boundaries. */
    Dx = EE_SNAP(Dx);
    Dy = EE_SNAP(Dy);

    while (DrawStructs) {
	MoveOneStruct(DrawStructs -> PickedStruct, Dx, Dy);

	DrawStructs = DrawStructs -> Pnext;
    }
}

/*****************************************************************************
* Given a structures move it by Dx, Dy.					     *
*****************************************************************************/
static void MoveOneStruct(DrawGenericStruct *DrawStruct, int Dx, int Dy)
{
    int i, *Points;
    DrawPolylineStruct *DrawPoly;
    DrawConnectionStruct *DrawConnect;
    DrawTextStruct *DrawText;
    DrawLibItemStruct *DrawLibItem;

    switch (DrawStruct -> StructType) {
        case DRAW_POLYLINE_STRUCT_TYPE:
	    DrawPoly = (DrawPolylineStruct *) DrawStruct;
	    Points = DrawPoly -> Points;
	    for (i = 0; i < DrawPoly -> NumOfPoints; i++) {
	        Points[i * 2] += Dx;
	        Points[i * 2 + 1] += Dy;
	    }
	    break;
	case DRAW_CONNECTION_STRUCT_TYPE:
	    DrawConnect = (DrawConnectionStruct *) DrawStruct;
	    DrawConnect -> PosX += Dx;
	    DrawConnect -> PosY += Dy;
	    break;
	case DRAW_TEXT_STRUCT_TYPE:
	    DrawText = (DrawTextStruct *) DrawStruct;
	    DrawText -> PosX += Dx;
	    DrawText -> PosY += Dy;
	    break;
	case DRAW_LIB_ITEM_STRUCT_TYPE:
	    DrawLibItem = (DrawLibItemStruct *) DrawStruct;
	    DrawLibItem -> PosX += Dx;
	    DrawLibItem -> PosY += Dy;
	    DrawLibItem -> PartNameX += Dx;
	    DrawLibItem -> PartNameY += Dy;
	    DrawLibItem -> ChipNameX += Dx;
	    DrawLibItem -> ChipNameY += Dy;
	    DrawLibItem -> BBoxMinX += Dx;
	    DrawLibItem -> BBoxMinY += Dy;
	    DrawLibItem -> BBoxMaxX += Dx;
	    DrawLibItem -> BBoxMaxY += Dy;
	    break;
    }
}

/*****************************************************************************
* Routine to edit library items and modify its entries.			     *
*****************************************************************************/
BooleanType EditLibraryItem(void)
{
    int PopPosition;
    char Line[LINE_LEN_SHORT], *OldStr;
    TextOrientationType Orient;
    BooleanType
        RetVal = FALSE;
    DrawLibItemStruct *LibItem;
    DrawPickedStruct *PickedItem,
	*PickedList = NULL;

    Cursor.CursorType = INTR_CURSOR_ARROW;
    if (EditPopUpMenu == NULL) {
        EditPopUpMenu =
            IntrPopUpMenuCreate("Modify Lib Item", (char **) EditMenuStrs,
                	    0, EDIT_MENU_SIZE, EEPopUpFrameColor,
                              EEPopUpBackColor, EEPopUpForeColor,
                            EEPopUpXorColor, EEWindowsFrameWidth, &Cursor);
    }

    LibItem = (DrawLibItemStruct *) PickStruct("Pick Library Item to Edit:",
    									TRUE);

    PopPosition = GRMapX(LibItem -> PosX) < GRScreenMaxX / 2 ?
							INTR_WNDW_PLACE_RIGHT :
							INTR_WNDW_PLACE_LEFT;

    if (LibItem != NULL &&
	LibItem -> StructType == DRAW_LIB_ITEM_STRUCT_TYPE) {
	DrawLibPart(LibItem, GR_COPY_PUT, EE_HIGHLIGHT_COLOR);
	SetHighLightStruct((DrawGenericStruct *) LibItem);

	while (IntrPopUpMenu(EditPopUpMenu, PopPosition) &&
	       EditPopUpMenu -> SelectedIndex != 0) {
	    switch (EditPopUpMenu -> SelectedIndex) {
	    	case 2: /* EditPartName */
	    	    if (LibItem -> PartName != NULL) {
	    	    	strcpy(Line, LibItem -> PartName);
	    	    	OldStr = LibItem -> PartName;
	    	    	LibItem -> PartName = NULL;
	    	    }
	    	    else {
	    	    	Line[0] = 0;
	    	    	OldStr = NULL;
	    	    }

	    	    IntrQueryLine("Enter new part name:", Line,
		        LINE_LEN_SHORT - 1, EEPopUpFrameColor, EEPopUpBackColor,
	    		EEPopUpForeColor, EEWindowsFrameWidth, PopPosition);

	    	    if (OldStr != NULL) {
	    	    	GRSetWriteMode(GR_COPY_PUT);
	    	    	GRSetColor(EE_ERASE_COLOR);
	    	    	PutTextInfo(LibItem -> PartNameOrient,
	    	    		    LibItem -> PartNameX,
	    	    		    LibItem -> PartNameY,
				    1,
				    OldStr);
	    	    	MyFree((VoidPtr) OldStr);
	    	    }

	    	    if (strlen(Line) > 0) {
	    	    	LibItem -> PartName = strdup(Line);
	    	    	if (OldStr == NULL) {
	    	    	    LibItem -> PartNameX = LibItem -> PosX;
	    	    	    LibItem -> PartNameY = LibItem -> PosY;
	    	    	}
	    	    	if (LibItem -> PartNameOrient == TEXT_ORIENT_NON)
	    	    	    PlaceString(LibItem -> PartName,
					&LibItem -> PartNameOrient,
					1,
	    	    			&LibItem -> PartNameX,
					&LibItem -> PartNameY,
        	                        PopPosition);
	    	    	GRSetWriteMode(GR_COPY_PUT);
	    	    	GRSetColor(ReturnLayerColor(LAYER_REFDES));
	    	    	PutTextInfo(LibItem -> PartNameOrient,
				    LibItem -> PartNameX,
				    LibItem -> PartNameY,
				    1,
				    LibItem -> PartName);
	    	    }
	    	    else
		        LibItem -> PartNameOrient = TEXT_ORIENT_NON;
	    	    RetVal = TRUE;
	    	    break;
	    	case 3: /* Un/DrawChipName */
		    if (CanDrawChipName(LibItem -> ChipName)) {
			if (LibItem -> ChipNameOrient != TEXT_ORIENT_NON) {
			    GRSetWriteMode(GR_COPY_PUT);
			    GRSetColor(EE_ERASE_COLOR);
			    PutTextInfo(LibItem -> ChipNameOrient,
	    	    			LibItem -> ChipNameX,
	    	    			LibItem -> ChipNameY,
					1,
					LibItem -> ChipName);
			    LibItem -> ChipNameOrient = TEXT_ORIENT_NON;
			}
		    	else {
			    LibItem -> ChipNameX = LibItem -> PosX;
	    	    	    LibItem -> ChipNameY = LibItem -> PosY;
			    if (PlaceString(LibItem -> ChipName,
		    			    &LibItem -> ChipNameOrient,
					    1,
					    &LibItem -> ChipNameX,
					    &LibItem -> ChipNameY,
                        		    PopPosition)) {
				GRSetWriteMode(GR_COPY_PUT);
				GRSetColor(ReturnLayerColor(LAYER_DEVICE));
				PutTextInfo(LibItem -> ChipNameOrient,
					    LibItem -> ChipNameX,
					    LibItem -> ChipNameY,
					    1,
					    LibItem -> ChipName);
			    }
			}
			RetVal = TRUE;
	    	    }
	    	    else
	    	    	IntrQueryContinue("Chip name is NOT drawable for this item",
	    	    			  EEPopUpFrameColor, EEPopUpBackColor,
	    	    			  EEPopUpForeColor, EEPopUpXorColor,
					  EEWindowsFrameWidth, &Cursor,
	 			          PopPosition);
	    	    break;
	    	case 4: /* ReposPartName */
	    	    if (LibItem -> PartNameOrient == TEXT_ORIENT_NON) {
		        Cursor.CursorType = INTR_CURSOR_ARROW;
	    	    	IntrQueryContinue("Picked item has no part name",
	    	    			  EEPopUpFrameColor, EEPopUpBackColor,
	    	    			  EEPopUpForeColor, EEPopUpXorColor,
					  EEWindowsFrameWidth, &Cursor,
	 			          PopPosition);
	    	    	break;
	    	    }

	    	    GRSetWriteMode(GR_COPY_PUT);
	    	    GRSetColor(EE_ERASE_COLOR);
	    	    PutTextInfo(LibItem -> PartNameOrient,
				LibItem -> PartNameX,
				LibItem -> PartNameY,
				1,
				LibItem -> PartName);

		    /* Since when auto panning it will be redrawn, we        */
		    /* disable this string drawing temporarily.		     */
		    Orient = LibItem -> PartNameOrient;
		    LibItem -> PartNameOrient = TEXT_ORIENT_NON;
	    	    RetVal = PlaceString(LibItem -> PartName,
					 &Orient,
					 1,
					 &LibItem -> PartNameX,
					 &LibItem -> PartNameY,
	                        	 PopPosition);
		    LibItem -> PartNameOrient = Orient;

	    	    GRSetWriteMode(GR_COPY_PUT);
		    GRSetColor(ReturnLayerColor(LAYER_REFDES));
		    PutTextInfo(LibItem -> PartNameOrient,
				LibItem -> PartNameX,
				LibItem -> PartNameY,
				1,
				LibItem -> PartName);
	    	    break;
	    	case 5: /* ReposChipName */
	    	    if (LibItem -> ChipNameOrient == TEXT_ORIENT_NON ||
			!CanDrawChipName(LibItem -> ChipName)) {
	    	    	Cursor.CursorType = INTR_CURSOR_ARROW;
	    	    	IntrQueryContinue("Picked item has no chip name",
					  EEPopUpFrameColor, EEPopUpBackColor,
                                	  EEPopUpForeColor, EEPopUpXorColor,
                                	  EEWindowsFrameWidth, &Cursor,
                                	  PopPosition);
	    	    	break;
	    	    }

		    GRSetWriteMode(GR_COPY_PUT);
		    GRSetColor(EE_ERASE_COLOR);
		    PutTextInfo(LibItem -> ChipNameOrient,
				LibItem -> ChipNameX,
				LibItem -> ChipNameY,
				1,
				LibItem -> ChipName);

		    /* Since when auto panning it will be redrawn, we        */
		    /* disable this string drawing temporarily.		     */
		    Orient = LibItem -> ChipNameOrient;
		    LibItem -> ChipNameOrient = TEXT_ORIENT_NON;
		    RetVal = PlaceString(LibItem -> ChipName,
					 &Orient,
					 1,
					 &LibItem -> ChipNameX,
					 &LibItem -> ChipNameY,
	                        	 PopPosition);
		    LibItem -> ChipNameOrient = Orient;

	    	    GRSetWriteMode(GR_COPY_PUT);
		    GRSetColor(ReturnLayerColor(LAYER_DEVICE));
		    PutTextInfo(LibItem -> ChipNameOrient,
		    		LibItem -> ChipNameX,
				LibItem -> ChipNameY,
				1,
				LibItem -> ChipName);
	    	    break;
	    	case 6: /* RePosLibItem */
		    RetVal = RePosLibItem(LibItem, PopPosition);
	    	    break;
	    }
	}

	SetHighLightStruct(NULL);
	DrawLibPart(LibItem, GR_COPY_PUT, EE_DRAW_COLOR);
    }

    if (LibItem -> StructType == DRAW_PICK_ITEM_STRUCT_TYPE) {
	PickedList = (DrawPickedStruct *) LibItem;

	while (PickedList != NULL) {
	    /* More than one item were picked - free them all: */
	    PickedItem = PickedList;
	    PickedList = PickedList -> Pnext;
	    MyFree((VoidPtr) PickedItem);
	}
    }

    return RetVal;
}

/*****************************************************************************
* Routine to place a string. Returns string xy position and orientation      *
* (vertically/horizontally). Returns TRUE if successful, FALSE otherwise.    *
*****************************************************************************/
BooleanType PlaceString(char *Str, TextOrientationType *Orient, int Scale,
					      int *x, int *y, int PopPosition)
{
    int CrsrBoxWidth, CrsrBoxHeight,
	LocalX = *x,
        LocalY = *y,
	Size = MAX(1, GRFontSize + (Scale - 1)) - DEFAULT_ZOOM_FACTOR;
    TextOrientationType LocalOrient;
    BooleanType RetVal;
    char Line[LINE_LEN];

    Cursor.CursorType = INTR_CURSOR_ARROW;
    GRPushTextSetting();
    GRSetTextStyle(GRFontName, TEXT_ORIENT_HORIZ, Size);
    if (IntrQueryYesNo("Horizonal?", EEPopUpFrameColor,
                       EEPopUpBackColor, EEPopUpForeColor, EEPopUpXorColor,
                       EEWindowsFrameWidth, &Cursor, PopPosition)) {
	LocalOrient = TEXT_ORIENT_HORIZ;
	CrsrBoxWidth = GRGetTextWidth(Str) / 2;
	CrsrBoxHeight = GRGetTextHeight(Str) / 2;
    }
    else {
	LocalOrient = TEXT_ORIENT_VERT;
	CrsrBoxWidth = GRGetTextHeight(Str) / 2;
	CrsrBoxHeight = GRGetTextWidth(Str) / 2;
    }
    GRPopTextSetting();

    IntrPushCursorType();
    Cursor.CursorType = INTR_CURSOR_BOX;
    Cursor.Width = CrsrBoxWidth;
    Cursor.Height = CrsrBoxHeight;
    IntrSetCursorType(&Cursor);

    sprintf(Line, "Place \"%s\":", Str);
    IntrDrawMessage(Line, EEPopUpForeColor, EEPopUpBackColor);

    if (LocalX >= 0 && LocalY >= 0) {
	GRCurrentCursorX = GRMapX(LocalX);
	GRCurrentCursorY = GRMapY(LocalY);
    }
    PutCursorInActiveWindow();

    IntrSetIdleFunction(AutoPanActiveWindow);

    if ((RetVal = IntrGetEventWaitSA(&LocalX, &LocalY) == INTR_EVNT_SELECT)
								!= FALSE) {
	*x = EE_SNAP(GRInvMapX(LocalX));
	*y = EE_SNAP(GRInvMapY(LocalY));
        *Orient = LocalOrient;
    }

    IntrSetIdleFunction(NULL);

    Cursor.CursorType = INTR_CURSOR_ARROW;

    IntrPopCursorType();
    IntrEraseMessage();

    return RetVal;
}

/*****************************************************************************
* Routine to create a new copy of given struct.				     *
*****************************************************************************/
static DrawGenericStruct *CopyStructLocal(DrawGenericStruct *DrawStruct)
{
    DrawGenericStruct
        *NewDrawStruct = NULL;
    DrawPickedStruct *NewPickedItem,
	*PickedList = NULL,
	*LastPickedItem = NULL;

    switch (DrawStruct -> StructType) {
	case DRAW_POLYLINE_STRUCT_TYPE:
	    NewDrawStruct = (DrawGenericStruct *)
					 MyMalloc(sizeof(DrawPolylineStruct));
	    GEN_COPY(NewDrawStruct, DrawStruct, sizeof(DrawPolylineStruct));
	    ((DrawPolylineStruct *) NewDrawStruct) -> Points = (int *)
		MyMalloc(sizeof(int) * 2 *
			 ((DrawPolylineStruct *) DrawStruct) -> NumOfPoints);
	    GEN_COPY(((DrawPolylineStruct *) NewDrawStruct) -> Points,
		     ((DrawPolylineStruct *) DrawStruct) -> Points,
		     sizeof(int) * 2 *
			 ((DrawPolylineStruct *) DrawStruct) -> NumOfPoints);
	    break;
	case DRAW_CONNECTION_STRUCT_TYPE:
	    NewDrawStruct = (DrawGenericStruct *)
				       MyMalloc(sizeof(DrawConnectionStruct));
	    GEN_COPY(NewDrawStruct, DrawStruct, sizeof(DrawConnectionStruct));
	    break;
	case DRAW_TEXT_STRUCT_TYPE:
	    NewDrawStruct = (DrawGenericStruct *) MyMalloc(sizeof(DrawTextStruct));
	    GEN_COPY(NewDrawStruct, DrawStruct, sizeof(DrawTextStruct));
	    ((DrawTextStruct *) NewDrawStruct) -> Text =
		strdup(((DrawTextStruct *) DrawStruct) -> Text);
	    break;
	case DRAW_LIB_ITEM_STRUCT_TYPE:
	    NewDrawStruct = (DrawGenericStruct *)
					  MyMalloc(sizeof(DrawLibItemStruct));
	    GEN_COPY(NewDrawStruct, DrawStruct, sizeof(DrawLibItemStruct));
	    if (((DrawLibItemStruct *) DrawStruct) -> ChipName)
		(((DrawLibItemStruct *) NewDrawStruct) -> ChipName) =
		    strdup(((DrawLibItemStruct *) DrawStruct) -> ChipName);
	    if (((DrawLibItemStruct *) DrawStruct) -> PartName)
		(((DrawLibItemStruct *) NewDrawStruct) -> PartName) =
		    strdup(((DrawLibItemStruct *) DrawStruct) -> PartName);
	    break;
	case DRAW_PICK_ITEM_STRUCT_TYPE:
	    PickedList = (DrawPickedStruct *) DrawStruct;
	    while (PickedList) {
		NewPickedItem = (DrawPickedStruct *)
					   MyMalloc(sizeof(DrawPickedStruct));
		NewPickedItem -> StructType = DRAW_PICK_ITEM_STRUCT_TYPE;
		NewPickedItem -> Pnext = NULL;
		if (NewDrawStruct == NULL)
		    NewDrawStruct = (DrawGenericStruct *) NewPickedItem;
		if (LastPickedItem != NULL)
		    LastPickedItem -> Pnext = NewPickedItem;
		LastPickedItem = NewPickedItem;

		NewPickedItem -> PickedStruct =
		    CopyStructLocal(PickedList -> PickedStruct);

		PickedList = PickedList -> Pnext;
	    }
	    break;
    }

    return NewDrawStruct;
}

/*****************************************************************************
* Routine to delete a given struct.					     *
*****************************************************************************/
void FreeStruct(DrawGenericStruct *DrawStruct)
{
    DrawPickedStruct *PickedList, *PickedItem;

    switch (DrawStruct -> StructType) {
	case DRAW_POLYLINE_STRUCT_TYPE:
	    MyFree((VoidPtr) ((DrawPolylineStruct *) DrawStruct) -> Points);
	    MyFree((VoidPtr) DrawStruct);
	    break;
	case DRAW_CONNECTION_STRUCT_TYPE:
	    MyFree((VoidPtr) DrawStruct);
	    break;
	case DRAW_TEXT_STRUCT_TYPE:
	    MyFree((VoidPtr) ((DrawTextStruct *) DrawStruct) -> Text);
	    MyFree((VoidPtr) DrawStruct);
	    break;
	case DRAW_LIB_ITEM_STRUCT_TYPE:
	    if (((DrawLibItemStruct *) DrawStruct) -> ChipName)
		MyFree((VoidPtr) ((DrawLibItemStruct *) DrawStruct) -> ChipName);
	    if (((DrawLibItemStruct *) DrawStruct) -> PartName)
		MyFree((VoidPtr) ((DrawLibItemStruct *) DrawStruct) -> PartName);
	    MyFree((VoidPtr) DrawStruct);
	    break;
	case DRAW_PICK_ITEM_STRUCT_TYPE:
	    PickedList = (DrawPickedStruct *) DrawStruct;
	    while (PickedList) {
		PickedItem = PickedList;
		PickedList = PickedList -> Pnext;
		FreeStruct(PickedItem -> PickedStruct);
		MyFree((VoidPtr) PickedItem);
	    }
	    break;
    }
}

/*****************************************************************************
* Routine to pick a object from global drawing object list.		     *
*****************************************************************************/
DrawGenericStruct *PickStruct(char *Header, BooleanType OnlyLibItem)
{
    BooleanType Snapped, Draw = TRUE;
    int i, x, y, OrigX, OrigY, OrigXScrn, OrigYScrn, Event;
    DrawPickedStruct *DontPickList = NULL, *PickedList = NULL, *PickedItem;
    DrawGenericStruct *DrawStruct;

    IntrPushCursorType();
    Cursor.CursorType = INTR_CURSOR_CROSS;
    IntrSetCursorType(&Cursor);

    IntrDrawMessage(Header, EEPopUpForeColor, EEPopUpBackColor);

    if (IntrGetEventWaitSA(&OrigXScrn, &OrigYScrn) == INTR_EVNT_ABORT) {
	IntrPopCursorType();
	IntrEraseMessage();

	return NULL;
    }
    OrigX = OrigXScrn;
    OrigY = OrigYScrn;
    OrigX = EE_SNAP(GRInvMapX(OrigX));
    OrigY = EE_SNAP(GRInvMapY(OrigY));

    do {
	x = OrigX;
	y = OrigY;
	if ((Snapped = SnapPoint2(&x, &y, OnlyLibItem,
        	EEActiveWindow -> EEDrawList, DontPickList)) == FALSE) break;

	/* Lets see if the user likes this picked structure: */
	do {
	    Draw = !Draw;
	    RedrawOneStruct(LastSnappedStruct, GR_COPY_PUT,
			    Draw ? EE_DRAW_COLOR : EE_ERASE_COLOR);
	    delay(300);
	    Event = IntrGetTextEventNoWait();
	}
	while (Event != INTR_EVNT_ABORT && Event != INTR_EVNT_SELECT);
	if (!Draw) RedrawOneStruct(LastSnappedStruct, GR_COPY_PUT, EE_DRAW_COLOR);

	if (Event == INTR_EVNT_ABORT) {
	    /* Put this structure in the dont pick list, and try again: */
	    PickedItem = (DrawPickedStruct *) MyMalloc(sizeof(DrawPickedStruct));
	    PickedItem -> StructType = DRAW_PICK_ITEM_STRUCT_TYPE;
	    PickedItem -> PickedStruct = LastSnappedStruct;
	    PickedItem -> Pnext = DontPickList;
	    DontPickList = PickedItem;
	}
    } while (Event != INTR_EVNT_SELECT);

    if (DontPickList == NULL && !Snapped) {
	/*   Wait for the second points to define a box everything inside is */
	/* to considered picked.					     */
        Cursor.CursorType = INTR_CURSOR_BOX_LAST;
        Cursor.LastX = OrigXScrn;
        Cursor.LastY = OrigYScrn;
	IntrSetCursorType(&Cursor);
	if (IntrGetEventWaitSA(&x, &y) == INTR_EVNT_ABORT) {
	    IntrPopCursorType();
	    IntrEraseMessage();

	    return NULL;
	}
	x = EE_SNAP(GRInvMapX(x));
	y = EE_SNAP(GRInvMapY(y));
	if (x < OrigX) {
	    i = x;
	    x = OrigX;
	    OrigX = i;
	}
	if (y < OrigY) {
	    i = y;
	    y = OrigY;
	    OrigY = i;
	}

	for (DrawStruct = EEActiveWindow -> EEDrawList;
	     DrawStruct != NULL;
	     DrawStruct = DrawStruct -> Pnext) {
	    if (DrawStructInBox(OrigX, OrigY, x, y, DrawStruct)) {
		/* Put this structure in the picked list: */
		PickedItem = (DrawPickedStruct *)
		    MyMalloc(sizeof(DrawPickedStruct));
		PickedItem -> StructType = DRAW_PICK_ITEM_STRUCT_TYPE;
		PickedItem -> PickedStruct = DrawStruct;
		PickedItem -> Pnext = PickedList;
		PickedList = PickedItem;
	    }
	}

	IntrEraseMessage();
	IntrPopCursorType();

	if (PickedList && PickedList -> Pnext == NULL) {
	    /* Only one item was picked - convert to scalar form (no list): */
	    PickedItem = PickedList;
	    PickedList = (DrawPickedStruct *) PickedList -> PickedStruct;
	    MyFree((VoidPtr) PickedItem);
	}

	if (PickedList != NULL) {
	    PickedBoxMinX = OrigX;
	    PickedBoxMinY = OrigY;
	    PickedBoxMaxX = x;
	    PickedBoxMaxY = y;
	}

	return (DrawGenericStruct *) PickedList;
    }
    else {
	while (DontPickList) {
	    PickedItem = DontPickList;
	    DontPickList = DontPickList -> Pnext;
	    MyFree((VoidPtr) PickedItem);
	}

	IntrEraseMessage();
	IntrPopCursorType();

	return Snapped ? LastSnappedStruct : NULL;
    }
}

/*****************************************************************************
* Interface routine to snap a point relative to all structures defined.      *
*****************************************************************************/
BooleanType SnapPoint(int *OrigX, int *OrigY, BooleanType OnlyLibItem)
{
    return SnapPoint2(OrigX, OrigY, OnlyLibItem,
				         EEActiveWindow -> EEDrawList, NULL);
}

/*****************************************************************************
* Routine to search all objects for the closest point to a given point, in   *
* drawing space, and snap it to that points if closer than SnapDistance.     *
* Note we use L1 norm as distance measure, as it is the fastest.	     *
* This routine updates LastSnappedStruct to the last object used in to snap  *
* a point. This variable is global to this module only (see above).	     *
* If DontSnapList is not NULL, structes in this list are skipped.	     *
* The routine returns TRUE if point was snapped.			     *
* The points is also snapped to the EE_SNAP.				     *
*****************************************************************************/
BooleanType SnapPoint2(int *OrigX, int *OrigY, BooleanType OnlyLibItem,
		   DrawGenericStruct *DrawList, DrawPickedStruct *DontSnapList)
{
    int i, *Points, x = *OrigX, y = *OrigY, x1, y1, x2, y2, NumOfPoints2,
	ClosestX = 16383, ClosestY = 16383;
    unsigned int Dist, CrntDist = 16383;
    DrawPickedStruct *DontSnap;

    for (; DrawList != NULL; DrawList = DrawList -> Pnext) {
	/* Make sure this structure is NOT in the dont snap list: */
	for (DontSnap = DontSnapList;
	     DontSnap != NULL;
	     DontSnap = DontSnap -> Pnext)
	    if (DontSnap -> PickedStruct == DrawList) break;
	if (DontSnap -> PickedStruct == DrawList) continue;

	switch (DrawList -> StructType) {
	    case DRAW_POLYLINE_STRUCT_TYPE:
		if (OnlyLibItem) break;
		Points = ((DrawPolylineStruct *) DrawList) -> Points;
		NumOfPoints2 =
		    ((DrawPolylineStruct *) DrawList) -> NumOfPoints * 2;
		for (i = 0; i < NumOfPoints2; i += 2) {
		    Dist = ((unsigned int) ABS(Points[i] - x)) +
			   ((unsigned int) ABS(Points[i+1] - y));
		    if (CrntDist > Dist) {
			CrntDist = Dist;
			LastSnappedStruct = DrawList;
			ClosestX = Points[i];
			ClosestY = Points[i+1];
		    }
		    if (i < NumOfPoints2 - 2) {
			/* Maybe we should snap the point to the middle of   */
			/* the line instead.				     */
			if ((Points[i] > x && Points[i+2] < x) ||
			    (Points[i] < x && Points[i+2] > x)) {
			    /* X value in middle of current line segment: */
			    Dist = (unsigned int) ABS(Points[i+1] - y);
			    if (CrntDist > Dist) {
				CrntDist = Dist;
				LastSnappedStruct = DrawList;
				ClosestX = x;
				ClosestY = Points[i+1];
			    }
			}
			if ((Points[i+1] > y) && (Points[i+3] < y) ||
			    (Points[i+1] < y) && (Points[i+3] > y)) {
			    /* Y value in middle of current line segment: */
			    Dist = (unsigned int) ABS(Points[i] - x);
			    if (CrntDist > Dist) {
				CrntDist = Dist;
				LastSnappedStruct = DrawList;
				ClosestX = Points[i];
				ClosestY = y;
			    }
			}
		    }
		}
		break;
	    case DRAW_CONNECTION_STRUCT_TYPE:
		if (OnlyLibItem) break;
		Dist = ((unsigned int)
			ABS(((DrawConnectionStruct *) DrawList) -> PosX - x)) +
		       ((unsigned int)
			ABS(((DrawConnectionStruct *) DrawList) -> PosY - y));
		if (CrntDist > Dist) {
		    CrntDist = Dist;
		    LastSnappedStruct = DrawList;
		    ClosestX = ((DrawConnectionStruct *) DrawList) -> PosX;
		    ClosestY = ((DrawConnectionStruct *) DrawList) -> PosY;
		}
		break;
	    case DRAW_TEXT_STRUCT_TYPE:
		if (OnlyLibItem) break;
		if (((DrawTextStruct *) DrawList) -> Orient ==
							TEXT_ORIENT_HORIZ) {
		    x1 = GRMapX(((DrawTextStruct *) DrawList) -> PosX) -
			GRGetTextWidth(((DrawTextStruct *) DrawList) -> Text) / 2;
		    x2 = GRMapX(((DrawTextStruct *) DrawList) -> PosX) +
			GRGetTextWidth(((DrawTextStruct *) DrawList) -> Text) / 2;
		    y1 = GRMapY(((DrawTextStruct *) DrawList) -> PosY) -
			GRGetTextHeight(((DrawTextStruct *) DrawList) -> Text) / 2;
		    y2 = GRMapY(((DrawTextStruct *) DrawList) -> PosY) +
			GRGetTextHeight(((DrawTextStruct *) DrawList) -> Text) / 2;
		}
		else {
		    x1 = GRMapX(((DrawTextStruct *) DrawList) -> PosX) -
			GRGetTextHeight(((DrawTextStruct *) DrawList) -> Text) / 2;
		    x2 = GRMapX(((DrawTextStruct *) DrawList) -> PosX) +
			GRGetTextHeight(((DrawTextStruct *) DrawList) -> Text) / 2;
		    y1 = GRMapY(((DrawTextStruct *) DrawList) -> PosY) -
			GRGetTextWidth(((DrawTextStruct *) DrawList) -> Text) / 2;
		    y2 = GRMapY(((DrawTextStruct *) DrawList) -> PosY) +
			GRGetTextWidth(((DrawTextStruct *) DrawList) -> Text) / 2;
		}
		x1 = GRInvMapX(x1);
		x2 = GRInvMapX(x2);
		y1 = GRInvMapY(y1);
		y2 = GRInvMapY(y2);
		if (x >= x1 && x <= x2) {
		    if (y >= y1 && y <= y2)
			Dist = 0;
		    else
			Dist = MIN(ABS(y - y1), ABS(y - y2));
		}
		else if (y >= y1 && y <= y2) {
		    if (x >= x1 && x <= x2)
			Dist = 0;
		    else
			Dist = MIN(ABS(x - x1), ABS(x - x2));
		}
		else
		    Dist = 16363;
		if (CrntDist > Dist) {
		    CrntDist = Dist;
		    LastSnappedStruct = DrawList;
		    ClosestX = x + Dist;
		    ClosestY = y;
		}
		break;
	    case DRAW_LIB_ITEM_STRUCT_TYPE:
		/* Check this library item iff our point is in its bbox: */
		if (((DrawLibItemStruct *) DrawList) -> BBoxMinX -
							EESnapDistance <= x &&
		    ((DrawLibItemStruct *) DrawList) -> BBoxMaxX +
							EESnapDistance >= x &&
		    ((DrawLibItemStruct *) DrawList) -> BBoxMinY -
							EESnapDistance <= y &&
		    ((DrawLibItemStruct *) DrawList) -> BBoxMaxY +
							EESnapDistance >= y)
		    SnapLibItemPoint(x, y, &ClosestX, &ClosestY,
				     (DrawLibItemStruct *) DrawList);
		Dist = ((unsigned int) ABS(ClosestX - x)) +
		       ((unsigned int) ABS(ClosestY - y));
		if (CrntDist > Dist) {
		    CrntDist = Dist;
		    LastSnappedStruct = DrawList;
		}
		break;
	}
    }

    /* Lets find the euclidian L2 distance: */
    if (SQR(((double) ClosestX) - x) + SQR(((double) ClosestY) - y) <
	SQR(EESnapDistance)) {
	/* We snap the point, make sure it is on EE_SNAP boundary: */
	ClosestX = EE_SNAP(ClosestX);
	ClosestY = EE_SNAP(ClosestY);
	*OrigX = ClosestX;
	*OrigY = ClosestY;

	return TRUE;
    }
    else
	return FALSE;
}

/*****************************************************************************
* Routine to test if an object has non empty intersection with the box       *
* defined by x1/y1 and x2/y2 (x1 < x2, y1 < y2), and return TRUE if so. This *
* routine is used to pick all points in a given box.			     *
*****************************************************************************/
BooleanType DrawStructInBox(int x1, int y1, int x2, int y2,
						DrawGenericStruct *DrawStruct)
{
    int i, *Points, xt1, yt1, xt2, yt2, NumOfPoints2;

    switch (DrawStruct -> StructType) {
	    case DRAW_POLYLINE_STRUCT_TYPE:
		Points = ((DrawPolylineStruct *) DrawStruct) -> Points;
		NumOfPoints2 =
		    ((DrawPolylineStruct *) DrawStruct) -> NumOfPoints * 2;
		for (i = 0; i < NumOfPoints2; i += 2) {
		    if (Points[i] >= x1 && Points[i] <= x2 &&
			Points[i+1] >= y1 && Points[i+1] <=y2) return TRUE;
		}
		break;
	    case DRAW_CONNECTION_STRUCT_TYPE:
		if (((DrawConnectionStruct *) DrawStruct) -> PosX >= x1 &&
		    ((DrawConnectionStruct *) DrawStruct) -> PosX <= x2 &&
		    ((DrawConnectionStruct *) DrawStruct) -> PosY >= y1 &&
		    ((DrawConnectionStruct *) DrawStruct) -> PosY <= y2)
		    return TRUE;
		break;
	    case DRAW_TEXT_STRUCT_TYPE:
		if (((DrawTextStruct *) DrawStruct) -> Orient ==
							TEXT_ORIENT_HORIZ) {
		    xt1 = GRMapX(((DrawTextStruct *) DrawStruct) -> PosX) -
			GRGetTextWidth(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		    xt2 = GRMapX(((DrawTextStruct *) DrawStruct) -> PosX) +
			GRGetTextWidth(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		    yt1 = GRMapY(((DrawTextStruct *) DrawStruct) -> PosY) -
			GRGetTextHeight(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		    yt2 = GRMapY(((DrawTextStruct *) DrawStruct) -> PosY) +
			GRGetTextHeight(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		}
		else {
		    xt1 = GRMapX(((DrawTextStruct *) DrawStruct) -> PosX) -
			GRGetTextHeight(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		    xt2 = GRMapX(((DrawTextStruct *) DrawStruct) -> PosX) +
			GRGetTextHeight(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		    yt1 = GRMapY(((DrawTextStruct *) DrawStruct) -> PosY) -
			GRGetTextWidth(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		    yt2 = GRMapY(((DrawTextStruct *) DrawStruct) -> PosY) +
			GRGetTextWidth(((DrawTextStruct *) DrawStruct) ->
								  Text) / 2;
		}
		xt1 = GRInvMapX(xt1);
		xt2 = GRInvMapX(xt2);
		yt1 = GRInvMapY(yt1);
		yt2 = GRInvMapY(yt2);
		if ((xt1 >= x1 && xt1 <= x2 && yt1 >= y1 && yt1 <= y2) ||
		    (xt2 >= x1 && xt2 <= x2 && yt2 >= y1 && yt2 <= y2))
		    return TRUE;
		break;
	    case DRAW_LIB_ITEM_STRUCT_TYPE:
		/* Check this library item iff our point is in its bbox: */
		xt1 = ((DrawLibItemStruct *) DrawStruct) -> BBoxMinX;
		xt2 = ((DrawLibItemStruct *) DrawStruct) -> BBoxMaxX;
		yt1 = ((DrawLibItemStruct *) DrawStruct) -> BBoxMinY;
		yt2 = ((DrawLibItemStruct *) DrawStruct) -> BBoxMaxY;

		/* See if we can trivially reject using the bounding boxes,  */
		/* otherwise use the full power of the library to decide.    */
		if (!(xt1 > x2 || yt1 > y2 || xt2 < x1 || yt2 < y1) &&
		    LibItemInBox(x1, y1, x2, y2,
			(DrawLibItemStruct *) DrawStruct))
		    return TRUE;
		break;
    }

    return FALSE;
}
