/** \file cmisc.c
 * Handling of the 'Describe' dialog
 */

/*  XTrkCad - Model Railroad CAD
 *  Copyright (C) 2005 Dave Bullis
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "common.h"
#include "cundo.h"
#include "param.h"
#include "fileio.h"
#include "cselect.h"
#include "track.h"
#include "common-ui.h"
#include "draw.h"

EXPORT wIndex_t describeCmdInx;
EXPORT BOOL_T inDescribeCmd;

static track_p descTrk;
static descData_p descData;
static descUpdate_t descUpdateFunc;
static coOrd descOrig, descSize;
static POS_T descBorder;
static wDrawColor descColor = 0;
EXPORT BOOL_T descUndoStarted;
static BOOL_T descNeedDrawHilite;
static wWinPix_t describeW_posy;
static wWinPix_t describeCmdButtonEnd;

static wMenu_p descPopupM;

static unsigned int
editableLayerList[NUM_LAYERS];		/**< list of non-frozen layers */
static int * layerValue;								/**pointer to current Layer (int *) */

static paramFloatRange_t rdata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW };
static paramIntegerRange_t idata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW };
static paramTextData_t tdata = { 300, 150 };
static char * pivotLabels[] = { N_("First"), N_("Middle"), N_("End"), NULL };
static char * boxLabels[] = { "", NULL };
static paramData_t describePLs[] = {
#define I_FLOAT_0		(0)
	{ PD_FLOAT, NULL, "F1", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F2", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F3", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F4", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F5", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F6", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F7", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F8", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F9", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F10", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F11", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F12", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F13", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F14", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F15", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F16", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F17", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F18", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F19", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F20", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F21", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F22", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F23", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F24", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F25", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F26", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F27", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F28", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F29", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F30", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F31", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F32", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F33", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F34", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F35", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F36", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F37", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F38", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F39", PDO_NOPREF, &rdata },
	{ PD_FLOAT, NULL, "F40", PDO_NOPREF, &rdata },
#define I_FLOAT_N		I_FLOAT_0+40

#define I_LONG_0		I_FLOAT_N
	{ PD_LONG, NULL, "I1", PDO_NOPREF, &idata },
	{ PD_LONG, NULL, "I2", PDO_NOPREF, &idata },
	{ PD_LONG, NULL, "I3", PDO_NOPREF, &idata },
	{ PD_LONG, NULL, "I4", PDO_NOPREF, &idata },
	{ PD_LONG, NULL, "I5", PDO_NOPREF, &idata },
#define I_LONG_N		I_LONG_0+5

#define I_STRING_0		I_LONG_N
	{ PD_STRING, NULL, "S1", PDO_NOPREF, I2VP(300) },
	{ PD_STRING, NULL, "S2", PDO_NOPREF, I2VP(300) },
	{ PD_STRING, NULL, "S3", PDO_NOPREF, I2VP(300) },
	{ PD_STRING, NULL, "S4", PDO_NOPREF, I2VP(300) },
#define I_STRING_N		I_STRING_0+4

#define I_LAYER_0		I_STRING_N
	{ PD_DROPLIST, NULL, "Y1", PDO_NOPREF, I2VP(150), NULL, 0 },
#define I_LAYER_N		I_LAYER_0+1

#define I_COLOR_0		I_LAYER_N
	{ PD_COLORLIST, NULL, "C1", PDO_NOPREF, NULL, N_("Color"), BC_HORZ|BC_NOBORDER },
#define I_COLOR_N		I_COLOR_0+1

#define I_LIST_0		I_COLOR_N
	{ PD_DROPLIST, NULL, "L1", PDO_NOPREF, I2VP(150), NULL, 0 },
	{ PD_DROPLIST, NULL, "L2", PDO_NOPREF, I2VP(150), NULL, 0 },
	{ PD_DROPLIST, NULL, "L3", PDO_NOPREF, I2VP(150), NULL, 0 },
	{ PD_DROPLIST, NULL, "L4", PDO_NOPREF, I2VP(150), NULL, 0 },
#define I_LIST_N		I_LIST_0+4

#define I_EDITLIST_0	I_LIST_N
	{ PD_DROPLIST, NULL, "LE1", PDO_NOPREF, I2VP(150), NULL, BL_EDITABLE },
#define I_EDITLIST_N	I_EDITLIST_0+1

#define I_TEXT_0		I_EDITLIST_N
	{ PD_TEXT, NULL, "T1", PDO_NOPREF, &tdata, NULL, BT_HSCROLL },
#define I_TEXT_N		I_TEXT_0+1

#define I_PIVOT_0		I_TEXT_N
	{ PD_RADIO, NULL, "P1", PDO_NOPREF, pivotLabels, N_("Lock"), BC_HORZ|BC_NOBORDER, 0 },
#define I_PIVOT_N		I_PIVOT_0+1

#define I_TOGGLE_0      I_PIVOT_N
	{ PD_TOGGLE, NULL, "boxed1", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
	{ PD_TOGGLE, NULL, "boxed2", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
	{ PD_TOGGLE, NULL, "boxed3", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
	{ PD_TOGGLE, NULL, "boxed4", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
#define I_TOGGLE_N 		I_TOGGLE_0+4
};

static paramGroup_t describePG = { "describe", 0, describePLs, COUNT( describePLs ) };

/**
 * A mapping table is used to map the index in the dropdown list to the layer
 * number. While usually this is a 1:1 translation, the values differ if there
 * are frozen layer. Frozen layers are not shown in the dropdown list.
 */

void
CreateEditableLayersList()
{
	int i = 0;
	int j = 0;

	while (i < NUM_LAYERS) {
		if (!GetLayerFrozen(i)) {
			editableLayerList[j++] = i;
		}

		i++;
	}
}

/**
 * Search a layer in the list of editable layers.
 *
 * \param IN layer layer to search
 * \return the index into the list
 */

static int
SearchEditableLayerList(unsigned int layer)
{
	int i;

	for (i = 0; i < NUM_LAYERS; i++) {
		if (editableLayerList[i] == layer) {
			return (i);
		}
	}

	return (-1);
}

static void DrawDescHilite(BOOL_T selected)
{
	if (descNeedDrawHilite == FALSE) {
		return;
	}

	if (descColor==0) {
		descColor = wDrawColorGray(87);
	}
	DrawRectangle(&tempD, descOrig, descSize, selected?descColor:wDrawColorBlue,
	              DRAW_TRANSPARENT);
}



static void DescribeUpdate(
        paramGroup_p pg,
        int inx,
        void * data)
{
	coOrd hi, lo;
	descData_p ddp;

	if (inx < 0) {
		return;
	}

	ddp = (descData_p)pg->paramPtr[inx].context;

	if ((ddp->mode&(DESC_RO|DESC_IGNORE)) != 0) {
		return;
	}

	if (ddp->type == DESC_PIVOT) {
		return;
	}

	if (!descUndoStarted) {
		UndoStart(_("Change Track"), "Change Track");
		descUndoStarted = TRUE;
	}

	if (!descTrk) {
		return;    // In case timer pops after OK
	}

	UndoModify(descTrk);
	descUpdateFunc(descTrk, (int)(ddp-descData), descData, FALSE);

	if (descTrk) {
		GetBoundingBox(descTrk, &hi, &lo);
		if ((ddp->mode&DESC_NOREDRAW) == 0) {
			descOrig = lo;
			descSize = hi;
			descOrig.x -= descBorder;
			descOrig.y -= descBorder;
			descSize.x -= descOrig.x-descBorder;
			descSize.y -= descOrig.y-descBorder;
		}


		if (OFF_D(mapD.orig, mapD.size, descOrig, descSize)) {
			ErrorMessage(MSG_MOVE_OUT_OF_BOUNDS);
		}
	}


	for (inx = 0; inx < COUNT( describePLs ); inx++) {
		if ((describePLs[inx].option & PDO_DLGIGNORE) != 0) {
			continue;
		}

		ddp = (descData_p)describePLs[inx].context;

		if ((ddp->mode&DESC_IGNORE) != 0) {
			continue;
		}

		if ((ddp->mode&DESC_CHANGE) == 0) {
			if ((ddp->mode&DESC_CHANGE2) == 0) {
				continue;
			}
		}

		if (ddp->mode&DESC_RO) {
			wControlActive(ddp->control0, FALSE);
		} else {
			wControlActive(ddp->control0, TRUE);
		}

		ddp->mode &= ~DESC_CHANGE;
		if (ddp->type == DESC_POS) {			//POS Has two fields
			if (ddp->mode&DESC_CHANGE2) {
				ddp->mode &= ~DESC_CHANGE2;		//Second time
			} else {
				ddp->mode |= DESC_CHANGE2;		//First time
			}
		}

		ParamLoadControl(&describePG, inx);
	}
}


static void DescOk(void * junk)
{
	wHide(describePG.win);

	if (layerValue && *layerValue>=0) {
		SetTrkLayer(descTrk,
		            editableLayerList[*layerValue]);  //int found that is really in the parm controls.
	}
	layerValue = NULL; 									   // wipe out reference
	descUpdateFunc(descTrk, -1, descData, !descUndoStarted);
	descTrk = NULL;

	if (descUndoStarted) {
		UndoEnd();
		descUndoStarted = FALSE;
	}

	descNeedDrawHilite = FALSE;
	if (programMode == MODE_DESIGN) {
		Reset(); // DescOk
	} else {
		descNeedDrawHilite = FALSE;
		wSetCursor(mainD.d,defaultCursor);
	}
}


static struct {
	parameterType pd_type;
	long option;
	int first;
	int last;
} descTypeMap[] = {
	/*NULL*/		{ 0, 0 },
	/*POS*/			{ PD_FLOAT, PDO_DIM,   I_FLOAT_0, I_FLOAT_N },
	/*FLOAT*/		{ PD_FLOAT, 0,		   I_FLOAT_0, I_FLOAT_N },
	/*ANGLE*/		{ PD_FLOAT, PDO_ANGLE, I_FLOAT_0, I_FLOAT_N },
	/*LONG*/		{ PD_LONG,	0,		   I_LONG_0, I_LONG_N },
	/*COLOR*/		{ PD_LONG,	0,		   I_COLOR_0, I_COLOR_N },
	/*DIM*/			{ PD_FLOAT, PDO_DIM,   I_FLOAT_0, I_FLOAT_N },
	/*PIVOT*/		{ PD_RADIO, 0,		   I_PIVOT_0, I_PIVOT_N },
	/*LAYER*/		{ PD_DROPLIST,PDO_LISTINDEX,	   I_LAYER_0, I_LAYER_N },
	/*STRING*/		{ PD_STRING,0,		   I_STRING_0, I_STRING_N },
	/*TEXT*/		{ PD_TEXT,	PDO_DLGNOLABELALIGN, I_TEXT_0, I_TEXT_N },
	/*LIST*/		{ PD_DROPLIST, PDO_LISTINDEX,	   I_LIST_0, I_LIST_N },
	/*EDITABLELIST*/{ PD_DROPLIST, 0,	   I_EDITLIST_0, I_EDITLIST_N },
	/*BOXED*/      	{ PD_TOGGLE, 0,	       I_TOGGLE_0, I_TOGGLE_N },
};

/**
 * An unused param element is selected from the list of pre-defined param elements and initialized
 * for an element specific param.
 *
 * \param ddp Element specific param
 * \param valueP the value pointer used by the element
 * \param label the label assigned by the element
 * \param sep ?
 * \return the selected widget
 */

static wControl_p AssignParamToDescribeDialog(descData_p ddp, void * valueP,
                char * label,
                wWinPix_t sep)
{
	int inx;

	for (inx = descTypeMap[ddp->type].first; inx<descTypeMap[ddp->type].last;
	     inx++) {
		if ((describePLs[inx].option & PDO_DLGIGNORE) != 0) {
			describePLs[inx].option = descTypeMap[ddp->type].option;

			if (describeW_posy > describeCmdButtonEnd) {
				describePLs[inx].option |= PDO_DLGUNDERCMDBUTT;
			}

			if (sep) {
				describeW_posy += wControlGetHeight(describePLs[inx].control) + sep;
			}
			describePLs[inx].context = ddp;
			describePLs[inx].valueP = valueP;
			if ((ddp->type == DESC_STRING) && ddp->max_string) {
				describePLs[inx].max_string = ddp->max_string;
				describePLs[inx].option |= PDO_STRINGLIMITLENGTH;
			}

			if (label && ddp->type != DESC_TEXT) {
				wControlSetLabel(describePLs[inx].control, label);
				describePLs[inx].winLabel = label;
			} else {
				wControlSetLabel(describePLs[inx].control, "");
				describePLs[inx].winLabel = "";
			}

			return describePLs[inx].control;
		}
	}

	CHECKMSG( FALSE, ("AssignParamToDescribeDialog: can't find %d", ddp->type) );
	return NULL;
}


static void DescribeLayout(
        paramData_t * pd,
        int inx,
        wWinPix_t colX,
        wWinPix_t * x,
        wWinPix_t * y)
{
	descData_p ddp;
	wWinPix_t w, h;

	if (inx < 0) {
		return;
	}

	if (pd->context == NULL) {
		return;
	}

	ddp = (descData_p)pd->context;
	*y = ddp->posy;

	if (ddp->type == DESC_POS &&
	    ddp->control0 != pd->control) {
		*x += wControlGetWidth(pd->control) + 3;
	} else if (ddp->type == DESC_TEXT) {
		w = tdata.width;
		h = tdata.height;
		wTextSetSize((wText_p)pd->control, w, h);
	}

	wControlShow(pd->control, TRUE);
}


/**
 * Creation and modification of the Describe dialog box is handled here. As the number
 * of values for a track element depends on the specific type, this dialog is dynamically
 * updated to hsow the changable parameters only
 *
 * \param IN title Description of the selected part, shown in window title bar
 * \param IN trk Track element to be described
 * \param IN data
 * \param IN update
 *
 */

//static wList_p setLayerL;
void DoDescribe(char * title, track_p trk, descData_p data, descUpdate_t update)
{
	int inx;
	descData_p ddp;
	char * label;
	int ro_mode;

	if (!inDescribeCmd) {
		return;
	}

	CreateEditableLayersList();
	descTrk = trk;
	descData = data;
	descUpdateFunc = update;
	describeW_posy = 0;

	if (describePG.win == NULL) {
		/* SDB 5.13.2005 */
		ParamCreateDialog(&describePG, _("Description"), _("Done"), DescOk,
		                  (paramActionCancelProc) DescribeCancel,
		                  TRUE, DescribeLayout, F_RECALLPOS,
		                  DescribeUpdate);
		describeCmdButtonEnd = wControlBelow((wControl_p)describePG.helpB);
	}

	for (inx=0; inx<COUNT( describePLs ); inx++) {
		describePLs[inx].option = PDO_DLGIGNORE;
		wControlShow(describePLs[inx].control, FALSE);
	}

	ro_mode = (GetLayerFrozen(GetTrkLayer(trk))?DESC_RO:0);

	if (ro_mode)
		for (ddp=data; ddp->type != DESC_NULL; ddp++) {
			if (ddp->mode&DESC_IGNORE) {
				continue;
			}

			ddp->mode |= DESC_RO;
		}

	for (ddp=data; ddp->type != DESC_NULL; ddp++) {
		if (ddp->mode&DESC_IGNORE) {
			continue;
		}

		label = _(ddp->label);
		ddp->posy = describeW_posy;
		ddp->control0 = AssignParamToDescribeDialog(ddp, ddp->valueP, label, 3);
		if (ddp->type != DESC_LAYER) {
			wControlActive(ddp->control0, (!(ddp->mode&DESC_RO)));
		}

		switch (ddp->type) {
		case DESC_POS:
			ddp->control1 = AssignParamToDescribeDialog(ddp,
			                &((coOrd*)(ddp->valueP))->y,
			                NULL,
			                0);
			wControlActive(ddp->control1, (!(ddp->mode&DESC_RO)));
			break;

		case DESC_LAYER:
			wListClear((wList_p)ddp->control0);  // Rebuild list on each invocation

			if (ro_mode) {
				char *layerFormattedName;
				layerFormattedName = FormatLayerName(*(int *)(ddp->valueP));
				wListAddValue((wList_p)ddp->control0, layerFormattedName, NULL, I2VP(inx));
				free(layerFormattedName);
				*(int *)(ddp->valueP) = 0;
				layerValue = (int *)(ddp->valueP);
				wControlActive(ddp->control0, FALSE);
			} else {
				for (inx = 0; inx<NUM_LAYERS; inx++) {
					char *layerFormattedName;
					layerFormattedName = FormatLayerName(editableLayerList[inx]);
					wListAddValue((wList_p)ddp->control0, layerFormattedName, NULL, I2VP(inx));
					free(layerFormattedName);
				}

				*(int *)(ddp->valueP) = SearchEditableLayerList(*(int *)(ddp->valueP));
				layerValue = (int *)(ddp->valueP);
				wControlActive(ddp->control0, TRUE);
			}

			break;

		default:
			break;
		}
	}

	ParamLayoutDialog(&describePG);
	ParamLoadControls(&describePG);
	sprintf(message, "%s (T%d)", title, GetTrkIndex(trk));
	wWinSetTitle(describePG.win, message);
	wShow(describePG.win);
}


static void DescChange(long changes)
{
	if ((changes&CHANGE_UNITS) && describePG.win && wWinIsVisible(describePG.win)) {
		ParamLoadControls(&describePG);
	}
}

/*****************************************************************************
 *
 * SIMPLE DESCRIPTION
 *
 */


EXPORT void DescribeCancel(void)
{
	if (describePG.win && wWinIsVisible(describePG.win)) {
		if (descTrk) {
			CHECK(!IsTrackDeleted(descTrk));
			descUpdateFunc(descTrk, -1, descData, TRUE);
			descTrk = NULL;

		}

		wHide(describePG.win);

		if (descUndoStarted) {
			UndoEnd();
			descUndoStarted = FALSE;
		}
	}

	descNeedDrawHilite = FALSE;
}


EXPORT STATUS_T CmdDescribe(wAction_t action, coOrd pos)
{
	static track_p trk;
	char msg[STR_SIZE];

	switch (action) {
	case C_START:
		InfoMessage(_("Select track to describe +Shift for Frozen"));
		wSetCursor(mainD.d,wCursorQuestion);
		descUndoStarted = FALSE;
		trk = NULL;
		return C_CONTINUE;

	case wActionMove:
		trk = OnTrack(&pos, FALSE, FALSE);
		if (trk && GetLayerFrozen(GetTrkLayer(trk))
		    && !(MyGetKeyState() & WKEY_SHIFT)) {
			trk = NULL;
			return C_CONTINUE;
		}
		return C_CONTINUE;


	case C_DOWN:
		if ((trk = OnTrack(&pos, FALSE, FALSE)) != NULL) {
			if (GetLayerFrozen(GetTrkLayer(trk)) && !(MyGetKeyState()& WKEY_SHIFT)) {
				InfoMessage("Track is Frozen, Add Shift to Describe");
				trk = NULL;
				return C_CONTINUE;
			}
			if (describePG.win && wWinIsVisible(describePG.win) && descTrk) {
				descUpdateFunc(descTrk, -1, descData, TRUE);
				descTrk = NULL;
			}

			descBorder = mainD.scale*0.1;

			if (descBorder < trackGauge) {
				descBorder = trackGauge;
			}

			inDescribeCmd = TRUE;
			GetBoundingBox(trk, &descSize, &descOrig);
			descOrig.x -= descBorder;
			descOrig.y -= descBorder;
			descSize.x -= descOrig.x-descBorder;
			descSize.y -= descOrig.y-descBorder;
			descNeedDrawHilite = TRUE;
			DescribeTrack(trk, msg, 255);
			inDescribeCmd = FALSE;
			InfoMessage(msg);
			trk = NULL;
		} else {
			InfoMessage("");
		}

		return C_CONTINUE;

	case C_REDRAW:

		if (describePG.win && wWinIsVisible(describePG.win) && descTrk) {
			descNeedDrawHilite = TRUE;
			coOrd lo,hi;
			GetBoundingBox(descTrk,&hi,&lo);
			descOrig = lo;
			descSize = hi;
			descOrig.x -= descBorder;
			descOrig.y -= descBorder;
			descSize.x -= descOrig.x-descBorder;
			descSize.y -= descOrig.y-descBorder;

			DrawDescHilite(TRUE);

			if (descTrk && QueryTrack(descTrk, Q_IS_DRAW)) {
				DrawOriginAnchor(descTrk);
			}
		} else if (trk) {
			DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
		}


		break;

	case C_CANCEL:
		DescribeCancel();
		wSetCursor(mainD.d,defaultCursor);
		return C_CONTINUE;

	case C_CMDMENU:
		menuPos = pos;
		if (!trk) { wMenuPopupShow(descPopupM); }
		return C_CONTINUE;
	}


	return C_CONTINUE;
}



#include "bitmaps/describe.xpm3"

void InitCmdDescribe(wMenu_p menu)
{
	describeCmdInx = AddMenuButton(menu, CmdDescribe, "cmdDescribe",
	                               _("Properties"), wIconCreatePixMap(describe_xpm3[iconSize]),
	                               LEVEL0, IC_CANCEL|IC_POPUP|IC_WANT_MOVE|IC_CMDMENU, ACCL_DESCRIBE, NULL);
	RegisterChangeNotification(DescChange);
	ParamRegister(&describePG);
}
void InitCmdDescribe2(wMenu_p menu)
{
	descPopupM = MenuRegister( "Describe Context Menu" );
	wMenuPushCreate(descPopupM, "cmdSelectMode", GetBalloonHelpStr("cmdSelectMode"),
	                0, DoCommandB, I2VP(selectCmdInx));
	wMenuPushCreate(descPopupM, "cmdModifyMode", GetBalloonHelpStr("cmdModifyMode"),
	                0, DoCommandB, I2VP(modifyCmdInx));
	wMenuPushCreate(descPopupM, "cmdPanMode", GetBalloonHelpStr("cmdPanMode"), 0,
	                DoCommandB, I2VP(panCmdInx));

}