/** \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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "track.h" #include "common.h" #include "i18n.h" /***************************************************************************** * * DESCRIPTION WINDOW * */ 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; static BOOL_T descUndoStarted; static BOOL_T descNeedDrawHilite; static wPos_t describeW_posy; static wPos_t describeCmdButtonEnd; 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_("Second"), NULL }; static paramData_t describePLs[] = { #define I_FLOAT_0 (0) { PD_FLOAT, NULL, "F1", 0, &rdata }, { PD_FLOAT, NULL, "F2", 0, &rdata }, { PD_FLOAT, NULL, "F3", 0, &rdata }, { PD_FLOAT, NULL, "F4", 0, &rdata }, { PD_FLOAT, NULL, "F5", 0, &rdata }, { PD_FLOAT, NULL, "F6", 0, &rdata }, { PD_FLOAT, NULL, "F7", 0, &rdata }, { PD_FLOAT, NULL, "F8", 0, &rdata }, { PD_FLOAT, NULL, "F9", 0, &rdata }, { PD_FLOAT, NULL, "F10", 0, &rdata }, { PD_FLOAT, NULL, "F11", 0, &rdata }, { PD_FLOAT, NULL, "F12", 0, &rdata }, { PD_FLOAT, NULL, "F13", 0, &rdata }, { PD_FLOAT, NULL, "F14", 0, &rdata }, { PD_FLOAT, NULL, "F15", 0, &rdata }, { PD_FLOAT, NULL, "F16", 0, &rdata }, { PD_FLOAT, NULL, "F17", 0, &rdata }, { PD_FLOAT, NULL, "F18", 0, &rdata }, { PD_FLOAT, NULL, "F19", 0, &rdata }, { PD_FLOAT, NULL, "F20", 0, &rdata }, #define I_FLOAT_N I_FLOAT_0+20 #define I_LONG_0 I_FLOAT_N { PD_LONG, NULL, "I1", 0, &idata }, { PD_LONG, NULL, "I2", 0, &idata }, { PD_LONG, NULL, "I3", 0, &idata }, { PD_LONG, NULL, "I4", 0, &idata }, { PD_LONG, NULL, "I5", 0, &idata }, #define I_LONG_N I_LONG_0+5 #define I_STRING_0 I_LONG_N { PD_STRING, NULL, "S1", 0, (void*)300 }, { PD_STRING, NULL, "S2", 0, (void*)300 }, { PD_STRING, NULL, "S3", 0, (void*)300 }, { PD_STRING, NULL, "S4", 0, (void*)300 }, #define I_STRING_N I_STRING_0+4 #define I_LAYER_0 I_STRING_N { PD_DROPLIST, NULL, "Y1", 0, (void*)150, NULL, 0 }, #define I_LAYER_N I_LAYER_0+1 #define I_COLOR_0 I_LAYER_N { PD_COLORLIST, NULL, "C1", 0, NULL, N_("Color") }, #define I_COLOR_N I_COLOR_0+1 #define I_LIST_0 I_COLOR_N { PD_DROPLIST, NULL, "L1", 0, (void*)150, NULL, 0 }, { PD_DROPLIST, NULL, "L2", 0, (void*)150, NULL, 0 }, #define I_LIST_N I_LIST_0+2 #define I_EDITLIST_0 I_LIST_N { PD_DROPLIST, NULL, "LE1", 0, (void*)150, NULL, BL_EDITABLE }, #define I_EDITLIST_N I_EDITLIST_0+1 #define I_TEXT_0 I_EDITLIST_N { PD_TEXT, NULL, "T1", 0, &tdata }, #define I_TEXT_N I_TEXT_0+1 #define I_PIVOT_0 I_TEXT_N { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 } #define I_PIVOT_N I_PIVOT_0+1 }; static paramGroup_t describePG = { "describe", 0, describePLs, sizeof describePLs/sizeof describePLs[0] }; static void DrawDescHilite( void ) { wPos_t x, y, w, h; if ( descNeedDrawHilite == FALSE ) return; if (descColor==0) descColor = wDrawColorGray(87); w = (wPos_t)((descSize.x/mainD.scale)*mainD.dpi+0.5); h = (wPos_t)((descSize.y/mainD.scale)*mainD.dpi+0.5); mainD.CoOrd2Pix(&mainD,descOrig,&x,&y); wDrawFilledRectangle( mainD.d, x, y, w, h, descColor, wDrawOptTemp ); } 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 ( (ddp->mode&DESC_NOREDRAW) == 0 ) DrawDescHilite(); if ( !descUndoStarted ) { UndoStart( _("Change Track"), "Change Track" ); descUndoStarted = TRUE; } UndoModify( descTrk ); descUpdateFunc( descTrk, ddp-descData, descData, FALSE ); if ( descTrk ) { GetBoundingBox( descTrk, &hi, &lo ); if ( OFF_D( mapD.orig, mapD.size, descOrig, descSize ) ) { ErrorMessage( MSG_MOVE_OUT_OF_BOUNDS ); } } 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; DrawDescHilite(); } for ( inx = 0; inx < sizeof describePLs/sizeof describePLs[0]; 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 ) continue; ddp->mode &= ~DESC_CHANGE; ParamLoadControl( &describePG, inx ); } } static void DescOk( void * junk ) { wHide( describePG.win ); if ( descTrk ) DrawDescHilite(); descUpdateFunc( descTrk, -1, descData, !descUndoStarted ); descTrk = NULL; if (descUndoStarted) { UndoEnd(); descUndoStarted = FALSE; } descNeedDrawHilite = FALSE; Reset(); } 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 } }; static wControl_p AllocateButt( descData_p ddp, void * valueP, char * label, wPos_t sep ) { int inx; for ( inx = descTypeMap[ddp->type].first; inxtype].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; describeW_posy += wControlGetHeight( describePLs[inx].control ) + sep; describePLs[inx].context = ddp; describePLs[inx].valueP = valueP; if ( label && ddp->type != DESC_TEXT ) { wControlSetLabel( describePLs[inx].control, label ); describePLs[inx].winLabel = label; } return describePLs[inx].control; } } AbortProg( "allocateButt: can't find %d", ddp->type ); return NULL; } static void DescribeLayout( paramData_t * pd, int inx, wPos_t colX, wPos_t * x, wPos_t * y ) { descData_p ddp; wPos_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 ) { *y += wControlGetHeight( 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; 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; inxtype != DESC_NULL; ddp++ ) { if ( ddp->mode&DESC_IGNORE ) continue; ddp->mode |= ro_mode; } for ( ddp=data; ddp->type != DESC_NULL; ddp++ ) { if ( ddp->mode&DESC_IGNORE ) continue; label = _(ddp->label); ddp->posy = describeW_posy; ddp->control0 = AllocateButt( ddp, ddp->valueP, label, (ddp->type == DESC_POS?3:3) ); wControlActive( ddp->control0, ((ddp->mode|ro_mode)&DESC_RO)==0 ); switch (ddp->type) { case DESC_POS: ddp->control1 = AllocateButt( ddp, &((coOrd*)(ddp->valueP))->y, "Y", 3 ); wControlActive( ddp->control1, ((ddp->mode|ro_mode)&DESC_RO)==0 ); break; case DESC_LAYER: wListClear((wList_p)ddp->control0); // Rebuild list on each invovation for ( inx = 0; inxcontrol0, message, NULL, (void*)(intptr_t)inx ); } } 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 ) { descUpdateFunc( descTrk, -1, descData, TRUE ); descTrk = NULL; DrawDescHilite(); } wHide( describePG.win ); if ( descUndoStarted ) { UndoEnd(); descUndoStarted = FALSE; } } descNeedDrawHilite = FALSE; } static STATUS_T CmdDescribe( wAction_t action, coOrd pos ) { track_p trk; char msg[STR_SIZE]; switch (action) { case C_START: InfoMessage( _("Select track to describe") ); descUndoStarted = FALSE; return C_CONTINUE; case C_DOWN: if ((trk = OnTrack( &pos, FALSE, FALSE )) != NULL) { if ( describePG.win && wWinIsVisible(describePG.win) && descTrk ) { DrawDescHilite(); 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; DrawDescHilite(); DescribeTrack( trk, msg, 255 ); inDescribeCmd = FALSE; InfoMessage( msg ); } else InfoMessage( "" ); return C_CONTINUE; case C_REDRAW: if (describePG.win && wWinIsVisible(describePG.win) && descTrk) DrawDescHilite(); break; case C_CANCEL: DescribeCancel(); return C_CONTINUE; } return C_CONTINUE; } #include "bitmaps/describe.xpm" void InitCmdDescribe( wMenu_p menu ) { describeCmdInx = AddMenuButton( menu, CmdDescribe, "cmdDescribe", _("Properties"), wIconCreatePixMap(describe_xpm), LEVEL0, IC_CANCEL|IC_POPUP, ACCL_DESCRIBE, NULL ); RegisterChangeNotification( DescChange ); ParamRegister( &describePG ); /*AddPlaybackProc( "DESCRIBE", playbackDescribe, NULL );*/ }