diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2016-12-28 16:52:56 +0100 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2016-12-28 16:52:56 +0100 |
commit | 7b358424ebad9349421acd533c2fa1cbf6cf3e3e (patch) | |
tree | 686678532eefed525c242fd214d0cfb2914726c5 /app/bin/dcar.c |
Initial import of xtrkcad version 1:4.0.2-2
Diffstat (limited to 'app/bin/dcar.c')
-rw-r--r-- | app/bin/dcar.c | 5150 |
1 files changed, 5150 insertions, 0 deletions
diff --git a/app/bin/dcar.c b/app/bin/dcar.c new file mode 100644 index 0000000..2bbf728 --- /dev/null +++ b/app/bin/dcar.c @@ -0,0 +1,5150 @@ +/* + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/dcar.c,v 1.6 2008-03-06 19:35:07 m_fischer Exp $ + * + * TRAIN + * + */ + +/* 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. + */ + +#ifndef WINDOWS +#include <errno.h> +#endif +#include <ctype.h> + +#include <stdint.h> + +#include "track.h" +#include "ctrain.h" +#include "i18n.h" +#include "fileio.h" + +static int log_carList; +static int log_carInvList; +static int log_carDlgState; +static int log_carDlgList; + +static paramFloatRange_t r0_99999 = { 0, 99999, 80 }; +static paramIntegerRange_t i1_999999999 = { 1, 999999999, 80, PDO_NORANGECHECK_HIGH }; +static paramIntegerRange_t i1_9999 = { 1, 9999, 50 }; +static char * isLocoLabels[] = { "", 0 }; +static char * cplrModeLabels[] = { N_("Truck"), N_("Body"), 0 }; +static BOOL_T carProtoListChanged; +static void CarInvListAdd( carItem_p item ); +static void CarInvListUpdate( carItem_p item ); + +#define T_MANUF (0) +#define T_PROTO (1) +#define T_DESC (2) +#define T_PART (3) +#define T_ROADNAME (4) +#define T_REPMARK (5) +#define T_NUMBER (6) + +typedef struct { + char * name; + long value; + } nameLongMap_t; + + +#define CAR_DESC_COUPLER_MODE_BODY (1L<<0) +#define CAR_DESC_IS_LOCO (1L<<1) +#define CAR_DESC_IS_LOCO_MASTER (1L<<2) +#define CAR_ITEM_HASNOTES (1L<<8) +#define CAR_ITEM_ONLAYOUT (1L<<9) + +#define CAR_DESC_BITS (0x000000FF) +#define CAR_ITEM_BITS (0x0000FF00) + + +typedef struct carProto_t * carProto_p; + +typedef struct { + DIST_T carLength; + DIST_T carWidth; + DIST_T truckCenter; + DIST_T coupledLength; + } carDim_t; +typedef struct { + char * number; + FLOAT_T purchPrice; + FLOAT_T currPrice; + long condition; + long purchDate; + long serviceDate; + char * notes; + } carData_t; + +struct carItem_t { + long index; + SCALEINX_T scaleInx; + char * contentsLabel; + char * title; + carProto_p proto; + DIST_T barScale; + wDrawColor color; + long options; + long type; + carDim_t dim; + carData_t data; + wIndex_t segCnt; + trkSeg_p segPtr; + track_p car; + coOrd pos; + ANGLE_T angle; + }; + + +/* + * Utilities + */ + + + +typedef struct { + char * ptr; + int len; + } tabString_t, *tabString_p; + + +static void TabStringExtract( + char * string, + int count, + tabString_t * tabs ) +{ + int inx; + char * next = string; + + for ( inx=0; inx<count; inx++ ) { + tabs[inx].ptr = string; + if ( next ) + next = strchr( string, '\t' ); + if ( next ) { + tabs[inx].len = next-string; + string = next+1; + } else { + tabs[inx].len = strlen( string ); + string += tabs[inx].len; + } + } + if ( tabs[T_MANUF].len == 0 ) { + tabs[T_MANUF].len = 7; + tabs[T_MANUF].ptr = N_("Unknown"); + } +} + + +static char * TabStringDup( + tabString_t * tab ) +{ + char * ret; + ret = MyMalloc( tab->len+1 ); + memcpy( ret, tab->ptr, tab->len ); + ret[tab->len] = '\0'; + return ret; +} + + +static char * TabStringCpy( + char * dst, + tabString_t * tab ) +{ + memcpy( dst, tab->ptr, tab->len ); + dst[tab->len] = '\0'; + return dst+tab->len; +} + + +static int TabStringCmp( + char * src, + tabString_t * tab ) +{ + int srclen = strlen(src); + int len = srclen; + int rc; + if ( len > tab->len ) + len = tab->len; + rc = strncasecmp( src, tab->ptr, len ); + if ( rc != 0 || srclen == tab->len ) + return rc; + else if ( srclen > tab->len ) + return 1; + else + return -1; +} + + +static long TabGetLong( + tabString_t * tab ) +{ + char old_c; + long val; + if ( tab->len <= 0 ) + return 0; + old_c = tab->ptr[tab->len]; + tab->ptr[tab->len] = '\0'; + val = atol( tab->ptr ); + tab->ptr[tab->len] = old_c; + return val; +} + + +static FLOAT_T TabGetFloat( + tabString_t * tab ) +{ + char old_c; + FLOAT_T val; + if ( tab->len <= 0 ) + return 0.0; + old_c = tab->ptr[tab->len]; + tab->ptr[tab->len] = '\0'; + val = atof( tab->ptr ); + tab->ptr[tab->len] = old_c; + return val; +} + + +static void RotatePts( + int cnt, + coOrd * pts, + coOrd orig, + ANGLE_T angle ) +{ + int inx; + for ( inx=0; inx<cnt; inx++ ) { + Rotate( &pts[inx], orig, angle ); + } +} + + +static void RescalePts( + int cnt, + coOrd * pts, + FLOAT_T scale_x, + FLOAT_T scale_y ) +{ + int inx; + for ( inx=0; inx<cnt; inx++ ) { + pts[inx].x *= scale_x; + pts[inx].y *= scale_y; + } +} + + +static int lookupListIndex; +static void * LookupListElem( + dynArr_t * da, + void * key, + int (*cmpFunc)( void *, void * ), + int elem_size ) +{ + int hi, lo, mid, rc; + lo = 0; + hi = da->cnt-1; + while (lo <= hi ) { + mid = (lo+hi)/2; + rc = cmpFunc( key, DYNARR_N(void*,*da,mid) ); + if ( rc == 0 ) { + lookupListIndex = mid; + return DYNARR_N(void*,*da,mid); + } + if ( rc > 0 ) + lo = mid+1; + else + hi = mid-1; + } + if ( elem_size == 0 ) { + lookupListIndex = -1; + return NULL; + } + DYNARR_APPEND( void*, *da, 10 ); + for ( mid=da->cnt-1; mid>lo; mid-- ) + DYNARR_N(void*,*da,mid) = DYNARR_N(void*,*da,mid-1); + DYNARR_N(void*,*da,lo) = (void*)MyMalloc(elem_size); + memset( DYNARR_N(void*,*da,lo), 0, elem_size ); + lookupListIndex = lo; + return DYNARR_N(void*,*da,lo); +} + +static void RemoveListElem( + dynArr_t * da, + void * elem ) +{ + int inx; + for ( inx=0; inx<da->cnt; inx++ ) + if ( DYNARR_N(void*,*da,inx) == elem ) + break; + if ( inx>=da->cnt ) + AbortProg( "removeListElem" ); + for ( inx++; inx<da->cnt; inx++ ) + DYNARR_N(void*,*da,inx-1) = DYNARR_N(void*,*da,inx); + da->cnt--; +} + +/* + * Draw Car Parts + */ + + +#define BW (8) +#define TW (45) +#define SI (30) +#define SO (37) +static coOrd truckOutline[] = { + { -TW, -SO }, + { TW, -SO }, + { TW, -SI }, + { BW, -SI }, + { BW, SI }, + { TW, SI }, + { TW, SO }, + { -TW, SO }, + { -TW, SI }, + { -BW, SI }, + { -BW, -SI }, + { -TW, -SI } }; +#define WO ((56.6-2)/2) +#define WI ((56.6-12)/2) +#define Wd (36/2) +#define AW (8/2) +static coOrd wheelOutline[] = { + { -Wd, -WO }, + + { -AW, -WO }, + { -AW, -SI }, + { AW, -SI }, + { AW, -WO }, + + { Wd, -WO }, + { Wd, -WI }, + { AW, -WI }, + { AW, WI }, + { Wd, WI }, + { Wd, WO }, + + { AW, WO }, + { AW, SI }, + { -AW, SI }, + { -AW, WO }, + + { -Wd, WO }, + { -Wd, WI }, + { -AW, WI }, + { -AW, -WI }, + + { -Wd, -WI } }; + +static void MovePts( + int cnt, + coOrd * pts, + coOrd orig ) +{ + int inx; + for ( inx=0; inx<cnt; inx++ ) { + pts[inx].x += orig.x; + pts[inx].y += orig.y; + } +} + + +static void CarProtoDrawTruck( + drawCmd_t * d, + DIST_T width, + FLOAT_T ratio, + coOrd pos, + ANGLE_T angle ) +{ + coOrd p[24], pp; + wDrawColor color = wDrawColorBlack; + + memcpy( p, truckOutline, sizeof truckOutline ); + RescalePts( sizeof truckOutline/sizeof truckOutline[0], p, 1.0, width/56.5 ); + RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, ratio, ratio ); + RotatePts( sizeof wheelOutline/sizeof wheelOutline[0], p, zero, angle ); + MovePts( sizeof truckOutline/sizeof truckOutline[0], p, pos ); + DrawFillPoly( d, sizeof truckOutline/sizeof truckOutline[0], p, color ); + pp.x = -70/2; + pp.y = 0; + memcpy( p, wheelOutline, sizeof wheelOutline ); + RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, 1.0, width/56.5 ); + MovePts( sizeof wheelOutline/sizeof wheelOutline[0], p, pp ); + RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, ratio, ratio ); + RotatePts( sizeof wheelOutline/sizeof wheelOutline[0], p, zero, angle ); + MovePts( sizeof wheelOutline/sizeof wheelOutline[0], p, pos ); + DrawFillPoly( d, sizeof wheelOutline/sizeof wheelOutline[0], p, color ); + pp.x = 70/2; + memcpy( p, wheelOutline, sizeof wheelOutline ); + RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, 1.0, width/56.5 ); + MovePts( sizeof wheelOutline/sizeof wheelOutline[0], p, pp ); + RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, ratio, ratio ); + RotatePts( sizeof wheelOutline/sizeof wheelOutline[0], p, zero, angle ); + MovePts( sizeof wheelOutline/sizeof wheelOutline[0], p, pos ); + DrawFillPoly( d, sizeof wheelOutline/sizeof wheelOutline[0], p, color ); +} + + +static coOrd couplerOutline[] = { + { 0, 2.5 }, + { 0, -2.5 }, + { 0, -2.5 }, + { 3, -7 }, + { 14, -5 }, + { 14, 2 }, + { 12, 2 }, + { 12, -2 }, + { 9, -2 }, + { 9, 3 }, + { 13, 6 }, + { 13, 7 }, + { 6, 7 }, + { 0, 2.5 } }; +static void CarProtoDrawCoupler( + drawCmd_t * d, + DIST_T length, + FLOAT_T ratio, + coOrd pos, + ANGLE_T angle ) +{ + coOrd p[24], pp; + wDrawColor color = wDrawColorBlack; + + length /= ratio; + if ( length < 12.0 ) + return; + memcpy( p, couplerOutline, sizeof couplerOutline ); + p[0].x = p[1].x = -(length-12.0); + pp.x = length-12.0; + pp.y = 0; +/* TODO - if length > 6 then draw Sills */ +#ifdef FUTURE + if ( angle == 270.0 ) { + pos.x -= (length-12.0); + for ( inx=0; inx<sizeof couplerOutline/sizeof couplerOutline[0]; inx++ ) { + p[inx].x = -p[inx].x; + p[inx].y = -p[inx].y; + } + } else { + pos.x += (length-12.0); + } +#endif + MovePts( sizeof couplerOutline/sizeof couplerOutline[0], p, pp ); + RescalePts( sizeof couplerOutline/sizeof couplerOutline[0], p, ratio, ratio ); + RotatePts( sizeof couplerOutline/sizeof couplerOutline[0], p, zero, angle-90.0 ); + MovePts( sizeof couplerOutline/sizeof couplerOutline[0], p, pos ); + DrawFillPoly( d, sizeof couplerOutline/sizeof couplerOutline[0], p, color ); +} + + + +/* + * Car Proto + */ + + +struct carProto_t; +typedef struct carProto_t carProto_t; + +struct carProto_t { + char * contentsLabel; + wIndex_t paramFileIndex; + char * desc; + long options; + long type; + carDim_t dim; + int segCnt; + trkSeg_p segPtr; + coOrd size; + coOrd orig; + }; + +static dynArr_t carProto_da; +#define carProto(N) DYNARR_N( carProto_t*, carProto_da, N ) + +#define N_TYPELISTMAP (7) +static nameLongMap_t typeListMap[N_TYPELISTMAP] = { + { N_("Diesel Loco"), 10101 }, + { N_("Steam Loco"), 10201 }, + { N_("Elect Loco"), 10301 }, + { N_("Freight Car"), 30100 }, + { N_("Psngr Car"), 50100 }, + { N_("M-O-W"), 70100 }, + { N_("Other"), 90100 } }; + +static trkSeg_p carProtoSegPtr; +static int carProtoSegCnt; + + +static coOrd dummyOutlineSegPts[5]; +static trkSeg_t dummyOutlineSegs; +static void CarProtoDlgCreateDummyOutline( + int * segCntP, + trkSeg_p * segPtrP, + BOOL_T isLoco, + DIST_T length, + DIST_T width, + wDrawColor color ) +{ + trkSeg_p segPtr; + coOrd * pts; + DIST_T length2; + + *segCntP = 1; + segPtr = *segPtrP = &dummyOutlineSegs; + + segPtr->type = SEG_FILPOLY; + segPtr->color = color; + segPtr->width = 0; + segPtr->u.p.cnt = isLoco?5:4; + segPtr->u.p.pts = pts = dummyOutlineSegPts; + segPtr->u.p.orig.x = 0; + segPtr->u.p.orig.y = 0; + segPtr->u.p.angle = 0; + length2 = length; + if ( isLoco ) { + pts->x = length; + pts->y = width/2.0; + pts++; + length2 -= width/2.0; + } + pts->x = length2; + pts->y = 0.0; + pts++; + pts->x = 0.0; + pts->y = 0.0; + pts++; + pts->x = 0.0; + pts->y = width; + pts++; + pts->x = length2; + pts->y = width; +} + + +static int CarProtoFindTypeCode( + long code ) +{ + int inx; + for ( inx=0; inx<N_TYPELISTMAP; inx++ ) { + if ( typeListMap[inx].value > code ) { + if ( inx == 0 ) + return N_TYPELISTMAP-1; + else + return inx-1; + } + } + return N_TYPELISTMAP-1; +} + + +static int CmpCarProto( + void * key, + void * elem ) +{ + char * key_val=key; + carProto_p elem_val=elem; + return strcasecmp( key_val, elem_val->desc ); +} + + +static carProto_p CarProtoFind( + char * desc ) +{ + return LookupListElem( &carProto_da, desc, CmpCarProto, 0 ); +} + + +static carProto_p CarProtoLookup( + char * desc, + BOOL_T createMissing, + BOOL_T isLoco, + DIST_T length, + DIST_T width ) +{ + carProto_p proto; + trkSeg_p segPtr; + proto = LookupListElem( &carProto_da, desc, CmpCarProto, createMissing?sizeof *proto:0 ); + if ( proto == NULL ) + return NULL; + if ( proto->desc == NULL ) { + proto->desc = MyStrdup(desc); + proto->contentsLabel = "Car Prototype"; + proto->paramFileIndex = PARAM_LAYOUT; + proto->options = (isLoco?CAR_DESC_IS_LOCO:0); + proto->dim.carLength = length; + proto->dim.carWidth = width; + proto->dim.truckCenter = length - 2.0*59.0; + proto->dim.coupledLength = length + 2.0*16.0; + CarProtoDlgCreateDummyOutline( &proto->segCnt, &segPtr, isLoco, length, width, drawColorBlue ); + proto->segPtr = (trkSeg_p)memdup( segPtr, (sizeof *(trkSeg_p)0) * proto->segCnt ); + CloneFilledDraw( proto->segCnt, proto->segPtr, FALSE ); + GetSegBounds( zero, 0.0, proto->segCnt, proto->segPtr, &proto->orig, &proto->size ); + carProtoListChanged = TRUE; + } + return proto; +} + + +static carProto_p CarProtoNew( + carProto_p proto, + int paramFileIndex, + char * desc, + long options, + long type, + carDim_t * dim, + wIndex_t segCnt, + trkSeg_p segPtr ) +{ + if ( proto == NULL ) { + proto = LookupListElem( &carProto_da, desc, CmpCarProto, sizeof *(carProto_p)0 ); + if ( proto->desc != NULL ) { + if ( proto->paramFileIndex == PARAM_CUSTOM && + paramFileIndex != PARAM_CUSTOM ) + return proto; + } + } + if ( proto->desc != NULL ) { + MyFree( proto->desc ); + } + proto->desc = MyStrdup(desc); + proto->contentsLabel = "Car Prototype"; + proto->paramFileIndex = paramFileIndex; + proto->options = options; + proto->type = type; + proto->dim = *dim; + proto->segCnt = segCnt; + proto->segPtr = (trkSeg_p)memdup( segPtr, (sizeof *(trkSeg_p)0) * proto->segCnt ); + CloneFilledDraw( proto->segCnt, proto->segPtr, FALSE ); + GetSegBounds( zero, 0.0, proto->segCnt, proto->segPtr, &proto->orig, &proto->size ); + carProtoListChanged = TRUE; + return proto; +} + + +static void CarProtoDelete( + carProto_p protoP ) +{ + if ( protoP == NULL ) + return; + RemoveListElem( &carProto_da, protoP ); + if ( protoP->desc ) + MyFree( protoP->desc ); + MyFree( protoP ); +} + + +static BOOL_T CarProtoRead( + char * line ) +{ + char * desc; + long options; + long type; + carDim_t dim; + + if ( !GetArgs( line+9, "qllff00ff", + &desc, &options, &type, &dim.carLength, &dim.carWidth, &dim.truckCenter, &dim.coupledLength ) ) + return FALSE; + if ( !ReadSegs() ) + return FALSE; + CarProtoNew( NULL, curParamFileIndex, desc, options, type, &dim, tempSegs_da.cnt, &tempSegs(0) ); + return TRUE; +} + + +static BOOL_T CarProtoWrite( + FILE * f, + carProto_t * proto ) +{ + BOOL_T rc = TRUE; + char *oldLocale = NULL; + + oldLocale = SaveLocale("C"); + + rc &= fprintf( f, "CARPROTO \"%s\" %ld %ld %0.3f %0.3f 0 0 %0.3f %0.3f\n", + PutTitle(proto->desc), proto->options, proto->type, proto->dim.carLength, proto->dim.carWidth, proto->dim.truckCenter, proto->dim.coupledLength )>0; + rc &= WriteSegs( f, proto->segCnt, proto->segPtr ); + + RestoreLocale(oldLocale); + + return rc; +} + + + +static BOOL_T CarProtoCustomSave( + FILE * f ) +{ + int inx; + carProto_t * proto; + BOOL_T rc = TRUE; + + for ( inx=0; inx<carProto_da.cnt; inx++ ) { + proto = carProto(inx); + if ( proto->paramFileIndex == PARAM_CUSTOM ) + rc &= CarProtoWrite( f, proto ); + } + return rc; +} + + +/* + * Car Desc + */ + +struct carPart_t; +typedef struct carPart_t carPart_t; +typedef carPart_t * carPart_p; +struct carPartParent_t; +typedef struct carPartParent_t carPartParent_t; +typedef carPartParent_t * carPartParent_p; + +typedef struct { + char * name; + int len; + } cmp_key_t; + +typedef struct { + tabString_t manuf; + tabString_t proto; + SCALEINX_T scale; + } cmp_partparent_t; +struct carPartParent_t { + char * manuf; + char * proto; + SCALEINX_T scale; + dynArr_t parts_da; + }; +struct carPart_t { + carPartParent_p parent; + wIndex_t paramFileIndex; + char * title; + long options; + long type; + carDim_t dim; + wDrawColor color; + char * partnoP; + int partnoL; + }; +static dynArr_t carPartParent_da; +#define carPartParent(N) DYNARR_N(carPartParent_p, carPartParent_da, N) +#define carPart(P,N) DYNARR_N(carPart_p, (P)->parts_da, N) +struct roadnameMap_t; +typedef struct roadnameMap_t roadnameMap_t; +typedef roadnameMap_t * roadnameMap_p; +struct roadnameMap_t { + char * roadname; + char * repmark; + }; +static dynArr_t roadnameMap_da; +#define roadnameMap(N) DYNARR_N(roadnameMap_p, roadnameMap_da, N) +static BOOL_T roadnameMapChanged; +static long carPartChangeLevel = 0; + + + +static int Cmp_part( + void * key, + void * elem ) +{ + carPart_p cmp_key=key; + carPart_p part_elem=elem; + int rc; + int len; + + len = min( cmp_key->partnoL, part_elem->partnoL ); + rc = strncasecmp( cmp_key->partnoP, part_elem->partnoP, len+1 ); + if ( rc != 0 ) + return rc; + if ( cmp_key->paramFileIndex == part_elem->paramFileIndex ) + return 0; + if ( cmp_key->paramFileIndex == PARAM_DEMO ) + return -1; + if ( part_elem->paramFileIndex == PARAM_DEMO ) + return 1; + if ( cmp_key->paramFileIndex == PARAM_CUSTOM ) + return -1; + if ( part_elem->paramFileIndex == PARAM_CUSTOM ) + return 1; + if ( cmp_key->paramFileIndex == PARAM_LAYOUT ) + return 1; + if ( part_elem->paramFileIndex == PARAM_LAYOUT ) + return -1; + if ( cmp_key->paramFileIndex > part_elem->paramFileIndex ) + return -1; + else + return 1; +} + + +static int Cmp_partparent( + void * key, + void * elem ) +{ + cmp_partparent_t * cmp_key=key; + carPartParent_p part_elem=elem; + int rc; + + rc = - TabStringCmp( part_elem->manuf, &cmp_key->manuf ); + if ( rc != 0 ) + return rc; + rc = cmp_key->scale - part_elem->scale; + if ( rc != 0 ) + return rc; + rc = - TabStringCmp( part_elem->proto, &cmp_key->proto ); + return rc; +} + + +static int Cmp_roadnameMap( + void * key, + void * elem ) +{ + cmp_key_t * cmp_key=key; + roadnameMap_p roadname_elem=elem; + int rc; + + rc = strncasecmp( cmp_key->name, roadname_elem->roadname, cmp_key->len ); + if ( rc == 0 && roadname_elem->roadname[cmp_key->len] ) + return -1; + return rc; +} + + +static roadnameMap_p LoadRoadnameList( + tabString_p roadnameTab, + tabString_p repmarkTab ) +{ + cmp_key_t cmp_key; + roadnameMap_p roadnameMapP; + + lookupListIndex = -1; + if ( roadnameTab->len<=0 ) + return NULL; + if ( TabStringCmp( "undecorated", roadnameTab ) == 0 ) + return NULL; + + cmp_key.name = roadnameTab->ptr; + cmp_key.len = roadnameTab->len; + roadnameMapP = LookupListElem( &roadnameMap_da, &cmp_key, Cmp_roadnameMap, sizeof *(roadnameMap_p)0 ); + if ( roadnameMapP->roadname == NULL ) { + roadnameMapP->roadname = TabStringDup(roadnameTab); + roadnameMapP->repmark = TabStringDup(repmarkTab); + roadnameMapChanged = TRUE; + } else if ( repmarkTab->len > 0 && + ( roadnameMapP->repmark == NULL || roadnameMapP->repmark[0] == '\0' ) ) { + roadnameMapP->repmark = TabStringDup(repmarkTab); + roadnameMapChanged = TRUE; + } + return roadnameMapP; +} + + +static carPart_p CarPartFind( + char * manufP, + int manufL, + char * partnoP, + int partnoL, + SCALEINX_T scale ) +{ + wIndex_t inx1, inx2; + carPart_p partP; + carPartParent_p parentP; + for ( inx1=0; inx1<carPartParent_da.cnt; inx1++ ) { + parentP = carPartParent(inx1); + if ( manufL == (int)strlen(parentP->manuf) && + strncasecmp( manufP, parentP->manuf, manufL ) == 0 && + scale == parentP->scale ) { + for ( inx2=0; inx2<parentP->parts_da.cnt; inx2++ ) { + partP = carPart( parentP, inx2 ); + if ( partnoL == partP->partnoL && + strncasecmp( partnoP, partP->partnoP, partnoL ) == 0 ) { + return partP; + } + } + } + } + return NULL; +} + + + + +static void CarPartParentDelete( + carPartParent_p parentP ) +{ + RemoveListElem( &carPartParent_da, parentP ); + MyFree( parentP->manuf ); + MyFree( parentP->proto ); + MyFree( parentP ); +} + + +static void CarPartUnlink( + carPart_p partP ) +{ + carPartParent_p parentP = partP->parent; + RemoveListElem( &parentP->parts_da, partP ); + if ( parentP->parts_da.cnt <= 0 ) { + CarPartParentDelete( parentP ); + } +} + + +static carPartParent_p CarPartParentNew( + char * manufP, + int manufL, + char *protoP, + int protoL, + SCALEINX_T scale ) +{ + carPartParent_p parentP; + cmp_partparent_t cmp_key; + cmp_key.manuf.ptr = manufP; + cmp_key.manuf.len = manufL; + cmp_key.proto.ptr = protoP; + cmp_key.proto.len = protoL; + cmp_key.scale = scale; + parentP = (carPartParent_p)LookupListElem( &carPartParent_da, &cmp_key, Cmp_partparent, sizeof * parentP); + if ( parentP->manuf == NULL ) { + parentP->manuf = (char*)MyMalloc( manufL+1 ); + memcpy( parentP->manuf, manufP, manufL ); + parentP->manuf[manufL] = '\0'; + parentP->proto = (char*)MyMalloc( protoL+1 ); + memcpy( parentP->proto, protoP, protoL ); + parentP->proto[protoL] = '\0'; + parentP->scale = scale; + } + return parentP; +} + + +static carPart_p CarPartNew( + carPart_p partP, + int paramFileIndex, + SCALEINX_T scaleInx, + char * title, + long options, + long type, + carDim_t *dim, + wDrawColor color) +{ + carPartParent_p parentP; + carPart_t cmp_key; + tabString_t tabs[7]; + + TabStringExtract( title, 7, tabs ); + if ( TabStringCmp( "Undecorated", &tabs[T_MANUF] ) == 0 || + TabStringCmp( "Custom", &tabs[T_MANUF] ) == 0 || + tabs[T_PART].len == 0 ) + return NULL; + if ( tabs[T_PROTO].len == 0 ) + return NULL; + if ( partP == NULL ) { + partP = CarPartFind( tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PART].ptr, tabs[T_PART].len, scaleInx ); + if ( partP != NULL && + partP->paramFileIndex == PARAM_CUSTOM && + paramFileIndex != PARAM_CUSTOM ) + return partP; +LOG( log_carList, 2, ( "new car part: %s (%d) at %d\n", title, paramFileIndex, lookupListIndex ) ) + } + if ( partP != NULL ) { + CarPartUnlink( partP ); + if ( partP->title != NULL ) + MyFree( partP->title ); +LOG( log_carList, 2, ( "upd car part: %s (%d)\n", title, paramFileIndex ) ) + } + LoadRoadnameList( &tabs[T_ROADNAME], &tabs[T_REPMARK] ); + parentP = CarPartParentNew( tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PROTO].ptr, tabs[T_PROTO].len, scaleInx ); + cmp_key.title = title; + cmp_key.parent = parentP; + cmp_key.paramFileIndex = paramFileIndex; + cmp_key.options = options; + cmp_key.type = type; + cmp_key.dim = *dim; + cmp_key.color = color; + cmp_key.partnoP = tabs[T_PART].ptr; + cmp_key.partnoL = tabs[T_PART].len; + partP = (carPart_p)LookupListElem( &parentP->parts_da, &cmp_key, Cmp_part, sizeof * partP ); + if ( partP->title != NULL ) + MyFree( partP->title ); + *partP = cmp_key; + sprintf( message, "\t\t%s", tabs[2].ptr ); + partP->title = MyStrdup( message ); + partP->partnoP = partP->title + 2+tabs[2].len+1;; + partP->partnoL = tabs[T_PART].len; + return partP; +} + + +static void CarPartDelete( + carPart_p partP ) +{ + if ( partP == NULL ) + return; + CarPartUnlink( partP ); + if ( partP->title ) + MyFree( partP->title ); + MyFree( partP ); +} + + +static BOOL_T CarPartRead( + char * line ) +{ + char scale[10]; + long options; + long type; + char * title; + carDim_t dim; + long rgb; + + if ( !GetArgs( line+8, "sqllff00ffl", + scale, &title, &options, &type, &dim.carLength, &dim.carWidth, &dim.truckCenter, &dim.coupledLength, &rgb ) ) + return FALSE; + CarPartNew( NULL, curParamFileIndex, LookupScale(scale), title, options, type, &dim, wDrawFindColor(rgb) ); + MyFree( title ); + return TRUE; +} + + +static BOOL_T CarPartWrite( + FILE * f, + carPart_p partP ) +{ + BOOL_T rc = TRUE; + char *oldLocale = NULL; + carPartParent_p parentP=partP->parent; + tabString_t tabs[7]; + + oldLocale = SaveLocale("C"); + + TabStringExtract( partP->title, 7, tabs ); + sprintf( message, "%s\t%s\t%.*s\t%.*s\t%.*s\t%.*s\t%.*s", + parentP->manuf, parentP->proto, + tabs[T_DESC].len, tabs[T_DESC].ptr, + tabs[T_PART].len, tabs[T_PART].ptr, + tabs[T_ROADNAME].len, tabs[T_ROADNAME].ptr, + tabs[T_REPMARK].len, tabs[T_REPMARK].ptr, + tabs[T_NUMBER].len, tabs[T_NUMBER].ptr ); + rc &= fprintf( f, "CARPART %s \"%s\"", GetScaleName(partP->parent->scale), PutTitle(message) )>0; + rc &= fprintf( f, " %ld %ld %0.3f %0.3f 0 0 %0.3f %0.3f %ld\n", + partP->options, partP->type, partP->dim.carLength, partP->dim.carWidth, partP->dim.truckCenter, partP->dim.coupledLength, wDrawGetRGB(partP->color) )>0; + + RestoreLocale(oldLocale); + + return rc; +} + + + +static BOOL_T CarDescCustomSave( + FILE * f ) +{ + int parentX; + carPartParent_p parentP; + int partX; + carPart_p partP; + BOOL_T rc = TRUE; + + for ( parentX=0; parentX<carPartParent_da.cnt; parentX++ ) { + parentP = carPartParent(parentX); + for ( partX=0; partX<parentP->parts_da.cnt; partX++ ) { + partP = carPart(parentP,partX); + if ( partP->paramFileIndex == PARAM_CUSTOM ) + rc &= CarPartWrite(f, partP ); + } + } + return rc; +} + + + +/* + * Car Item + */ + +static dynArr_t carItemInfo_da; +#define carItemInfo(N) DYNARR_N( carItem_t*, carItemInfo_da, N ) + +#define N_CONDLISTMAP (6) +static nameLongMap_t condListMap[N_CONDLISTMAP] = { + { N_("N/A"), 0 }, + { N_("Mint"), 100 }, + { N_("Excellent"), 80 }, + { N_("Good"), 60 }, + { N_("Fair"), 40 }, + { N_("Poor"), 20 } }; + + +static wIndex_t MapCondition( + long conditionValue ) +{ + if ( conditionValue < 10 ) + return 0; + else if ( conditionValue < 30 ) + return 5; + else if ( conditionValue < 50 ) + return 4; + else if ( conditionValue < 70 ) + return 3; + else if ( conditionValue < 90 ) + return 2; + else + return 1; +} + + +static carItem_p CarItemNew( + carItem_p item, + int paramFileIndex, + long itemIndex, + SCALEINX_T scale, + char * title, + long options, + long type, + carDim_t *dim, + wDrawColor color, + FLOAT_T purchPrice, + FLOAT_T currPrice, + long condition, + long purchDate, + long serviceDate ) +{ + carPart_p partP; + tabString_t tabs[7]; + + TabStringExtract( title, 7, tabs ); + if ( paramFileIndex != PARAM_CUSTOM ) { + partP = CarPartFind( tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PART].ptr, tabs[T_PART].len, scale ); + if ( partP == NULL ) { + CarPartNew( NULL, PARAM_LAYOUT, scale, title, options, type, dim, color ); + } + } + + if ( item == NULL ) { + DYNARR_APPEND( carItem_t*, carItemInfo_da, 10 ); + item = (carItem_t*)MyMalloc( sizeof * item ); + carItemInfo(carItemInfo_da.cnt-1) = item; + } else { + if ( item->title ) MyFree( item->title ); + if ( item->data.number ) MyFree( item->data.number ); + } + item->index = itemIndex; + item->scaleInx = scale; + item->title = MyStrdup(title); + item->contentsLabel = "Car Item"; + item->barScale = curBarScale>0?curBarScale:(60.0*12.0/curScaleRatio); + item->options = options; + item->type = type; + item->dim = *dim; + item->color = color; + if ( tabs[T_REPMARK].len>0 || tabs[T_NUMBER].len>0 ) { + sprintf( message, "%.*s%s%.*s", tabs[T_REPMARK].len, tabs[T_REPMARK].ptr, (tabs[T_REPMARK].len>0&&tabs[T_NUMBER].len>0)?" ":"", tabs[T_NUMBER].len, tabs[T_NUMBER].ptr ); + } else { + sprintf( message, "#%ld", item->index ); + } + item->data.number = MyStrdup( message ); + item->data.purchPrice = purchPrice; + item->data.currPrice = currPrice; + item->data.condition = condition; + item->data.purchDate = purchDate; + item->data.serviceDate = serviceDate; + item->data.notes = NULL; + item->segCnt = 0; + item->segPtr = NULL; + LoadRoadnameList( &tabs[T_ROADNAME], &tabs[T_REPMARK] ); + return item; +} + + +EXPORT BOOL_T CarItemRead( + char * line ) +{ + long itemIndex; + char scale[10]; + char * title; + long options; + long type; + carDim_t dim; + long rgb; + FLOAT_T purchPrice = 0; + FLOAT_T currPrice = 0; + long condition = 0; + long purchDate = 0; + long serviceDate = 0; + int len, siz; + static dynArr_t buffer_da; + carItem_p item; + char * cp; + wIndex_t layer; + coOrd pos; + ANGLE_T angle; + wIndex_t index; + + if ( !GetArgs( line+4, "lsqll" "ff00ffl" "fflll000000c", + &itemIndex, scale, &title, &options, &type, + &dim.carLength, &dim.carWidth, &dim.truckCenter, &dim.coupledLength, &rgb, + &purchPrice, &currPrice, &condition, &purchDate, &serviceDate, &cp ) ) + return FALSE; + if ( (options&CAR_ITEM_HASNOTES) ) { + DYNARR_SET( char, buffer_da, 0 ); + while ( (line=GetNextLine()) && strncmp( line, " END", 7 ) != 0 ) { + siz = buffer_da.cnt; + len = strlen( line ); + DYNARR_SET( char, buffer_da, siz+len+1 ); + memcpy( &((char*)buffer_da.ptr)[siz], line, len ); + ((char*)buffer_da.ptr)[siz+len] = '\n'; + } + DYNARR_APPEND( char, buffer_da, 1 ); + ((char*)buffer_da.ptr)[buffer_da.cnt-1] = 0; + } + item = CarItemNew( NULL, curParamFileIndex, itemIndex, LookupScale(scale), title, + options&(CAR_DESC_BITS|CAR_ITEM_BITS), type, &dim, wDrawFindColor(rgb), + purchPrice, currPrice, condition, purchDate, serviceDate ); + if ( (options&CAR_ITEM_HASNOTES) ) + item->data.notes = MyStrdup( (char*)buffer_da.ptr ); + MyFree(title); + if ( (options&CAR_ITEM_ONLAYOUT) ) { + if ( !GetArgs( cp, "dLpf", + &index, &layer, &pos, &angle ) ) + return FALSE; + item->car = NewCar( index, item, pos, angle ); + SetTrkLayer( item->car, layer ); + ReadSegs(); + SetEndPts( item->car, 2 ); + ComputeBoundingBox( item->car ); + } + return TRUE; +} + + +static BOOL_T CarItemWrite( + FILE * f, + carItem_t * item, + BOOL_T layout ) +{ + long options = (item->options&CAR_DESC_BITS); + coOrd pos; + ANGLE_T angle; + BOOL_T rc = TRUE; + char *oldLocale = NULL; + + oldLocale = SaveLocale("C"); + + if ( item->data.notes && item->data.notes[0] ) + options |= CAR_ITEM_HASNOTES; + if ( layout && item->car && !IsTrackDeleted(item->car) ) + options |= CAR_ITEM_ONLAYOUT; + rc &= fprintf( f, "CAR %ld %s \"%s\" %ld %ld %0.3f %0.3f 0 0 %0.3f %0.3f %ld %0.3f %0.3f %ld %ld %ld 0 0 0 0 0 0", + item->index, GetScaleName(item->scaleInx), PutTitle(item->title), + options, item->type, + item->dim.carLength, item->dim.carWidth, item->dim.truckCenter, item->dim.coupledLength, wDrawGetRGB(item->color), + item->data.purchPrice, item->data.currPrice, item->data.condition, item->data.purchDate, item->data.serviceDate )>0; + if ( ( options&CAR_ITEM_ONLAYOUT) ) { + CarGetPos( item->car, &pos, &angle ); + rc &= fprintf( f, " %d %d %0.3f %0.3f %0.3f", + GetTrkIndex(item->car), GetTrkLayer(item->car), pos.x, pos.y, angle )>0; + } + rc &= fprintf( f, "\n" )>0; + if ( (options&CAR_ITEM_HASNOTES) ) { + rc &= fprintf( f, "%s\n", item->data.notes )>0; + rc &= fprintf( f, " END\n" )>0; + } + if ( (options&CAR_ITEM_ONLAYOUT) ) { + rc &= WriteEndPt( f, item->car, 0 ); + rc &= WriteEndPt( f, item->car, 1 ); + rc &= fprintf( f, "\tEND\n" )>0; + } + + RestoreLocale(oldLocale); + + return rc; +} + + + +EXPORT carItem_p CarItemFind( + long itemInx ) +{ + if ( itemInx >= 0 && itemInx < carItemInfo_da.cnt ) + return carItemInfo(itemInx); + else + return NULL; +} + + +EXPORT long CarItemFindIndex( + carItem_p item ) +{ + long inx; + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) + if ( carItemInfo(inx) == item ) + return inx; + AbortProg( "carItemFindIndex" ); + return -1; +} + + +EXPORT void CarItemGetSegs( + carItem_p item ) +{ + coOrd orig; + carProto_p protoP; + tabString_t tabs[7]; + trkSeg_t * segPtr; + DIST_T ratio = GetScaleRatio(item->scaleInx); + + TabStringExtract( item->title, 7, tabs ); + TabStringCpy( message, &tabs[T_PROTO] ); + protoP = CarProtoLookup( message, FALSE, FALSE, 0.0, 0.0 ); + if ( protoP != NULL ) { + item->segCnt = protoP->segCnt; + segPtr = protoP->segPtr; + orig = protoP->orig; + } else { + CarProtoDlgCreateDummyOutline( &item->segCnt, &segPtr, (item->options&CAR_DESC_IS_LOCO)!=0, item->dim.carLength, item->dim.carWidth, item->color ); + orig = zero; + } + item->segPtr = (trkSeg_p)MyMalloc( item->segCnt * sizeof *(segPtr) ); + memcpy( item->segPtr, segPtr, item->segCnt * sizeof *(segPtr) ); + CloneFilledDraw( item->segCnt, item->segPtr, FALSE ); + if ( protoP ) { + orig.x = -orig.x; + orig.y = -orig.y; + MoveSegs( item->segCnt, item->segPtr, orig ); + RescaleSegs( item->segCnt, item->segPtr, item->dim.carLength/protoP->size.x, item->dim.carWidth/protoP->size.y, 1/ratio ); + RecolorSegs( item->segCnt, item->segPtr, item->color ); + } +} + + +EXPORT BOOL_T WriteCars( + FILE * f ) +{ + int inx; + BOOL_T rc = TRUE; + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) + rc &= CarItemWrite( f, carItemInfo(inx), TRUE ); + return rc; +} + + +EXPORT BOOL_T CarCustomSave( + FILE * f ) +{ + BOOL_T rc = TRUE; + rc &= CarProtoCustomSave( f ); + rc &= CarDescCustomSave( f ); + return rc; +} + + +/* + * Car Item Select + */ + +EXPORT carItem_p currCarItemPtr; +EXPORT long carHotbarModeInx = 1; +static long carHotbarModes[] = { 0x0002, 0x0012, 0x0312, 0x4312, 0x0021, 0x0321, 0x4321 }; +static long carHotbarContents[] = { 0x0005, 0x0002, 0x0012, 0x0012, 0x0001, 0x0021, 0x0021 }; +static long newCarInx; +static paramData_t newCarPLs[] = { + { PD_DROPLIST, &newCarInx, "index", PDO_DLGWIDE, (void*)400, N_("Item") } }; +static paramGroup_t newCarPG = { "train-newcar", 0, newCarPLs, sizeof newCarPLs/sizeof newCarPLs[0] }; +EXPORT wControl_p newCarControls[2]; +static char newCarLabel1[STR_SIZE]; +static char * newCarLabels[2] = { newCarLabel1, NULL }; + +static dynArr_t carItemHotbar_da; +#define carItemHotbar(N) DYNARR_N( carItem_p, carItemHotbar_da, N ) + + +static int Cmp_carHotbar( + const void * ptr1, + const void * ptr2 ) +{ + carItem_p item1 = *(carItem_p*)ptr1; + carItem_p item2 = *(carItem_p*)ptr2; + tabString_t tabs1[7], tabs2[7]; + int rc; + long mode; + + TabStringExtract( item1->title, 7, tabs1 ); + TabStringExtract( item2->title, 7, tabs2 ); + for ( mode=carHotbarModes[carHotbarModeInx],rc=0; mode!=0&&rc==0; mode>>=4 ) { + switch ( mode&0x000F ) { + case 4: + rc = (int)(item1->index-item2->index); + break; + case 1: + rc = strncasecmp( tabs1[T_MANUF].ptr, tabs2[T_MANUF].ptr, max(tabs1[T_MANUF].len,tabs2[T_MANUF].len) ); + break; + case 3: + rc = strncasecmp( tabs1[T_PART].ptr, tabs2[T_PART].ptr, max(tabs1[T_PART].len,tabs2[T_PART].len) ); + break; + case 2: + if ( item1->type < item2->type ) + rc = -1; + else if ( item1->type > item2->type ) + rc = 1; + else + rc = strncasecmp( tabs1[T_PROTO].ptr, tabs2[T_PROTO].ptr, max(tabs1[T_PROTO].len,tabs2[T_PROTO].len) ); + break; + } + } + return rc; +} + + +static void CarItemHotbarUpdate( + paramGroup_p pg, + int inx, + void * data ) +{ + wIndex_t carItemInx; + carItem_p item; + if ( inx == 0 ) { + carItemInx = (wIndex_t)*(long*)data; + if ( carItemInx < 0 ) + return; + carItemInx = (wIndex_t)(long)wListGetItemContext( (wList_p)pg->paramPtr[inx].control, carItemInx ); + item = carItemHotbar(carItemInx); + if ( item != NULL ) + currCarItemPtr = item; + } +} + + +static char * FormatCarTitle( + carItem_p item, + long mode ) +{ + tabString_t tabs[7]; + char * cp; + TabStringExtract( item->title, 7, tabs ); + cp = message; + for ( ; mode!=0; mode>>=4 ) { + switch ( mode&0x000F ) { + case 1: + cp = TabStringCpy( cp, &tabs[T_MANUF] ); + break; + case 2: + cp = TabStringCpy( cp, &tabs[T_PROTO] ); + break; + case 3: + cp = TabStringCpy( cp, &tabs[T_PART] ); + break; + case 4: + sprintf( cp, "%ld ", item->index ); + cp += strlen(cp); + break; + case 5: + strcpy( cp, typeListMap[CarProtoFindTypeCode(item->type)].name ); + cp += strlen(cp); + break; + } + *cp++ = '/'; + } + *--cp = '\0'; + return message; +} + + +EXPORT char * CarItemDescribe( + carItem_p item, + long mode, + long * index ) +{ + tabString_t tabs[7]; + char * cp; + static char desc[STR_LONG_SIZE]; + + TabStringExtract( item->title, 7, tabs ); + cp = desc; + if ( mode != -1 ) { + sprintf( cp, "%ld ", item->index ); + cp = desc+strlen(cp); + } + if ( (mode&0xF)!=1 && ((mode>>4)&0xF)!=1 && ((mode>>8)&0xF)!=1 && ((mode>>12)&0xF)!=1 ) { + cp = TabStringCpy( cp, &tabs[T_MANUF] ); + *cp++ = ' '; + } + if ( (mode&0xF)!=3 && ((mode>>4)&0xF)!=3 && ((mode>>8)&0xF)!=3 && ((mode>>12)&0xF)!=3 ) { + cp = TabStringCpy( cp, &tabs[T_PART] ); + *cp++ = ' '; + } + if ( (mode&0xF)!=2 && ((mode>>4)&0xF)!=2 && ((mode>>8)&0xF)!=2 && ((mode>>12)&0xF)!=2 ) { + cp = TabStringCpy( cp, &tabs[T_PROTO] ); + *cp++ = ' '; + } + if ( tabs[T_DESC].len > 0 ) { + cp = TabStringCpy( cp, &tabs[T_DESC] ); + *cp++ = ' '; + } + if ( mode != -1 ) { + if ( tabs[T_REPMARK].len > 0 ) { + cp = TabStringCpy( cp, &tabs[T_REPMARK] ); + *cp++ = ' '; + } else if ( tabs[T_ROADNAME].len > 0 ) { + cp = TabStringCpy( cp, &tabs[T_ROADNAME] ); + *cp++ = ' '; + } + if ( tabs[T_NUMBER].len > 0 ) { + cp = TabStringCpy( cp, &tabs[T_NUMBER] ); + *cp++ = ' '; + } + } + *--cp = '\0'; + if ( index != NULL ) + *index = item->index; + return desc; +} + + +EXPORT void CarItemLoadList( void * junk ) +{ + wIndex_t inx; + carItem_p item; + char * cp; + wPos_t w, h; + + DYNARR_SET( carItem_t*, carItemHotbar_da, carItemInfo_da.cnt ); + memcpy( carItemHotbar_da.ptr, carItemInfo_da.ptr, carItemInfo_da.cnt * sizeof item ); + wListClear( (wList_p)newCarPLs[0].control ); + for ( inx=0; inx<carItemHotbar_da.cnt; inx++ ) { + item = carItemHotbar(inx); + if ( item->car && !IsTrackDeleted(item->car) ) + continue; + cp = CarItemDescribe( item, 0, NULL ); + wListAddValue( (wList_p)newCarPLs[0].control, cp, NULL, (void*)(intptr_t)inx ); + } + /*wListSetValue( (wList_p)newCarPLs[0].control, "Select a car" );*/ + wListSetIndex( (wList_p)newCarPLs[0].control, 0 ); + strcpy( newCarLabel1, _("Select") ); + ParamLoadControl( &newCarPG, 0 ); + InfoSubstituteControls( newCarControls, newCarLabels ); + wWinGetSize( mainW, &w, &h ); + w -= wControlGetPosX( newCarControls[0] ) + 4; + if ( w > 20 ) + wListSetSize( (wList_p)newCarControls[0], w, wControlGetHeight( newCarControls[0] ) ); +} + + +static char * CarItemHotbarProc( + hotBarProc_e op, + void * data, + drawCmd_p d, + coOrd * origP ) +{ + wIndex_t carItemInx = (wIndex_t)(long)data; + carItem_p item; + wIndex_t inx; + long mode; + char * cp; + wPos_t w, h; + + item = carItemHotbar(carItemInx); + if ( item == NULL ) + return NULL; + switch ( op ) { + case HB_SELECT: + currCarItemPtr = item; + mode = carHotbarModes[carHotbarModeInx]; + if ( (mode&0xF000) == 0 ) { + wListClear( (wList_p)newCarPLs[0].control ); + for ( inx=carItemInx; + inx<carItemHotbar_da.cnt && ( inx==carItemInx || Cmp_carHotbar(&carItemHotbar(carItemInx),&carItemHotbar(inx))==0 ); + inx++ ) { + item = carItemHotbar(inx); + if ( item->car && !IsTrackDeleted(item->car) ) + continue; + cp = CarItemDescribe( item, mode, NULL ); + wListAddValue( (wList_p)newCarPLs[0].control, cp, NULL, (void*)(intptr_t)inx ); + } + /*wListSetValue( (wList_p)newCarPLs[0].control, "Select a car" );*/ + wListSetIndex( (wList_p)newCarPLs[0].control, 0 ); + cp = CarItemHotbarProc( HB_BARTITLE, (void*)(intptr_t)carItemInx, NULL, NULL ); + strncpy( newCarLabel1, cp, sizeof newCarLabel1 ); + ParamLoadControls( &newCarPG ); + ParamGroupRecord( &newCarPG ); + + InfoSubstituteControls( newCarControls, newCarLabels ); + wWinGetSize( mainW, &w, &h ); + w -= wControlGetPosX( newCarControls[0] ) + 4; + if ( w > 20 ) + wListSetSize( (wList_p)newCarControls[0], w, wControlGetHeight( newCarControls[0] ) ); + } else { + InfoSubstituteControls( NULL, NULL ); + cp = CarItemDescribe( item, 0, NULL ); + InfoMessage( cp ); + } + break; + case HB_LISTTITLE: + case HB_BARTITLE: + return FormatCarTitle( item, carHotbarModes[carHotbarModeInx] ); + case HB_FULLTITLE: + return item->title; + case HB_DRAW: + if ( item->segCnt == 0 ) + CarItemGetSegs( item ); + DrawSegs( d, *origP, 0.0, item->segPtr, item->segCnt, trackGauge, wDrawColorBlack ); + return NULL; + } + return NULL; +} + + +EXPORT int CarAvailableCount( void ) +{ + wIndex_t inx; + int cnt = 0; + carItem_t * item; + for ( inx=0; inx < carItemHotbar_da.cnt; inx ++ ) { + item = carItemHotbar(inx); + if ( item->scaleInx != curScaleInx ) + continue; + cnt++; + } + return cnt; +} + + +EXPORT void AddHotBarCarDesc( void ) +{ + wIndex_t inx; + carItem_t * item0, * item1; + coOrd orig; + coOrd size; + + DYNARR_SET( carItem_t*, carItemHotbar_da, carItemInfo_da.cnt ); + memcpy( carItemHotbar_da.ptr, carItemInfo_da.ptr, carItemInfo_da.cnt * sizeof item0 ); + qsort( carItemHotbar_da.ptr, carItemHotbar_da.cnt, sizeof item0, Cmp_carHotbar ); + for ( inx=0,item0=NULL; inx < carItemHotbar_da.cnt; inx ++ ) { + item1 = carItemHotbar(inx); + if ( item1->car && !IsTrackDeleted(item1->car) ) + continue; + if ( item1->scaleInx != curScaleInx ) + continue; + if ( (carHotbarModes[carHotbarModeInx]&0xF000)!=0 || ( item0 == NULL || Cmp_carHotbar( &item0, &item1 ) != 0 ) ) { +#ifdef DESCFIX + orig.x = - item->orig.x; + orig.y = - item->orig.y; +#endif + orig = zero; + size.x = item1->dim.carLength; + size.y = item1->dim.carWidth; + AddHotBarElement( FormatCarTitle( item1, carHotbarContents[carHotbarModeInx] ), size, orig, FALSE, (60.0*12.0/curScaleRatio), (void*)(intptr_t)inx, CarItemHotbarProc ); + } + item0 = item1; + } +} + + +EXPORT coOrd CarItemFindCouplerMountPoint( + carItem_p item, + traverseTrack_t trvTrk, + int dir ) +{ + DIST_T couplerOffset; + coOrd pos; + + if ( dir ) + FlipTraverseTrack( &trvTrk ); + if ( trvTrk.trk == NULL || (item->options&CAR_DESC_COUPLER_MODE_BODY)!=0 ) { + couplerOffset = (item->dim.carLength-(item->dim.coupledLength-item->dim.carLength))/2.0; + Translate( &pos, trvTrk.pos, trvTrk.angle, couplerOffset ); + } else { + TraverseTrack2( &trvTrk, item->dim.truckCenter/2.0 ); + /*Translate( &pos1, trvTrk.pos, trvTrk.angle, item->dim.truckCenter/2.0 );*/ + couplerOffset = item->dim.carLength - (item->dim.truckCenter+item->dim.coupledLength)/2.0; + Translate( &pos, trvTrk.pos, trvTrk.angle, couplerOffset ); + } + return pos; +} + + +EXPORT void CarItemSize( + carItem_p item, + coOrd * size ) +{ + size->x = item->dim.carLength; + size->y = item->dim.carWidth; +} + + +EXPORT char * CarItemNumber( + carItem_p item ) +{ + return item->data.number; +} + + +static DIST_T CarItemTruckCenter( + carItem_p item ) +{ + return item->dim.truckCenter; +} + + +EXPORT DIST_T CarItemCoupledLength( + carItem_p item ) +{ + return item->dim.coupledLength; +} + + +EXPORT BOOL_T CarItemIsLoco( + carItem_p item ) +{ + return (item->options&CAR_DESC_IS_LOCO) == (CAR_DESC_IS_LOCO); +} + + +EXPORT BOOL_T CarItemIsLocoMaster( + carItem_p item ) +{ + return (item->options&(CAR_DESC_IS_LOCO|CAR_DESC_IS_LOCO_MASTER)) == (CAR_DESC_IS_LOCO|CAR_DESC_IS_LOCO_MASTER); +} + + +EXPORT void CarItemSetLocoMaster( + carItem_p item, + BOOL_T locoIsMaster ) +{ + if ( locoIsMaster ) + item->options |= CAR_DESC_IS_LOCO_MASTER; + else + item->options &= ~CAR_DESC_IS_LOCO_MASTER; +} + + +EXPORT void CarItemSetTrack( + carItem_p item, + track_p trk ) +{ + item->car = trk; + if ( trk != NULL ) + SetTrkScale( trk, item->scaleInx ); +} + +static DIST_T CarItemCouplerLength( + carItem_p item, + int dir ) +{ + return item->dim.coupledLength-item->dim.carLength; +} + + +EXPORT void CarItemPlace( + carItem_p item, + traverseTrack_p trvTrk, + DIST_T * dists ) +{ + DIST_T dist; + traverseTrack_t trks[2]; + + dist = CarItemTruckCenter(item)/2.0; + trks[0] = trks[1] = *trvTrk; + TraverseTrack2( &trks[0], dist ); + TraverseTrack2( &trks[1], -dist ); + item->pos.x = (trks[0].pos.x+trks[1].pos.x)/2.0; + item->pos.y = (trks[0].pos.y+trks[1].pos.y)/2.0; + item->angle = FindAngle( trks[1].pos, trks[0].pos ); + dists[0] = dists[1] = CarItemCoupledLength(item)/2.0; +} + + + +static int drawCarTrucks = 0; +EXPORT void CarItemDraw( + drawCmd_p d, + carItem_p item, + wDrawColor color, + int direction, + BOOL_T locoIsMaster, + vector_t *coupler ) +{ + coOrd size, pos, pos2; + DIST_T length; + wFont_p fp; + wDrawWidth width; + trkSeg_t simpleSegs[1]; + coOrd simplePts[4]; + int dir; + DIST_T rad; + static int couplerLineWidth = 3; + DIST_T scale2rail; + + CarItemSize( item, &size ); + if ( d->scale >= ((d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale) ) { + simplePts[0].x = simplePts[3].x = -size.x/2.0; + simplePts[1].x = simplePts[2].x = size.x/2.0; + simplePts[0].y = simplePts[1].y = -size.y/2.0; + simplePts[2].y = simplePts[3].y = size.y/2.0; + simpleSegs[0].type = SEG_FILPOLY; + simpleSegs[0].color = item->color; + simpleSegs[0].width = 0; + simpleSegs[0].u.p.cnt = 4; + simpleSegs[0].u.p.pts = simplePts; + simpleSegs[0].u.p.orig = zero; + simpleSegs[0].u.p.angle = 0.0; + DrawSegs( d, item->pos, item->angle-90.0, simpleSegs, 1, 0.0, color ); + } else { + if ( item->segCnt == 0 ) + CarItemGetSegs( item ); + Translate( &pos, item->pos, item->angle, -size.x/2.0 ); + Translate( &pos, pos, item->angle-90, -size.y/2.0 ); + DrawSegs( d, pos, item->angle-90.0, item->segPtr, item->segCnt, 0.0, color ); + } + + if ( drawCarTrucks ) { + length = item->dim.truckCenter/2.0; + Translate( &pos, item->pos, item->angle, length ); + DrawArc( d, pos, trackGauge/2.0, 0.0, 360.0, FALSE, 0, color ); + Translate( &pos, item->pos, item->angle+180, length ); + DrawArc( d, pos, trackGauge/2.0, 0.0, 360.0, FALSE, 0, color ); + } + + if ( (labelEnable&LABELENABLE_CARS) ) { + fp = wStandardFont( F_HELV, FALSE, FALSE ); + DrawBoxedString( BOX_BACKGROUND, d, item->pos, item->data.number, fp, (wFontSize_t)descriptionFontSize, color, 0.0 ); + } + + /* draw loco head light */ + if ( (item->options&CAR_DESC_IS_LOCO)!=0 ) { + Translate( &pos, item->pos, item->angle+(direction?180.0:0.0), size.x/2.0-trackGauge/2.0 ); + if ( locoIsMaster ) { + DrawFillCircle( d, pos, trackGauge/2.0, (color==wDrawColorBlack?drawColorGold:color) ); + } else { + width = (wDrawWidth)floor( trackGauge/8.0 * d->dpi / d->scale ); + DrawArc( d, pos, trackGauge/2.0, 0.0, 360.0, FALSE, width, (color==wDrawColorBlack?drawColorGold:color) ); + } + } + + /* draw coupler */ + scale2rail = ((d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale); + if ( d->scale >= scale2rail ) + return; + scale2rail /= 2; + rad = trackGauge/8.0; + for ( dir=0; dir<2; dir++ ) { + Translate( &pos, coupler[dir].pos, coupler[dir].angle, CarItemCouplerLength(item,dir) ); + DrawLine( d, coupler[dir].pos, pos, couplerLineWidth, color ); + if ( d->scale < scale2rail ) { + /*DrawFillCircle( d, p0, rad, dir==0?color:selectedColor );*/ + Translate( &pos2, pos, coupler[dir].angle+90.0, trackGauge/3 ); + DrawLine( d, pos2, pos, couplerLineWidth, color ); + } + } +} + + +EXPORT void CarItemUpdate( + carItem_p item ) +{ + DoChangeNotification( CHANGE_SCALE ); +} + +/* + * Car Item/Part Dlg + */ + +static int carDlgChanged; + +static SCALEINX_T carDlgScaleInx; +static carItem_p carDlgUpdateItemPtr; +static carPart_p carDlgUpdatePartPtr; +static carProto_p carDlgUpdateProtoPtr; +static carPart_p carDlgNewPartPtr; +static carProto_p carDlgNewProtoPtr; + +static BOOL_T carDlgFlipToggle; + +static wIndex_t carDlgManufInx; +static char carDlgManufStr[STR_SIZE]; +static wIndex_t carDlgKindInx; +static wIndex_t carDlgProtoInx; +static char carDlgProtoStr[STR_SIZE]; +static wIndex_t carDlgPartnoInx; +static char carDlgPartnoStr[STR_SIZE]; +static char carDlgDescStr[STR_SIZE]; + +static long carDlgDispMode; +static wIndex_t carDlgRoadnameInx; +static char carDlgRoadnameStr[STR_SIZE]; +static char carDlgRepmarkStr[STR_SIZE]; +static char carDlgNumberStr[STR_SIZE]; +static wDrawColor carDlgBodyColor; +static long carDlgIsLoco; +static wIndex_t carDlgTypeInx; + +static carDim_t carDlgDim; +static DIST_T carDlgCouplerLength; +static long carDlgCouplerMount; + +static long carDlgItemIndex = 1; +static FLOAT_T carDlgPurchPrice; +static char carDlgPurchPriceStr[STR_SIZE]; +static FLOAT_T carDlgCurrPrice; +static char carDlgCurrPriceStr[STR_SIZE]; +static wIndex_t carDlgConditionInx; +static long carDlgCondition; +static long carDlgPurchDate; +static char carDlgPurchDateStr[STR_SIZE]; +static long carDlgServiceDate; +static char carDlgServiceDateStr[STR_SIZE]; +static long carDlgQuantity = 1; +static long carDlgMultiNum; + +static char *dispmodeLabels[] = { N_("Information"), N_("Customize"), NULL }; +static drawCmd_t carDlgD = { + NULL, + &screenDrawFuncs, + DC_NOCLIP, + 1.0, + 0.0, + { 0, 0 }, { 0, 0 }, + Pix2CoOrd, CoOrd2Pix }; +static void CarDlgRedraw(void); +static paramDrawData_t carDlgDrawData = { 455, 100, (wDrawRedrawCallBack_p)CarDlgRedraw, NULL, &carDlgD }; +static paramTextData_t notesData = { 440, 100 }; +static char *multinumLabels[] = { N_("Sequential"), N_("Repeated"), NULL }; +static void CarDlgNewProto( void ); +static void CarDlgUpdate( paramGroup_p, int, void * ); +static void CarDlgNewDesc( void ); +static void CarDlgNewProto( void ); + +static paramData_t carDlgPLs[] = { +#define A (0) +#define I_CD_MANUF_LIST (A+0) + { PD_DROPLIST, &carDlgManufInx, "manuf", PDO_NOPREF, (void*)350, N_("Manufacturer"), BL_EDITABLE }, +#define I_CD_PROTOTYPE_STR (A+1) + { PD_STRING, &carDlgProtoStr, "prototype", PDO_NOPREF, (void*)350, N_("Prototype") }, +#define I_CD_PROTOKIND_LIST (A+2) + { PD_DROPLIST, &carDlgKindInx, "protokind-list", PDO_NOPREF, (void*)125, N_("Prototype"), 0 }, +#define I_CD_PROTOTYPE_LIST (A+3) + { PD_DROPLIST, &carDlgProtoInx, "prototype-list", PDO_NOPREF|PDO_DLGHORZ, (void*)(225-3), NULL, 0 }, +#define I_CD_TYPE_LIST (A+4) + { PD_DROPLIST, &carDlgTypeInx, "type", PDO_NOPREF, (void*)350, N_("Type"), 0 }, +#define I_CD_PARTNO_LIST (A+5) + { PD_DROPLIST, &carDlgPartnoInx, "partno-list", PDO_NOPREF, (void*)350, N_("Part"), BL_EDITABLE }, +#define I_CD_PARTNO_STR (A+6) + { PD_STRING, &carDlgPartnoStr, "partno", PDO_NOPREF, (void*)350, N_("Part Number") }, +#define I_CD_ISLOCO (A+7) + { PD_TOGGLE, &carDlgIsLoco, "isLoco", PDO_NOPREF|PDO_DLGWIDE, isLocoLabels, N_("Loco?"), BC_HORZ|BC_NOBORDER }, +#define I_CD_DESC_STR (A+8) + { PD_STRING, &carDlgDescStr, "desc", PDO_NOPREF, (void*)350, N_("Description"), 0 }, +#define I_CD_IMPORT (A+9) + { PD_BUTTON, NULL, "import", 0, 0, N_("Import") }, +#define I_CD_RESET (A+10) + { PD_BUTTON, NULL, "reset", PDO_DLGHORZ, 0, N_("Reset") }, +#define I_CD_FLIP (A+11) + { PD_BUTTON, NULL, "flip", PDO_DLGHORZ|PDO_DLGWIDE|PDO_DLGBOXEND, 0, N_("Flip") }, + +#define I_CD_DISPMODE (A+12) + { PD_RADIO, &carDlgDispMode, "dispmode", PDO_NOPREF|PDO_DLGWIDE, dispmodeLabels, N_("Mode"), BC_HORZ|BC_NOBORDER }, + +#define B (A+13) +#define I_CD_ROADNAME_LIST (B+0) + { PD_DROPLIST, &carDlgRoadnameInx, "road", PDO_NOPREF|PDO_DLGWIDE, (void*)350, N_("Road"), BL_EDITABLE }, +#define I_CD_REPMARK (B+1) + { PD_STRING, carDlgRepmarkStr, "repmark", PDO_NOPREF, (void*)60, N_("Reporting Mark") }, +#define I_CD_NUMBER (B+2) + { PD_STRING, carDlgNumberStr, "number", PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, (void*)80, N_("Number") }, +#define I_CD_BODYCOLOR (B+3) + { PD_COLORLIST, &carDlgBodyColor, "bodyColor", PDO_DLGWIDE|PDO_DLGHORZ, NULL, N_("Color") }, +#define I_CD_CARLENGTH (B+4) + { PD_FLOAT, &carDlgDim.carLength, "carLength", PDO_DIM|PDO_NOPREF|PDO_DLGWIDE, &r0_99999, N_("Car Length") }, +#define I_CD_CARWIDTH (B+5) + { PD_FLOAT, &carDlgDim.carWidth, "carWidth", PDO_DIM|PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, &r0_99999, N_("Width") }, +#define I_CD_TRKCENTER (B+6) + { PD_FLOAT, &carDlgDim.truckCenter, "trkCenter", PDO_DIM|PDO_NOPREF, &r0_99999, N_("Truck Centers") }, +#define I_CD_CPLRMNT (B+7) + { PD_RADIO, &carDlgCouplerMount, "cplrMount", PDO_NOPREF|PDO_DLGHORZ|PDO_DLGWIDE, cplrModeLabels, N_("Coupler Mount"), BC_HORZ|BC_NOBORDER }, +#define I_CD_CPLDLEN (B+8) + { PD_FLOAT, &carDlgDim.coupledLength, "cpldLen", PDO_DIM|PDO_NOPREF, &r0_99999, N_("Coupled Length") }, +#define I_CD_CPLRLEN (B+9) + { PD_FLOAT, &carDlgCouplerLength, "cplrLen", PDO_DIM|PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, &r0_99999, N_("Coupler Length") }, +#define I_CD_CANVAS (B+10) + { PD_DRAW, NULL, "canvas", PDO_NOPSHUPD|PDO_DLGWIDE|PDO_DLGNOLABELALIGN|PDO_DLGRESETMARGIN|PDO_DLGBOXEND|PDO_DLGRESIZE, &carDlgDrawData, NULL, 0 }, + +#define C (B+11) +#define I_CD_ITEMINDEX (C+0) + { PD_LONG, &carDlgItemIndex, "index", PDO_NOPREF|PDO_DLGWIDE, &i1_999999999, N_("Index"), 0 }, +#define I_CD_PURPRC (C+1) + { PD_STRING, &carDlgPurchPriceStr, "purchPrice", PDO_NOPREF|PDO_DLGWIDE, (void*)50, N_("Purchase Price"), 0, &carDlgPurchPrice }, +#define I_CD_CURPRC (C+2) + { PD_STRING, &carDlgCurrPriceStr, "currPrice", PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, (void*)50, N_("Current Price"), 0, &carDlgCurrPrice }, +#define I_CD_COND (C+3) + { PD_DROPLIST, &carDlgConditionInx, "condition", PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, (void*)90, N_("Condition") }, +#define I_CD_PURDAT (C+4) + { PD_STRING, &carDlgPurchDateStr, "purchDate", PDO_NOPREF|PDO_DLGWIDE, (void*)80, N_("Purchase Date"), 0, &carDlgPurchDate }, +#define I_CD_SRVDAT (C+5) + { PD_STRING, &carDlgServiceDateStr, "serviceDate", PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, (void*)80, N_("Service Date"), 0, &carDlgServiceDate }, +#define I_CD_QTY (C+6) + { PD_LONG, &carDlgQuantity, "quantity", PDO_NOPREF|PDO_DLGWIDE, &i1_9999, N_("Quantity") }, +#define I_CD_MLTNUM (C+7) + { PD_RADIO, &carDlgMultiNum, "multinum", PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, multinumLabels, N_("Numbers"), BC_HORZ|BC_NOBORDER }, +#define I_CD_NOTES (C+8) + { PD_TEXT, NULL, "notes", PDO_NOPREF|PDO_DLGWIDE|PDO_DLGNOLABELALIGN|PDO_DLGRESETMARGIN, ¬esData, N_("Notes") }, + +#define D (C+9) +#define I_CD_MSG (D+0) + { PD_MESSAGE, NULL, NULL, PDO_DLGNOLABELALIGN|PDO_DLGRESETMARGIN|PDO_DLGBOXEND, (void*)450 }, +#define I_CD_NEW (D+1) + { PD_MENU, NULL, "new-menu", PDO_DLGCMDBUTTON, NULL, N_("New"), 0, (void*)0 }, + { PD_MENUITEM, (void*)CarDlgNewDesc, "new-part-mi", 0, NULL, N_("Car Part"), 0, (void*)0 }, + { PD_MENUITEM, (void*)CarDlgNewProto, "new-proto-mi", 0, NULL, N_("Car Prototype"), 0, (void*)0 }, +#define I_CD_NEWPROTO (D+4) + { PD_BUTTON, (void*)CarDlgNewProto, "new", PDO_DLGCMDBUTTON, NULL, N_("New"), 0, (void*)0 } }; + +static paramGroup_t carDlgPG = { "carpart", 0, carDlgPLs, sizeof carDlgPLs/sizeof carDlgPLs[0] }; + + +static dynArr_t carDlgSegs_da; +#define carDlgSegs(N) DYNARR_N( trkSeg_t, carDlgSegs_da, N ) + + +typedef enum { + T_ItemSel, T_ItemEnter, T_ProtoSel, T_ProtoEnter, T_PartnoSel, T_PartnoEnter } carDlgTransistion_e; +static char *carDlgTransistion_s[] = { + "ItemSel", "ItemEnter", "ProtoSel", "ProtoEnter", "PartnoSel", "PartnoEnter" }; +typedef enum { + S_Error, + S_ItemSel, S_ItemEnter, S_PartnoSel, S_PartnoEnter, S_ProtoSel } carDlgState_e; +static char *carDlgState_s[] = { + "Error", + "ItemSel", "ItemEnter", "PartnoSel", "PartnoEnter", "ProtoSel" }; +typedef enum { + A_Return, + A_SError, + A_Else, + A_SItemSel, + A_SItemEnter, + A_SPartnoSel, + A_SPartnoEnter, + A_SProtoSel, + A_IsCustom, + A_IsNewPart, + A_IsNewProto, + A_LoadDataFromPartList, + A_LoadDimsFromStack, + A_LoadManufListForScale, + A_LoadManufListAll, + A_LoadProtoListForManuf, + A_LoadProtoListAll, + A_LoadPartnoList, + A_LoadLists, + A_LoadDimsFromProtoList, + A_ConvertDimsToProto, + A_Redraw, + A_ClrManuf, + A_ClrPartnoStr, + A_ClrNumberStr, + A_LoadProtoStrFromList, + A_ShowPartnoList, + A_HidePartnoList, + A_PushDims, + A_PopDims, + A_PopTitleAndTypeinx, + A_PopCouplerLength, + A_ShowControls, + A_LoadInfoFromUpdateItem, + A_LoadDataFromUpdatePart, + A_InitProto, + A_RecallCouplerLength, + A_Last + } carDlgAction_e; +static char *carDlgAction_s[] = { + "Return", + "SError", + "Else", + "SItemSel", + "SItemEnter", + "SPartnoSel", + "SPartnoEnter", + "SProtoSel", + "IsCustom", + "IsNewPart", + "IsNewProto", + "LoadDataFromPartList", + "LoadDimsFromStack", + "LoadManufListForScale", + "LoadManufListAll", + "LoadProtoListForManuf", + "LoadProtoListAll", + "LoadPartnoList", + "LoadLists", + "LoadDimsFromProtoList", + "ConvertDimsToProto", + "Redraw", + "ClrManuf", + "ClrPartnoStr", + "ClrNumberStr", + "LoadProtoStrFromList", + "ShowPartnoList", + "HidePartnoList", + "PushDims", + "PopDims", + "PopTitleAndTypeinx", + "PopCouplerLength", + "ShowControls", + "LoadInfoFromUpdateItem", + "LoadDataFromUpdatePart", + "InitProto", + "RecallCouplerLength", + "Last" + }; +static carDlgAction_e stateMachine[7][7][10] = { +/* A_SError */{ {A_SError}, {A_SError}, {A_SError}, {A_SError}, {A_SError}, {A_SError}, {A_SError} }, + +/*A_SItemSel*/{ +/*T_ItemSel*/ { A_LoadProtoListForManuf, A_LoadPartnoList, A_LoadDataFromPartList, A_Redraw }, +/*T_ItemEnter*/ { A_SItemEnter, A_LoadProtoListAll, A_ClrPartnoStr, A_ClrNumberStr, A_LoadDimsFromProtoList, A_Redraw, A_HidePartnoList }, +/*T_ProtoSel*/ { A_LoadPartnoList, A_LoadDataFromPartList, A_Redraw }, +/*T_ProtoEnter*/ { A_SError }, +/*T_PartnoSel*/ { A_LoadDataFromPartList, A_Redraw }, +/*T_PartnoEnter*/{ A_SItemEnter, A_LoadProtoListAll, A_HidePartnoList } }, + +/*A_SItemEnter*/{ +/*T_ItemSel*/ { A_SItemSel, A_LoadProtoListForManuf, A_LoadPartnoList, A_LoadDataFromPartList, A_Redraw, A_ShowPartnoList }, +/*T_ItemEnter*/ { A_Return }, +/*T_ProtoSel*/ { A_LoadDimsFromProtoList, A_Redraw }, +/*T_ProtoEnter*/ { A_SError }, +/*T_PartnoSel*/ { A_SError }, +/*T_PartnoEnter*/{ A_Return } }, + +/*A_SPartnoSel*/{ +/*T_ItemSel*/ { A_SPartnoSel }, +/*T_ItemEnter*/ { A_SPartnoSel }, +/*T_ProtoSel*/ { A_SPartnoSel, A_LoadDimsFromProtoList, A_Redraw }, +/*T_ProtoEnter*/ { A_SError }, +/*T_PartnoSel*/ { A_SError } }, + +/*A_SPartnoEnter*/{ +/*T_ItemSel*/ { A_SPartnoSel }, +/*T_ItemEnter*/ { A_SPartnoEnter }, +/*T_ProtoSel*/ { A_SPartnoEnter, A_LoadDimsFromProtoList, A_Redraw }, +/*T_ProtoEnter*/ { A_SError }, +/*T_PartnoSel*/ { A_SError }, +/*T_PartnoEnter*/{ A_SPartnoEnter } }, + +/*A_SProtoSel*/{ +/*T_ItemSel*/ { A_SError }, +/*T_ItemEnter*/ { A_SError }, +/*T_ProtoSel*/ { A_SError }, +/*T_ProtoEnter*/ { A_SProtoSel }, +/*T_PartnoSel*/ { A_SError }, +/*T_PartnoEnter*/{ A_SError } } }; + +static carDlgAction_e itemNewActions[] = { + A_RecallCouplerLength, + A_LoadLists, + A_IsCustom, 2+3, + A_LoadDimsFromProtoList, A_ClrPartnoStr, A_ClrNumberStr, + A_Else, 1, + A_LoadDataFromPartList, + A_ShowControls, A_Return }; +static carDlgAction_e itemUpdActions[] = { A_LoadInfoFromUpdateItem, /*A_LoadManufListForScale, + A_IsCustom, 5, + A_LoadProtoListAll, A_HidePartnoList, A_SItemEnter, + A_Else, 5, + A_LoadProtoListForManuf, A_LoadPartnoList, A_LoadDataFromPartList, A_ShowPartnoList, A_SItemSel,*/ + A_ShowControls, A_Return }; + +static carDlgAction_e partNewActions[] = { A_RecallCouplerLength, A_LoadManufListAll, A_LoadProtoListAll, A_ClrPartnoStr, A_ClrNumberStr, A_SPartnoSel, A_LoadDimsFromProtoList, A_ShowControls, A_Redraw, A_Return }; +static carDlgAction_e partUpdActions[] = { A_LoadDataFromUpdatePart, A_SPartnoSel, A_ShowControls, A_Return }; + +static carDlgAction_e protoNewActions[] = { A_InitProto, A_SProtoSel, A_ShowControls, A_Return }; +static carDlgAction_e protoUpdActions[] = { A_InitProto, A_SProtoSel, A_ShowControls, A_Return }; + +static carDlgAction_e item2partActions[] = { + A_PushDims, A_LoadManufListAll, A_LoadProtoListAll, + A_IsCustom, 0+1, + A_ClrManuf, + A_SPartnoSel, + A_ShowControls, A_Return }; +static carDlgAction_e part2itemActions[] = { + A_IsNewPart, 2+0, + A_Else, 1, + A_PopTitleAndTypeinx, + A_LoadLists, + A_IsCustom, 2+1, + A_LoadDimsFromProtoList, + A_Else, 1, + A_LoadDataFromPartList, +#ifdef LATER + A_IsNewPart, 2+0, + A_Else, 1, + A_LoadDimsFromStack, +#endif + A_ShowControls, + A_Return }; + +static carDlgAction_e item2protoActions[] = { A_PushDims, A_ConvertDimsToProto, A_SProtoSel, A_ShowControls, A_Return }; +static carDlgAction_e proto2itemActions[] = { + A_IsCustom, 2+2+3, + A_IsNewProto, 2+3, + A_LoadProtoListAll, + A_PopCouplerLength, + A_LoadDimsFromProtoList, + A_Else, 2, + A_LoadDimsFromStack, + A_LoadProtoStrFromList, + A_ShowControls, + A_Return }; + +static carDlgAction_e part2protoActions[] = { A_PushDims, A_ConvertDimsToProto, A_SProtoSel, A_ShowControls, A_Return }; +static carDlgAction_e proto2partActions[] = { + A_IsNewProto, 2+3, + A_LoadProtoListAll, + A_PopCouplerLength, + A_LoadDimsFromProtoList, + A_Else, 2, + A_LoadDimsFromStack, + A_LoadProtoStrFromList, + A_ShowControls, + A_Return }; + + +#define CARDLG_STK_SIZE (2) +int carDlgStkPtr = 0; +struct { + carDim_t dim; + DIST_T couplerLength; + carDlgState_e state; + int changed; + carPart_p partP; + wIndex_t typeInx; + } carDlgStk[CARDLG_STK_SIZE]; + +static carDlgState_e currState = S_Error; +#define S_ITEM (currState==S_ItemSel||currState==S_ItemEnter) +#define S_PART (currState==S_PartnoSel) +#define S_PROTO (currState==S_ProtoSel) + + + +static void CarDlgLoadDimsFromPart( carPart_p partP ) +{ + tabString_t tabs[7]; + + if ( partP == NULL ) return; + carDlgDim = partP->dim; + carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0; + sprintf( message, "%s-%s", carDlgPLs[I_CD_CPLRLEN].nameStr, GetScaleName(carDlgScaleInx) ); + wPrefSetFloat( carDlgPG.nameStr, message, carDlgCouplerLength ); + carDlgIsLoco = (partP->options&CAR_DESC_IS_LOCO)?1:0; + carDlgBodyColor = partP->color; + ParamLoadControl( &carDlgPG, I_CD_CARLENGTH ); + ParamLoadControl( &carDlgPG, I_CD_CARWIDTH ); + ParamLoadControl( &carDlgPG, I_CD_TRKCENTER ); + ParamLoadControl( &carDlgPG, I_CD_CPLDLEN ); + wColorSelectButtonSetColor( (wButton_p)carDlgPLs[I_CD_BODYCOLOR].control, *(wDrawColor*)carDlgPLs[I_CD_BODYCOLOR].valueP ); + TabStringExtract( partP->title, 7, tabs ); +} + + +static void CarDlgLoadDimsFromProto( carProto_p protoP ) +{ + DIST_T ratio = GetScaleRatio(carDlgScaleInx); + carDlgDim.carLength = protoP->dim.carLength/ratio; + carDlgDim.carWidth = protoP->dim.carWidth/ratio; + carDlgDim.truckCenter = protoP->dim.truckCenter/ratio; + carDlgDim.coupledLength = carDlgDim.carLength + carDlgCouplerLength*2; + /*carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0;*/ + carDlgIsLoco = (protoP->options&CAR_DESC_IS_LOCO)?1:0; + ParamLoadControl( &carDlgPG, I_CD_CARLENGTH ); + ParamLoadControl( &carDlgPG, I_CD_CARWIDTH ); + ParamLoadControl( &carDlgPG, I_CD_TRKCENTER ); + ParamLoadControl( &carDlgPG, I_CD_CPLDLEN ); +} + + +static void CarDlgRedraw( void ) +{ + wPos_t w, h; + DIST_T ww, hh; + DIST_T scale_w, scale_h; + coOrd orig, pos, size; + carProto_p protoP; + FLOAT_T ratio; + int segCnt; + trkSeg_p segPtr; + + if ( S_PROTO ) + ratio = 1; + else + ratio = 1/GetScaleRatio(carDlgScaleInx); + wDrawClear( carDlgD.d ); + if ( carDlgDim.carLength <= 0 || carDlgDim.carWidth <= 0 ) + return; + FreeFilledDraw( carDlgSegs_da.cnt, &carDlgSegs(0) ); + if ( !S_PROTO ) { + if ( carDlgProtoInx < 0 || + (protoP = CarProtoLookup( carDlgProtoStr, FALSE, FALSE, 0.0, 0.0 )) == NULL || + protoP->segCnt == 0 ) { + CarProtoDlgCreateDummyOutline( &segCnt, &segPtr, (BOOL_T)carDlgIsLoco, carDlgDim.carLength, carDlgDim.carWidth, carDlgBodyColor ); + } else { + segCnt = protoP->segCnt; + segPtr = protoP->segPtr; + } + } else { + if ( carProtoSegCnt <= 0 ) { + CarProtoDlgCreateDummyOutline( &segCnt, &segPtr, (BOOL_T)carDlgIsLoco, carDlgDim.carLength, carDlgDim.carWidth, drawColorBlue ); + } else { + segCnt = carProtoSegCnt; + segPtr = carProtoSegPtr; + } + } + DYNARR_SET( trkSeg_t, carDlgSegs_da, segCnt ); + memcpy( &carDlgSegs(0), segPtr, segCnt * sizeof *(trkSeg_t*)0 ); + CloneFilledDraw( carDlgSegs_da.cnt, &carDlgSegs(0), TRUE ); + GetSegBounds( zero, 0.0, carDlgSegs_da.cnt, &carDlgSegs(0), &orig, &size ); + scale_w = carDlgDim.carLength/size.x; + scale_h = carDlgDim.carWidth/size.y; + RescaleSegs( carDlgSegs_da.cnt, &carDlgSegs(0), scale_w, scale_h, ratio ); + if ( !S_PROTO ) { + RecolorSegs( carDlgSegs_da.cnt, &carDlgSegs(0), carDlgBodyColor ); + } else { + if ( carDlgFlipToggle ) { + pos.x = carDlgDim.carLength/2.0; + pos.y = carDlgDim.carWidth/2.0; + RotateSegs( carDlgSegs_da.cnt, &carDlgSegs(0), pos, 180.0 ); + } + } + + wDrawGetSize( carDlgD.d, &w, &h ); + ww = w/carDlgD.dpi-1.0; + hh = h/carDlgD.dpi-0.5; + scale_w = carDlgDim.carLength/ww; + scale_h = carDlgDim.carWidth/hh; + if ( scale_w > scale_h ) + carDlgD.scale = scale_w; + else + carDlgD.scale = scale_h; + orig.x = 0.50*carDlgD.scale; + orig.y = 0.25*carDlgD.scale; + DrawSegs( &carDlgD, orig, 0.0, &carDlgSegs(0), carDlgSegs_da.cnt, 0.0, wDrawColorBlack ); + pos.y = orig.y+carDlgDim.carWidth/2.0; + + if ( carDlgDim.truckCenter > 0.0 ) { + pos.x = orig.x+(carDlgDim.carLength-carDlgDim.truckCenter)/2.0; + CarProtoDrawTruck( &carDlgD, trackGauge*curScaleRatio, ratio, pos, 0.0 ); + pos.x = orig.x+(carDlgDim.carLength+carDlgDim.truckCenter)/2.0; + CarProtoDrawTruck( &carDlgD, trackGauge*curScaleRatio, ratio, pos, 0.0 ); + } + if ( carDlgDim.coupledLength > carDlgDim.carLength ) { + pos.x = orig.x; + CarProtoDrawCoupler( &carDlgD, (carDlgDim.coupledLength-carDlgDim.carLength)/2.0, ratio, pos, 270.0 ); + pos.x = orig.x+carDlgDim.carLength; + CarProtoDrawCoupler( &carDlgD, (carDlgDim.coupledLength-carDlgDim.carLength)/2.0, ratio, pos, 90.0 ); + } +} + + + +static void CarDlgLoadRoadnameList( void ) +/* Loads RoadnameList. + * Set carDlgRoadnameInx to entry matching carDlgRoadnameStr (if found) + * Otherwise not set + */ +{ + wIndex_t inx; + roadnameMap_p roadnameMapP; + + if ( !roadnameMapChanged ) return; + wListClear( (wList_p)carDlgPLs[I_CD_ROADNAME_LIST].control ); + wListAddValue( (wList_p)carDlgPLs[I_CD_ROADNAME_LIST].control, _("Undecorated"), NULL, NULL ); + for ( inx=0; inx<roadnameMap_da.cnt; inx++ ) { + roadnameMapP = DYNARR_N(roadnameMap_p, roadnameMap_da, inx); + wListAddValue( (wList_p)carDlgPLs[I_CD_ROADNAME_LIST].control, roadnameMapP->roadname, NULL, roadnameMapP ); + if ( strcasecmp( carDlgRoadnameStr, roadnameMapP->roadname )==0 ) + carDlgRoadnameInx = inx+1; + } + roadnameMapChanged = FALSE; +} + + +static BOOL_T CheckAvail( + carPartParent_p parentP ) +{ + wIndex_t inx; + carPart_p partP; + for ( inx=0; inx<parentP->parts_da.cnt; inx++ ) { + partP = carPart(parentP,inx); + if ( IsParamValid(partP->paramFileIndex) ) + return TRUE; + } + return FALSE; +} + + +static BOOL_T CarDlgLoadManufList( + BOOL_T bLoadAll, + BOOL_T bInclCustomUnknown, + SCALEINX_T scale ) +{ + carPartParent_p manufP, manufP1; + wIndex_t inx, listInx=-1; + BOOL_T found = TRUE; + char * firstName = NULL; + +LOG( log_carDlgList, 3, ( "CarDlgLoadManufList( %s, %s, %d )\n carDlgManufStr=\"%s\"\n", bLoadAll?"TRUE":"FALSE", bInclCustomUnknown?"TRUE":"FALSE", scale, carDlgManufStr ) ) + carDlgManufInx = -1; + manufP1 = NULL; + wListClear( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control ); + for ( inx=0; inx<carPartParent_da.cnt; inx++ ) { + manufP = carPartParent(inx); + if ( manufP1!=NULL && strcasecmp( manufP1->manuf, manufP->manuf ) == 0 ) + continue; + if ( bLoadAll==FALSE && manufP->scale != scale ) + continue; + if ( !CheckAvail(manufP) ) + continue; + listInx = wListAddValue( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, manufP->manuf, NULL, (void*)manufP ); + if ( carDlgManufInx < 0 && ( carDlgManufStr[0] == '\0' || strcasecmp( carDlgManufStr, manufP->manuf ) == 0 ) ) { +LOG( log_carDlgList, 4, ( " found manufStr (inx=%d, listInx=%d)\n", inx, listInx ) ) + carDlgManufInx = listInx; + if ( carDlgManufStr[0] == '\0' ) strcpy( carDlgManufStr, manufP->manuf ); + } + if ( firstName == NULL ) + firstName = manufP->manuf; + manufP1 = manufP; + } + if ( bInclCustomUnknown ) { + listInx = wListAddValue( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, _("Custom"), NULL, (void*)NULL ); + if ( carDlgManufInx < 0 && ( carDlgManufStr[0] == '\0' || strcasecmp( carDlgManufStr, "Custom" ) == 0 ) ) { +LOG( log_carDlgList, 4, ( " found Cus manufStr (inx=%d, listInx=%d)\n", inx, listInx ) ) + carDlgManufInx = listInx; + if ( carDlgManufStr[0] == '\0' ) strcpy( carDlgManufStr, _("Custom") ); + } + if ( firstName == NULL ) + firstName = "Custom"; + wListAddValue( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, _("Unknown"), NULL, (void*)NULL ); + if ( carDlgManufInx < 0 && ( carDlgManufStr[0] == '\0' || strcasecmp( carDlgManufStr, "Unknown" ) == 0 ) ) { +LOG( log_carDlgList, 4, ( " found Unk manufStr (inx=%d, listInx=%d)\n", inx, listInx ) ) + carDlgManufInx = listInx; + if ( carDlgManufStr[0] == '\0' ) strcpy( carDlgManufStr, _("Unknown") ); + } + } + if ( carDlgManufInx < 0 ) { + found = FALSE; + if ( firstName != NULL ) { +LOG( log_carDlgList, 4, ( " didn't find manufStr, using [0] = %s\n", firstName ) ) + carDlgManufInx = 0; + strcpy( carDlgManufStr, firstName ); + } + } + return found; +} + + +static BOOL_T CarDlgLoadProtoList( + char * manuf, + SCALEINX_T scale, + BOOL_T loadTypeList ) +{ + carPartParent_p parentP; + wIndex_t inx, listInx, inx1; + BOOL_T found; + carProto_p protoP; + carPart_p partP; + char * firstName; + int typeCount[N_TYPELISTMAP]; + int listTypeInx, currTypeInx; + + listTypeInx = -1; + carDlgProtoInx = -1; + firstName = NULL; + + wListClear( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control ); + memset( typeCount, 0, N_TYPELISTMAP * sizeof typeCount[0] ); +LOG( log_carDlgList, 3, ( "CarDlgLoadProtoList( %s, %d, %s )\n carDlgProtoStr=\"%s\", carDlgTypeInx=%d\n", manuf?manuf:"NULL", scale, loadTypeList?"TRUE":"FALSE", carDlgProtoStr, carDlgTypeInx ) ) + if ( manuf==NULL ) { + if ( carProto_da.cnt <= 0 ) return FALSE; + if ( listTypeInx < 0 && carDlgProtoStr[0] && (protoP=CarProtoFind(carDlgProtoStr)) ) + listTypeInx = CarProtoFindTypeCode(protoP->type); + if ( listTypeInx < 0 ) + listTypeInx = CarProtoFindTypeCode(carProto(0)->type); + for ( inx=0; inx<carProto_da.cnt; inx++ ) { + protoP = carProto(inx); + currTypeInx = CarProtoFindTypeCode(protoP->type); + typeCount[currTypeInx]++; + if ( carDlgTypeInx >= 0 && + listTypeInx != carDlgTypeInx && + currTypeInx == carDlgTypeInx ) { +LOG( log_carDlgList, 4, ( " found typeinx, reset list (old=%d)\n", listTypeInx ) ) + wListClear( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control ); + listTypeInx = carDlgTypeInx; + carDlgProtoInx = -1; + firstName = NULL; + } + if ( currTypeInx != listTypeInx ) continue; + listInx = wListAddValue( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, protoP->desc, NULL, (void*)protoP ); + if ( carDlgProtoInx < 0 && carDlgProtoStr[0] && strcasecmp( carDlgProtoStr, protoP->desc ) == 0 ) { +LOG( log_carDlgList, 4, ( " found protoStr (inx=%d, listInx=%d)\n", inx, listInx ) ) + carDlgProtoInx = listInx; + if ( carDlgProtoStr[0] == '\0' ) strcpy( carDlgProtoStr, protoP->desc ); + } + if ( firstName == NULL ) + firstName = protoP->desc; + } + } else { + for ( inx=0; inx<carPartParent_da.cnt; inx++ ) { + parentP = carPartParent(inx); + if ( strcasecmp( manuf, parentP->manuf ) != 0 || + scale != parentP->scale ) + continue; + if ( !CheckAvail(parentP) ) + continue; + found = FALSE; + for ( inx1=0; inx1<parentP->parts_da.cnt; inx1++ ) { + partP = carPart( parentP, inx1 ); + currTypeInx = CarProtoFindTypeCode(partP->type); + typeCount[currTypeInx]++; + if ( listTypeInx < 0 ) + listTypeInx = currTypeInx; + if ( carDlgTypeInx >= 0 && + listTypeInx != carDlgTypeInx && + currTypeInx == carDlgTypeInx ) { +LOG( log_carDlgList, 4, ( " found typeinx, reset list (old=%d)\n", listTypeInx ) ) + wListClear( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control ); + listTypeInx = carDlgTypeInx; + carDlgProtoInx = -1; + firstName = NULL; + } + if ( listTypeInx == currTypeInx ) + found = TRUE; + } + if ( !found ) + continue; + listInx = wListAddValue( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, parentP->proto, NULL, (void*)parentP ); + if ( carDlgProtoInx < 0 && ( carDlgProtoStr[0] == '\0' || strcasecmp( carDlgProtoStr, parentP->proto ) == 0 ) ) { +LOG( log_carDlgList, 4, ( " found protoStr (inx=%d, listInx=%d)\n", inx, listInx ) ) + carDlgProtoInx = listInx; + if ( carDlgProtoStr[0] == '\0' ) { + strcpy( carDlgProtoStr, parentP->proto ); + } + } + if ( firstName == NULL ) + firstName = parentP->proto; + } + } + + found = TRUE; + if ( carDlgProtoInx < 0 ) { + found = FALSE; + if ( firstName != NULL ) { +LOG( log_carDlgList, 4, ( " didn't find protoStr, using [0] = %s\n", firstName ) ) + carDlgProtoInx = 0; + strcpy( carDlgProtoStr, firstName ); + } + } + wListSetIndex( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoInx ); + + if ( loadTypeList ) { +LOG( log_carDlgList, 4, ( " loading typelist\n" ) ) + wListClear( (wList_p)carDlgPLs[I_CD_PROTOKIND_LIST].control ); + for ( currTypeInx=0; currTypeInx<N_TYPELISTMAP; currTypeInx++ ) { + if ( typeCount[currTypeInx] > 0 ) { + listInx = wListAddValue( (wList_p)carDlgPLs[I_CD_PROTOKIND_LIST].control, _(typeListMap[currTypeInx].name), NULL, (void*)(intptr_t)currTypeInx ); + if ( currTypeInx == listTypeInx ) { +LOG( log_carDlgList, 4, ( " current = %d\n", listInx ) ) + carDlgKindInx = listInx; + } + } + } + } + + return found; +} + + +static void ConstructPartDesc( + tabString_t * tabs ) +{ + char * cp; + cp = message; + *cp = '\0'; + if ( tabs[T_PART].len ) { + cp = TabStringCpy( cp, &tabs[T_PART] ); + *cp++ = ' '; + } + if ( tabs[T_DESC].len ) { + cp = TabStringCpy( cp, &tabs[T_DESC] ); + *cp++ = ' '; + } + if ( tabs[T_REPMARK].len ) { + cp = TabStringCpy( cp, &tabs[T_REPMARK] ); + *cp++ = ' '; + } else if ( tabs[T_ROADNAME].len ) { + cp = TabStringCpy( cp, &tabs[T_ROADNAME] ); + *cp++ = ' '; + } else { + strcpy( cp, _("Undecorated ") ); + cp += strlen( cp ); + } + if ( tabs[T_NUMBER].len ) { + cp = TabStringCpy( cp, &tabs[T_NUMBER] ); + *cp++ = ' '; + } + *cp = '\0'; +} + + +static BOOL_T CarDlgLoadPartList( carPartParent_p parentP ) +/* Loads PartList from parentP + * Set carDlgPartnoInx to entry matching carDlgPartnoStr (if set and found) + * Otherwise set carDlgPartnoInx and carDlgPartnoStr to 1st entry on list + * Set carDlgDescStr to found entry + */ +{ + wIndex_t listInx; + wIndex_t inx; + carPart_p partP; + carPart_t lastPart; + tabString_t tabs[7]; + BOOL_T found; + carPart_p selPartP; + + carDlgPartnoInx = -1; + wListClear( (wList_p)carDlgPLs[I_CD_PARTNO_LIST].control ); + if ( parentP==NULL ) { + carDlgPartnoStr[0] = '\0'; + carDlgDescStr[0] = '\0'; + return FALSE; + } + found = FALSE; + selPartP = NULL; + lastPart.title = NULL; + for ( inx=0; inx<parentP->parts_da.cnt; inx++ ) { + partP = carPart(parentP,inx); + TabStringExtract( partP->title, 7, tabs ); + ConstructPartDesc( tabs ); + lastPart.paramFileIndex = partP->paramFileIndex; + if ( message[0] && IsParamValid(partP->paramFileIndex) && + ( lastPart.title == NULL || Cmp_part( &lastPart, partP ) != 0 ) ) { + listInx = wListAddValue( (wList_p)carDlgPLs[I_CD_PARTNO_LIST].control, message, NULL, (void*)partP ); + if ( carDlgPartnoInx<0 && + (carDlgPartnoStr[0]?TabStringCmp( carDlgPartnoStr, &tabs[T_PART] ) == 0:TRUE) ) { + carDlgPartnoInx = listInx; + found = TRUE; + selPartP = partP; + } + if ( selPartP == NULL ) + selPartP = partP; + lastPart = *partP; + } + } + if ( selPartP == NULL ) { + carDlgPartnoStr[0] = '\0'; + carDlgDescStr[0] = '\0'; + } else { + if ( carDlgPartnoInx<0 ) + carDlgPartnoInx = 0; + TabStringExtract( selPartP->title, 7, tabs ); + TabStringCpy( carDlgPartnoStr, &tabs[T_PART] ); + TabStringCpy( carDlgDescStr, &tabs[T_DESC] ); + } + return found; +} + + + +static void CarDlgLoadPart( + carPart_p partP ) +{ + tabString_t tabs[7]; + roadnameMap_p roadnameMapP; + CarDlgLoadDimsFromPart( partP ); + carDlgBodyColor = partP->color; + carDlgTypeInx = CarProtoFindTypeCode( partP->type ); + carDlgIsLoco = ((partP->type)&1)!=0; + TabStringExtract( partP->title, 7, tabs ); + TabStringCpy( carDlgPartnoStr, &tabs[T_PART] ); + TabStringCpy( carDlgDescStr, &tabs[T_DESC] ); + roadnameMapP = LoadRoadnameList( &tabs[T_ROADNAME], &tabs[T_REPMARK] ); + carDlgRoadnameInx = lookupListIndex+1; + if ( roadnameMapP ) { + TabStringCpy( carDlgRoadnameStr, &tabs[T_ROADNAME] ); + CarDlgLoadRoadnameList(); + TabStringCpy( carDlgRepmarkStr, &tabs[T_REPMARK] ); + } else { + carDlgRoadnameInx = 0; + strcpy( carDlgRoadnameStr, _("Undecorated") ); + carDlgRepmarkStr[0] = '\0'; + } + TabStringCpy( carDlgNumberStr, &tabs[T_NUMBER] ); + carDlgBodyColor = partP->color; +} + + +static BOOL_T CarDlgLoadLists( + BOOL_T isItem, + tabString_t * tabs, + SCALEINX_T scale ) +{ + BOOL_T loadCustomUnknown = isItem; + DIST_T ratio; + carPartParent_p parentP; + static carProto_t protoTmp; + static char protoTmpDesc[STR_SIZE]; + + if ( tabs ) TabStringCpy( carDlgManufStr, &tabs[T_MANUF] ); + if ( strcasecmp( carDlgManufStr, "unknown" ) == 0 || + strcasecmp( carDlgManufStr, "custom" ) == 0 ) { + loadCustomUnknown = TRUE; + /*isItem = FALSE;*/ + } + if ( (!CarDlgLoadManufList( !isItem, loadCustomUnknown, scale )) && tabs ) { + TabStringCpy( carDlgManufStr, &tabs[T_MANUF] ); + carDlgManufInx = wListAddValue( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, carDlgManufStr, NULL, (void*)NULL ); + isItem = FALSE; + } + if ( isItem ) { + parentP = (carPartParent_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, carDlgManufInx ); + if ( parentP ) { + if ( tabs ) TabStringCpy( carDlgProtoStr, &tabs[T_PROTO] ); + if ( CarDlgLoadProtoList( carDlgManufStr, scale, TRUE ) || !tabs ) { + parentP = (carPartParent_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoInx ); + if ( parentP ) { + if ( tabs ) TabStringCpy( carDlgPartnoStr, &tabs[T_PART] ); + if ( CarDlgLoadPartList( parentP ) || ( (!tabs) && carDlgPartnoInx>=0 ) ) { + return TRUE; + } + } + } + } + } + if ( tabs ) TabStringCpy( carDlgProtoStr, &tabs[T_PROTO] ); + if ( !CarDlgLoadProtoList( NULL, 0, TRUE ) && tabs ) { + /* create dummy proto */ + ratio = GetScaleRatio( scale ); + protoTmp.contentsLabel = "temporary"; + protoTmp.paramFileIndex = PARAM_LAYOUT; + strcpy( protoTmpDesc, carDlgProtoStr ); + protoTmp.desc = protoTmpDesc; + protoTmp.options = (carDlgIsLoco?CAR_DESC_IS_LOCO:0); + protoTmp.type = typeListMap[carDlgTypeInx].value; + protoTmp.dim.carWidth = carDlgDim.carWidth*ratio; + protoTmp.dim.carLength = carDlgDim.carLength*ratio; + protoTmp.dim.coupledLength = carDlgDim.coupledLength*ratio; + protoTmp.dim.truckCenter = carDlgDim.truckCenter*ratio; + CarProtoDlgCreateDummyOutline( &carProtoSegCnt, &carProtoSegPtr, (BOOL_T)carDlgIsLoco, protoTmp.dim.carLength, protoTmp.dim.carWidth, drawColorBlue ); + protoTmp.segCnt = carProtoSegCnt; + protoTmp.segPtr = carProtoSegPtr; + GetSegBounds( zero, 0.0, carProtoSegCnt, carProtoSegPtr, &protoTmp.orig, &protoTmp.size ); + TabStringCpy( carDlgProtoStr, &tabs[T_PROTO] ); + carDlgProtoInx = wListAddValue( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoStr, NULL, &protoTmp );/*??*/ + } + carDlgPartnoInx = -1; + if ( tabs ) { + TabStringCpy( carDlgPartnoStr, &tabs[T_PART] ); + TabStringCpy( carDlgDescStr, &tabs[T_DESC] ); + } + return FALSE; +} + + +static void CarDlgShowControls( void ) +{ + + + /*ParamControlActive( &carDlgPG, I_CD_MANUF_LIST, S_ITEM||(S_PART&&carDlgUpdatePartPtr) );*/ + + ParamControlShow( &carDlgPG, I_CD_NEW, S_ITEM ); + ParamControlShow( &carDlgPG, I_CD_NEWPROTO, S_PART ); + + ParamControlShow( &carDlgPG, I_CD_ITEMINDEX, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_PURPRC, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_CURPRC, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_COND, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_PURDAT, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_SRVDAT, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_NOTES, S_ITEM && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_MLTNUM, S_ITEM && carDlgUpdateItemPtr==NULL && carDlgDispMode==0 ); + ParamControlShow( &carDlgPG, I_CD_QTY, S_ITEM && carDlgUpdateItemPtr==NULL && carDlgDispMode==0 ); + + ParamControlShow( &carDlgPG, I_CD_ROADNAME_LIST, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + ParamControlShow( &carDlgPG, I_CD_REPMARK, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + ParamControlShow( &carDlgPG, I_CD_NUMBER, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + ParamControlShow( &carDlgPG, I_CD_BODYCOLOR, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + ParamControlShow( &carDlgPG, I_CD_CARLENGTH, !( S_ITEM && carDlgDispMode==0 ) ); + ParamControlShow( &carDlgPG, I_CD_CARWIDTH, !( S_ITEM && carDlgDispMode==0 ) ); + ParamControlShow( &carDlgPG, I_CD_TRKCENTER, !( S_ITEM && carDlgDispMode==0 ) ); + ParamControlShow( &carDlgPG, I_CD_CANVAS, !( S_ITEM && carDlgDispMode==0 ) ); + ParamControlShow( &carDlgPG, I_CD_CPLRLEN, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + ParamControlShow( &carDlgPG, I_CD_CPLDLEN, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + ParamControlShow( &carDlgPG, I_CD_CPLRMNT, S_PART || ( S_ITEM && carDlgDispMode==1 ) ); + + ParamControlShow( &carDlgPG, I_CD_DISPMODE, S_ITEM ); + + ParamControlShow( &carDlgPG, I_CD_TYPE_LIST, S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_FLIP, S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_DESC_STR, S_PART || (currState==S_ItemEnter) ); + ParamControlShow( &carDlgPG, I_CD_IMPORT, S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_RESET, S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_PARTNO_STR, S_PART || (currState==S_ItemEnter) ); + ParamControlShow( &carDlgPG, I_CD_PARTNO_LIST, (currState==S_ItemSel) ); + ParamControlShow( &carDlgPG, I_CD_ISLOCO, S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_PROTOKIND_LIST, !S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_PROTOTYPE_LIST, !S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_PROTOTYPE_STR, S_PROTO ); + ParamControlShow( &carDlgPG, I_CD_MANUF_LIST, !S_PROTO ); + + /*ParamControlActive( &carDlgPG, I_CD_PROTOTYPE_STR, S_PROTO && carDlgUpdateProtoPtr==NULL );*/ + ParamControlActive( &carDlgPG, I_CD_ITEMINDEX, S_ITEM && carDlgUpdateItemPtr==NULL ); + ParamControlActive( &carDlgPG, I_CD_MLTNUM, S_ITEM && carDlgQuantity>1 ); + ParamControlActive( &carDlgPG, I_CD_IMPORT, selectedTrackCount > 0 ); + + ParamLoadMessage( &carDlgPG, I_CD_MSG, "" ); + + if ( S_ITEM ) { + if ( carDlgUpdateItemPtr == NULL ) { + sprintf( message, _("New %s Scale Car"), GetScaleName( carDlgScaleInx ) ); + wButtonSetLabel( carDlgPG.okB, _("Add") ); + } else { + sprintf( message, _("Update %s Scale Car"), GetScaleName( carDlgScaleInx ) ); + wButtonSetLabel( carDlgPG.okB, _("Update") ); + } + wWinSetTitle( carDlgPG.win, message ); + } else if ( S_PART ) { + if ( carDlgUpdatePartPtr == NULL ) { + sprintf( message, _("New %s Scale Car Part"), GetScaleName( carDlgScaleInx ) ); + wButtonSetLabel( carDlgPG.okB, _("Add") ); + } else { + sprintf( message, _("Update %s Scale Car Part"), GetScaleName( carDlgScaleInx ) ); + wButtonSetLabel( carDlgPG.okB, _("Update") ); + } + wWinSetTitle( carDlgPG.win, message ); + } else if ( S_PROTO ) { + if ( carDlgUpdateProtoPtr == NULL ) { + wWinSetTitle( carDlgPG.win, _("New Prototype") ); + wButtonSetLabel( carDlgPG.okB, _("Add") ); + } else { + wWinSetTitle( carDlgPG.win, _("Update Prototype") ); + wButtonSetLabel( carDlgPG.okB, _("Update") ); + } + } + + ParamLoadControls( &carDlgPG ); + + ParamDialogOkActive( &carDlgPG, S_ITEM ); + CarDlgUpdate( &carDlgPG, -1, NULL ); +} + + + +static void CarDlgDoActions( + carDlgAction_e * actions ) +{ + carPart_p partP; + carPartParent_p parentP; + carProto_p protoP; + wIndex_t inx; + int offset; + DIST_T ratio; + tabString_t tabs[7]; + char * cp; + BOOL_T reload[sizeof carDlgPLs/sizeof carDlgPLs[0]]; +#define RELOAD_DIMS \ + reload[I_CD_CARLENGTH] = reload[I_CD_CARWIDTH] = reload[I_CD_CPLDLEN] = \ + reload[I_CD_TRKCENTER] = reload[I_CD_CPLRLEN] = TRUE +#define RELOAD_PARTDATA \ + RELOAD_DIMS; \ + reload[I_CD_PARTNO_STR] = reload[I_CD_DESC_STR] = \ + reload[I_CD_ROADNAME_LIST] = reload[I_CD_REPMARK] = \ + reload[I_CD_NUMBER] = reload[I_CD_BODYCOLOR] = TRUE +#define RELOAD_LISTS \ + reload[I_CD_MANUF_LIST] = \ + reload[I_CD_PROTOKIND_LIST] = \ + reload[I_CD_PROTOTYPE_LIST] = \ + reload[I_CD_PARTNO_LIST] = TRUE + + memset( reload, 0, sizeof reload ); + while ( 1 ) { +LOG( log_carDlgState, 2, ( "Action = %s\n", carDlgAction_s[*actions] ) ) + switch ( *actions++ ) { + case A_Return: + for ( inx=0; inx<sizeof carDlgPLs/sizeof carDlgPLs[0]; inx++ ) + if ( reload[inx] ) + ParamLoadControl( &carDlgPG, inx ); + return; + case A_SError: + currState = S_Error; + break; + case A_Else: + offset = (int)*actions++; + actions += offset; + break; + case A_SItemSel: + currState = S_ItemSel; + break; + case A_SItemEnter: + currState = S_ItemEnter; + break; + case A_SPartnoSel: + currState = S_PartnoSel; + break; + case A_SPartnoEnter: + currState = S_PartnoEnter; + break; + case A_SProtoSel: + currState = S_ProtoSel; + break; + case A_IsCustom: + offset = (int)*actions++; + if ( currState != S_ItemEnter ) + actions += offset; + break; + case A_IsNewPart: + offset = (int)*actions++; + if (carDlgNewPartPtr==NULL) { + actions += offset; + } else { + TabStringExtract( carDlgNewPartPtr->title, 7, tabs ); + TabStringCpy( carDlgPartnoStr, &tabs[T_PART] ); + TabStringCpy( carDlgDescStr, &tabs[T_DESC] ); + reload[I_CD_PARTNO_STR] = reload[I_CD_DESC_STR] = TRUE; + } + break; + case A_IsNewProto: + offset = (int)*actions++; + if (carDlgNewProtoPtr==NULL) { + actions += offset; + } else { + strcpy( carDlgProtoStr, carDlgNewProtoPtr->desc ); + } + break; + case A_LoadDataFromPartList: + partP = (carPart_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_PARTNO_LIST].control, carDlgPartnoInx ); + if ( partP != NULL ){ + CarDlgLoadPart(partP); + RELOAD_PARTDATA; + RELOAD_PARTDATA; + } + break; + case A_LoadDimsFromStack: + carDlgDim = carDlgStk[carDlgStkPtr].dim; + carDlgCouplerLength = carDlgStk[carDlgStkPtr].couplerLength; + carDlgTypeInx = carDlgStk[carDlgStkPtr].typeInx; + carDlgIsLoco = (typeListMap[carDlgTypeInx].value&1) != 0; + RELOAD_DIMS; + break; + case A_LoadManufListForScale: + CarDlgLoadManufList( FALSE, TRUE, carDlgScaleInx ); + reload[I_CD_MANUF_LIST] = TRUE; + break; + case A_LoadManufListAll: + CarDlgLoadManufList( TRUE, FALSE, carDlgScaleInx ); + reload[I_CD_MANUF_LIST] = TRUE; + break; + case A_LoadProtoListForManuf: + parentP = (carPartParent_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, carDlgManufInx ); + CarDlgLoadProtoList( parentP->manuf, parentP->scale, TRUE ); + reload[I_CD_PROTOKIND_LIST] = TRUE; + reload[I_CD_PROTOTYPE_LIST] = TRUE; + break; + case A_LoadProtoListAll: + CarDlgLoadProtoList( NULL, 0, TRUE ); + reload[I_CD_PROTOKIND_LIST] = TRUE; + reload[I_CD_PROTOTYPE_LIST] = TRUE; + break; + case A_LoadPartnoList: + parentP = (carPartParent_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoInx ); + CarDlgLoadPartList( parentP ); + reload[I_CD_PARTNO_LIST] = TRUE; + break; + case A_LoadLists: + if ( CarDlgLoadLists( TRUE, NULL, carDlgScaleInx ) ) + currState = S_ItemSel; + else + currState = S_ItemEnter; + break; + case A_LoadDimsFromProtoList: + protoP = (carProto_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoInx ); + if ( protoP ) { + CarDlgLoadDimsFromProto( protoP ); + carDlgTypeInx = CarProtoFindTypeCode( protoP->type ); + carDlgIsLoco = (protoP->options&CAR_DESC_IS_LOCO)!=0; + } else { + ratio = GetScaleRatio( carDlgScaleInx ); + carDlgDim.carLength = 50*12/ratio; + carDlgDim.carWidth = 10*12/ratio; + carDlgDim.coupledLength = carDlgDim.carLength+carDlgCouplerLength*2; + carDlgDim.truckCenter = carDlgDim.carLength-59.0*2.0/ratio; + carDlgTypeInx = 0; + carDlgIsLoco = (typeListMap[0].value&1); + } + RELOAD_DIMS; + reload[I_CD_TYPE_LIST] = reload[I_CD_ISLOCO] = TRUE; + break; + case A_ConvertDimsToProto: + ratio = GetScaleRatio( carDlgScaleInx ); + carDlgDim.carLength *= ratio; + carDlgDim.carWidth *= ratio; + carDlgCouplerLength = 16.0; + carDlgDim.coupledLength = carDlgDim.carLength + 2 * carDlgCouplerLength; + carDlgDim.truckCenter *= ratio; + RELOAD_DIMS; + break; + case A_Redraw: + CarDlgRedraw(); + break; + case A_ClrManuf: + carDlgManufStr[0] = '\0'; + wListSetValue( (wList_p)carDlgPLs[I_CD_MANUF_LIST].control, "" ); + carDlgManufInx = -1; + break; + case A_ClrPartnoStr: + carDlgPartnoStr[0] = '\0'; + carDlgDescStr[0] = '\0'; + reload[I_CD_PARTNO_STR] = reload[I_CD_DESC_STR] = TRUE; + break; + case A_ClrNumberStr: + carDlgNumberStr[0] = '\0'; + reload[I_CD_NUMBER] = TRUE; + break; + case A_LoadProtoStrFromList: + wListGetValues( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoStr, sizeof carDlgProtoStr, NULL, NULL ); +#ifdef LATER + protoP = (carProto_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_PROTOTYPE_LIST].control, carDlgProtoInx ); + if ( protoP ) { + carDlgTypeInx = CarProtoFindTypeCode( protoP->type ); + carDlgIsLoco = (protoP->options&CAR_DESC_IS_LOCO)!=0; + } +#endif + break; + case A_ShowPartnoList: + reload[I_CD_PARTNO_LIST] = TRUE; + ParamControlShow( &carDlgPG, I_CD_PARTNO_LIST, TRUE ); + ParamControlShow( &carDlgPG, I_CD_DESC_STR, FALSE ); + ParamControlShow( &carDlgPG, I_CD_PARTNO_STR, FALSE ); + break; + case A_HidePartnoList: + reload[I_CD_PARTNO_STR] = reload[I_CD_DESC_STR] = TRUE; + ParamControlShow( &carDlgPG, I_CD_PARTNO_LIST, FALSE ); + ParamControlShow( &carDlgPG, I_CD_DESC_STR, TRUE ); + ParamControlShow( &carDlgPG, I_CD_PARTNO_STR, TRUE ); + break; + case A_PushDims: + if ( carDlgStkPtr >= CARDLG_STK_SIZE ) + AbortProg( "carDlgNewDesc: CARDLG_STK_SIZE" ); + carDlgStk[carDlgStkPtr].dim = carDlgDim; + carDlgStk[carDlgStkPtr].couplerLength = carDlgCouplerLength; + carDlgStk[carDlgStkPtr].state = currState; + carDlgStk[carDlgStkPtr].changed = carDlgChanged; + carDlgStk[carDlgStkPtr].typeInx = carDlgTypeInx; + if ( currState == S_ItemSel && carDlgPartnoInx >= 0 ) + carDlgStk[carDlgStkPtr].partP = (carPart_p)wListGetItemContext( (wList_p)carDlgPLs[I_CD_PARTNO_LIST].control, carDlgPartnoInx ); + else + carDlgStk[carDlgStkPtr].partP = NULL; + carDlgStkPtr++; + break; + case A_PopDims: + break; + case A_PopTitleAndTypeinx: + if ( carDlgStk[carDlgStkPtr].partP ) { + TabStringExtract( carDlgStk[carDlgStkPtr].partP->title, 7, tabs ); + strcpy( carDlgManufStr, carDlgStk[carDlgStkPtr].partP->parent->manuf ); + strcpy( carDlgProtoStr, carDlgStk[carDlgStkPtr].partP->parent->proto ); + TabStringCpy( carDlgPartnoStr, &tabs[T_PART] ); + TabStringCpy( carDlgDescStr, &tabs[T_DESC] ); + } + carDlgTypeInx = carDlgStk[carDlgStkPtr].typeInx; + break; + case A_PopCouplerLength: + carDlgCouplerLength = carDlgStk[carDlgStkPtr].couplerLength; + break; + case A_ShowControls: + CarDlgShowControls(); + break; + case A_LoadInfoFromUpdateItem: + carDlgScaleInx = carDlgUpdateItemPtr->scaleInx; + carDlgItemIndex = carDlgUpdateItemPtr->index; + TabStringExtract( carDlgUpdateItemPtr->title, 7, tabs ); + TabStringCpy( carDlgManufStr, &tabs[T_MANUF] ); + TabStringCpy( carDlgProtoStr, &tabs[T_PROTO] ); + TabStringCpy( carDlgRoadnameStr, &tabs[T_ROADNAME] ); + TabStringCpy( carDlgRepmarkStr, &tabs[T_REPMARK] ); + TabStringCpy( carDlgNumberStr, &tabs[T_NUMBER] ); + carDlgDim = carDlgUpdateItemPtr->dim; + carDlgBodyColor = carDlgUpdateItemPtr->color; + carDlgTypeInx = CarProtoFindTypeCode( carDlgUpdateItemPtr->type ); + carDlgIsLoco = (carDlgUpdateItemPtr->type&1)!=0; + carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0; + sprintf( message, "%s-%s", carDlgPLs[I_CD_CPLRLEN].nameStr, GetScaleName(carDlgScaleInx) ); + wPrefSetFloat( carDlgPG.nameStr, message, carDlgCouplerLength ); + carDlgCouplerMount = (carDlgUpdateItemPtr->options&CAR_DESC_COUPLER_MODE_BODY)!=0; + carDlgIsLoco = (carDlgUpdateItemPtr->options&CAR_DESC_IS_LOCO)!=0; + carDlgPurchPrice = carDlgUpdateItemPtr->data.purchPrice; + sprintf( carDlgPurchPriceStr, "%0.2f", carDlgPurchPrice ); + carDlgCurrPrice = carDlgUpdateItemPtr->data.currPrice; + sprintf( carDlgCurrPriceStr, "%0.2f", carDlgCurrPrice ); + carDlgCondition = carDlgUpdateItemPtr->data.condition; + carDlgConditionInx = MapCondition( carDlgUpdateItemPtr->data.condition ); + carDlgPurchDate = carDlgUpdateItemPtr->data.purchDate; + if ( carDlgPurchDate ) + sprintf( carDlgPurchDateStr, "%ld", carDlgPurchDate ); + else + carDlgPurchDateStr[0] = '\0'; + carDlgServiceDate = carDlgUpdateItemPtr->data.serviceDate; + if ( carDlgServiceDate ) + sprintf( carDlgServiceDateStr, "%ld", carDlgServiceDate ); + else + carDlgServiceDateStr[0] = '\0'; + wTextClear( (wText_p)carDlgPLs[I_CD_NOTES].control ); + if ( carDlgUpdateItemPtr->data.notes ) { + strncpy( message, carDlgUpdateItemPtr->data.notes, sizeof message ); + message[sizeof message - 1] = '\0'; + for ( cp=message; *cp; cp++ ) + if ( *cp == '\n' ) *cp = ' '; + wTextAppend( (wText_p)carDlgPLs[I_CD_NOTES].control, message ); + } + LoadRoadnameList( &tabs[T_ROADNAME], &tabs[T_REPMARK] ); + CarDlgLoadRoadnameList(); + carDlgRoadnameInx = lookupListIndex+1; + memset( reload, 1, sizeof reload ); + + if ( CarDlgLoadLists( TRUE, tabs, carDlgScaleInx ) ) + currState = S_ItemSel; + else + currState = S_ItemEnter; + break; + case A_LoadDataFromUpdatePart: + carDlgScaleInx = carDlgUpdatePartPtr->parent->scale; + TabStringExtract( carDlgUpdatePartPtr->title, 7, tabs ); + tabs[T_MANUF].ptr = carDlgUpdatePartPtr->parent->manuf; + tabs[T_MANUF].len = strlen(carDlgUpdatePartPtr->parent->manuf); + tabs[T_PROTO].ptr = carDlgUpdatePartPtr->parent->proto; + tabs[T_PROTO].len = strlen(carDlgUpdatePartPtr->parent->proto); + CarDlgLoadLists( FALSE, tabs, carDlgScaleInx ); + CarDlgLoadPart( carDlgUpdatePartPtr ); + RELOAD_LISTS; + RELOAD_DIMS; + RELOAD_PARTDATA; + break; + case A_InitProto: + if ( carDlgUpdateProtoPtr==NULL ) { + carDlgProtoStr[0] = 0; + carDlgDim.carLength = 50*12; + carDlgDim.carWidth = 10*12; + carDlgDim.coupledLength = carDlgDim.carLength+16.0*2.0; + carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0; + carDlgDim.truckCenter = carDlgDim.carLength-59.0*2.0; + carDlgIsLoco = (typeListMap[carDlgTypeInx].value&1); + } else { + strcpy( carDlgProtoStr , carDlgUpdateProtoPtr->desc ); + carDlgDim = carDlgUpdateProtoPtr->dim; + carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0; + carDlgIsLoco = (carDlgUpdateProtoPtr->options&CAR_DESC_IS_LOCO)!=0; + carDlgTypeInx = CarProtoFindTypeCode( carDlgUpdateProtoPtr->type ); + carProtoSegCnt = carDlgUpdateProtoPtr->segCnt; + carProtoSegPtr = carDlgUpdateProtoPtr->segPtr; + currState = S_ProtoSel; + } + RELOAD_DIMS; + break; + case A_RecallCouplerLength: + sprintf( message, "%s-%s", carDlgPLs[I_CD_CPLRLEN].nameStr, GetScaleName(carDlgScaleInx) ); + carDlgCouplerLength = 16.0/GetScaleRatio(carDlgScaleInx); + wPrefGetFloat( carDlgPG.nameStr, message, &carDlgCouplerLength, carDlgCouplerLength ); + break; + default: + AbortProg( "carDlgDoActions: bad action" ); + break; + } + } +} + + +static void CarDlgDoStateActions( + carDlgAction_e * actions ) +{ + CarDlgDoActions( actions ); +LOG( log_carDlgState, 1, ( " ==> S_%s\n", carDlgState_s[currState] ) ) +} + +static void CarDlgStateMachine( + carDlgTransistion_e transistion ) +{ +LOG( log_carDlgState, 1, ( "S_%s[T_%s]\n", carDlgState_s[currState], carDlgTransistion_s[transistion] ) ) + CarDlgDoStateActions( stateMachine[currState][transistion] ); +} + + +static BOOL_T CheckCarDlgItemIndex( long * index ) +{ + BOOL_T found = TRUE; + BOOL_T updated = FALSE; + + int inx; + carItem_p item; + while ( found ) { + found = FALSE; + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) { + item = carItemInfo(inx); + if ( item->index == *index ) { + (*index)++; + found = TRUE; + updated = TRUE; + break; + } + } + } + return !updated; +} + + +static void CarDlgUpdate( + paramGroup_p pg, + int inx, + void * valueP ) +{ + BOOL_T redraw = FALSE; + roadnameMap_p roadnameMapP; + char * cp, *cq; + long valL, d, m; + FLOAT_T ratio; + BOOL_T ok; + DIST_T len; + BOOL_T checkTruckCenter = FALSE; + cmp_key_t cmp_key; + coOrd orig, size, size2; + carPartParent_p parentP; + static DIST_T carDlgTruckOffset; + static long carDlgClock; + static long carDlgCarLengthClock; + static long carDlgTruckCenterClock; + static long carDlgCoupledLengthClock; + static long carDlgCouplerLengthClock; + + ratio = (S_PROTO?1.0:GetScaleRatio(carDlgScaleInx)); + +LOG( log_carDlgState, 3, ( "CarDlgUpdate( %d )\n", inx ) ) + + switch ( inx ) { + + case -1: + if ( carDlgDim.truckCenter > 0 && carDlgDim.carLength > carDlgDim.truckCenter ) + carDlgTruckOffset = carDlgDim.carLength - carDlgDim.truckCenter; + else + carDlgTruckOffset = 0; + carDlgCarLengthClock = carDlgCoupledLengthClock = carDlgTruckCenterClock = carDlgCouplerLengthClock = carDlgClock = 0; + redraw = TRUE; + break; + + case I_CD_MANUF_LIST: + carDlgChanged++; + wListGetValues( (wList_p)pg->paramPtr[inx].control, carDlgManufStr, sizeof carDlgManufStr, NULL, NULL ); + if ( carDlgManufInx < 0 || + wListGetItemContext( (wList_p)pg->paramPtr[inx].control, carDlgManufInx ) == NULL ) + CarDlgStateMachine( T_ItemEnter ); +#ifdef LATER + else if ( strcasecmp( carDlgManufStr, "unknown" ) == 0 || + strcasecmp( carDlgManufStr, "custom" ) == 0 ) + CarDlgStateMachine( T_ItemEnter ); +#endif + else + CarDlgStateMachine( T_ItemSel ); + /*ParamControlShow( &carDlgPG, I_CD_MANUF_LIST, TRUE );*/ + break; + + case I_CD_PROTOKIND_LIST: + carDlgChanged++; + carDlgTypeInx = (int)(long)wListGetItemContext( (wList_p)pg->paramPtr[inx].control, carDlgKindInx ); + if ( S_PART || (currState==S_ItemEnter) ) { + CarDlgLoadProtoList( NULL, 0, FALSE ); + } else { + parentP = NULL; + if ( carDlgProtoInx >= 0 ) + parentP = (carPartParent_p)wListGetItemContext( (wList_p)pg->paramPtr[I_CD_PROTOTYPE_LIST].control, carDlgProtoInx ); + CarDlgLoadProtoList( carDlgManufStr, (parentP?parentP->scale:0), FALSE ); + } + CarDlgStateMachine( T_ProtoSel ); + break; + + case I_CD_PROTOTYPE_LIST: + carDlgChanged++; + wListGetValues( (wList_p)pg->paramPtr[inx].control, carDlgProtoStr, sizeof carDlgProtoStr, NULL, NULL ); + CarDlgStateMachine( T_ProtoSel ); + break; + + case I_CD_PARTNO_LIST: + carDlgChanged++; + wListGetValues( (wList_p)pg->paramPtr[inx].control, carDlgPartnoStr, sizeof carDlgPartnoStr, NULL, NULL ); + if ( carDlgPartnoInx >= 0 ) { + CarDlgStateMachine( T_PartnoSel ); + } else { + CarDlgStateMachine( T_PartnoEnter ); + wControlSetFocus( pg->paramPtr[I_CD_PARTNO_STR].control ); + } + break; + + case I_CD_DISPMODE: + for ( inx=B; inx<C; inx++ ) + ParamControlShow( &carDlgPG, inx, carDlgDispMode==1 ); + for ( inx=C; inx<D; inx++ ) + ParamControlShow( &carDlgPG, inx, carDlgDispMode==0 ); + if ( carDlgDispMode == 0 && carDlgUpdateItemPtr != NULL ) { + ParamControlShow( &carDlgPG, I_CD_QTY, FALSE ); + ParamControlShow( &carDlgPG, I_CD_MLTNUM, FALSE ); + } + redraw = carDlgDispMode==1; + break; + + case I_CD_ROADNAME_LIST: + carDlgChanged++; + roadnameMapP = NULL; + if ( *(long*)valueP == 0 ) { + roadnameMapP = NULL; + carDlgRoadnameStr[0] = '\0'; + } else if ( *(long*)valueP > 0 ) { + roadnameMapP = (roadnameMap_p)wListGetItemContext( (wList_p)pg->paramPtr[I_CD_ROADNAME_LIST].control, (wIndex_t)*(long*)valueP ); + strcpy( carDlgRoadnameStr, roadnameMapP->roadname ); + } else { + wListGetValues( (wList_p)pg->paramPtr[I_CD_ROADNAME_LIST].control, carDlgRoadnameStr, sizeof carDlgRoadnameStr, NULL, NULL ); + cmp_key.name = carDlgRoadnameStr; + cmp_key.len = strlen(carDlgRoadnameStr); + roadnameMapP = LookupListElem( &roadnameMap_da, &cmp_key, Cmp_roadnameMap, 0 ); + } + if ( roadnameMapP ) { + strcpy( carDlgRepmarkStr, roadnameMapP->repmark ); + } else { + carDlgRepmarkStr[0] = '\0'; + } + ParamLoadControl( pg, I_CD_REPMARK ); + break; + + case I_CD_CARLENGTH: + carDlgChanged++; + if ( carDlgDim.carLength == 0.0 ) { + carDlgCarLengthClock = 0; + } else if ( carDlgDim.carLength < 100/ratio ) { + return; + } else if ( carDlgCouplerLength != 0 && ( carDlgDim.coupledLength == 0 || carDlgCouplerLengthClock >= carDlgCoupledLengthClock ) ) { + len = carDlgDim.carLength+carDlgCouplerLength*2.0; + if ( len > 0 ) { + carDlgDim.coupledLength = len; + ParamLoadControl( &carDlgPG, I_CD_CPLDLEN ); + } + carDlgCarLengthClock = ++carDlgClock; + } else if ( carDlgDim.coupledLength != 0 && ( carDlgCouplerLength == 0 || carDlgCoupledLengthClock > carDlgCouplerLengthClock ) ) { + len = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0; + if ( len > 0 ) { + carDlgCouplerLength = len; + ParamLoadControl( &carDlgPG, I_CD_CPLRLEN ); + if ( !S_PROTO ) { + sprintf( message, "%s-%s", carDlgPLs[I_CD_CPLRLEN].nameStr, GetScaleName(carDlgScaleInx) ); + wPrefSetFloat( carDlgPG.nameStr, message, carDlgCouplerLength ); + } + } + carDlgCarLengthClock = ++carDlgClock; + } + checkTruckCenter = TRUE; + redraw = TRUE; + break; + + case I_CD_CPLDLEN: + carDlgChanged++; + if ( carDlgDim.coupledLength == 0 ) { + carDlgCoupledLengthClock = 0; + } else if ( carDlgDim.coupledLength < 100/ratio ) { + return; + } else if ( carDlgDim.carLength != 0 && ( carDlgCouplerLength == 0 || carDlgCarLengthClock > carDlgCouplerLengthClock ) ) { + len = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0; + if ( len > 0 ) { + carDlgCouplerLength = len; + ParamLoadControl( &carDlgPG, I_CD_CPLRLEN ); + if ( !S_PROTO ) { + sprintf( message, "%s-%s", carDlgPLs[I_CD_CPLRLEN].nameStr, GetScaleName(carDlgScaleInx) ); + wPrefSetFloat( carDlgPG.nameStr, message, carDlgCouplerLength ); + } + } + carDlgCoupledLengthClock = ++carDlgClock; + } else if ( carDlgCouplerLength != 0 && ( carDlgDim.carLength == 0 || carDlgCouplerLengthClock >= carDlgCarLengthClock ) ) { + len = carDlgDim.coupledLength-carDlgCouplerLength*2.0; + if ( len > 0 ) { + carDlgDim.carLength = len; + ParamLoadControl( &carDlgPG, I_CD_CARLENGTH ); + checkTruckCenter = TRUE; + } + carDlgCoupledLengthClock = ++carDlgClock; + } + redraw = TRUE; + break; + + case I_CD_CPLRLEN: + carDlgChanged++; + if ( carDlgCouplerLength == 0 ) { + carDlgCouplerLengthClock = 0; + redraw = TRUE; + break; + } else if ( carDlgCouplerLength < 1/ratio ) { + return; + } else if ( carDlgDim.carLength != 0 && ( carDlgDim.coupledLength == 0 || carDlgCarLengthClock >= carDlgCoupledLengthClock ) ) { + len = carDlgDim.carLength+carDlgCouplerLength*2.0; + if ( len > 0 ) { + carDlgDim.coupledLength = carDlgDim.carLength+carDlgCouplerLength*2.0; + ParamLoadControl( &carDlgPG, I_CD_CPLDLEN ); + } + carDlgCouplerLengthClock = ++carDlgClock; + } else if ( carDlgDim.coupledLength != 0 && ( carDlgDim.carLength == 0 || carDlgCoupledLengthClock > carDlgCarLengthClock ) ) { + len = carDlgCouplerLength-carDlgDim.coupledLength*2.0; + if ( len > 0 ) { + carDlgDim.carLength = carDlgCouplerLength-carDlgDim.coupledLength*2.0; + ParamLoadControl( &carDlgPG, I_CD_CARLENGTH ); + checkTruckCenter = TRUE; + } + carDlgCouplerLengthClock = ++carDlgClock; + } + if ( !S_PROTO ) { + sprintf( message, "%s-%s", carDlgPLs[I_CD_CPLRLEN].nameStr, GetScaleName(carDlgScaleInx) ); + wPrefSetFloat( carDlgPG.nameStr, message, carDlgCouplerLength ); + } + redraw = TRUE; + break; + + case I_CD_CARWIDTH: + carDlgChanged++; + if ( carDlgDim.carLength < 30/ratio ) return; + redraw = TRUE; + break; + + case I_CD_BODYCOLOR: + carDlgChanged++; + RecolorSegs( carDlgSegs_da.cnt, &carDlgSegs(0), carDlgBodyColor ); + redraw = TRUE; + break; + + case I_CD_ISLOCO: + carDlgChanged++; + redraw = TRUE; + break; + + case I_CD_TRKCENTER: + carDlgChanged++; + if ( carDlgDim.truckCenter == 0 ) { + carDlgTruckOffset = 0; + } else if ( carDlgDim.truckCenter < 100/ratio /*&& carDlgDim.carLength == 0.0*/ ) { + return; + } else if ( carDlgDim.carLength > carDlgDim.truckCenter ) { + carDlgTruckOffset = carDlgDim.carLength - carDlgDim.truckCenter; + } else { + carDlgTruckOffset = 0; + } + redraw = TRUE; + break; + + case I_CD_QTY: + wControlActive( carDlgPLs[I_CD_MLTNUM].control, carDlgQuantity>1 ); + break; + + case I_CD_PURPRC: + case I_CD_CURPRC: + carDlgChanged++; + *(FLOAT_T*)(pg->paramPtr[inx].context) = strtod( (char*)pg->paramPtr[inx].valueP, &cp ); + if ( cp==NULL || *cp!='\0' ) + *(FLOAT_T*)(pg->paramPtr[inx].context) = -1; + break; + + case I_CD_COND: + carDlgChanged++; + carDlgCondition = + (carDlgConditionInx==0)?0: + (carDlgConditionInx==1)?100: + (carDlgConditionInx==2)?80: + (carDlgConditionInx==3)?60: + (carDlgConditionInx==4)?40:20; + break; + + case I_CD_PURDAT: + case I_CD_SRVDAT: + carDlgChanged++; + cp = (char*)pg->paramPtr[inx].valueP; + if ( *cp ) { + valL = strtol( cp, &cq, 10 ); + if ( cq==NULL || *cq!='\0' ) { + cp = N_("Enter a 8 digit numeric date"); + } else if ( valL != 0 ) { + if ( strlen(cp) != 8 ) { + cp = N_("Enter a 8 digit date"); + } else if ( valL < 19000101 || valL > 21991231 ) { + cp = N_("Enter a date between 19000101 and 21991231"); + } else { + d = valL % 100; + m = (valL / 100) % 100; + if ( m < 1 || m > 12 ) { + cp = N_("Invalid month"); + } else if ( d < 1 || d > 31 ) { + cp = N_("Invalid day"); + } else { + cp = NULL; + } + } + } + if ( cp ) { + valL = 0; + } + } else { + cp = NULL; + valL = 0; + } + wControlSetBalloon( pg->paramPtr[inx].control, 0, -5, _(cp) ); + *(long*)(pg->paramPtr[inx].context) = valL; + break; + + case I_CD_TYPE_LIST: + carDlgChanged++; + carDlgIsLoco = (typeListMap[carDlgTypeInx].value&1); + ParamLoadControl( &carDlgPG, I_CD_ISLOCO ); + redraw = TRUE; + break; + + case I_CD_IMPORT: + carDlgChanged++; + WriteSelectedTracksToTempSegs(); + carProtoSegCnt = tempSegs_da.cnt; + carProtoSegPtr = (trkSeg_t*)tempSegs_da.ptr; + CloneFilledDraw( carProtoSegCnt, carProtoSegPtr, TRUE ); + GetSegBounds( zero, 0.0, carProtoSegCnt, carProtoSegPtr, &orig, &size ); + if ( size.x <= 0.0 || + size.y <= 0.0 || + size.x < size.y ) { + NoticeMessage( MSG_CARPROTO_BADSEGS, _("Ok"), NULL ); + return; + } + orig.x = -orig.x; + orig.y = -orig.y; + MoveSegs( carProtoSegCnt, carProtoSegPtr, orig ); + size2.x = floor(size.x*curScaleRatio+0.5); + size2.y = floor(size.y*curScaleRatio+0.5); + RescaleSegs( carProtoSegCnt, carProtoSegPtr, size2.x/size.x, size2.y/size.y, curScaleRatio ); + carDlgDim.carLength = size2.x; + carDlgDim.carWidth = size2.y; + carDlgDim.coupledLength = carDlgDim.carLength + 32; + if ( carDlgDim.carLength > 120 ) { + carDlgDim.truckCenter = carDlgDim.carLength - 120; + carDlgTruckOffset = carDlgDim.carLength - carDlgDim.truckCenter; + } else { + carDlgDim.truckCenter = 0; + carDlgTruckOffset = 0; + } + carDlgFlipToggle = FALSE; + ParamLoadControl( &carDlgPG, I_CD_CARLENGTH ); + ParamLoadControl( &carDlgPG, I_CD_CARWIDTH ); + ParamLoadControl( &carDlgPG, I_CD_CPLRLEN ); + ParamLoadControl( &carDlgPG, I_CD_TRKCENTER ); + redraw = TRUE; + break; + + case I_CD_RESET: + carDlgChanged++; + carProtoSegCnt = 0; + redraw = TRUE; + break; + + case I_CD_FLIP: + carDlgChanged++; + carDlgFlipToggle = ! carDlgFlipToggle; + redraw = TRUE; + break; + + } + + if ( checkTruckCenter && carDlgDim.carLength > 0 ) { + if ( carDlgTruckOffset > 0 ) { + carDlgDim.truckCenter = carDlgDim.carLength - carDlgTruckOffset; + } else { + carDlgDim.truckCenter = carDlgDim.carLength * 0.75; + } + ParamLoadControl( &carDlgPG, I_CD_TRKCENTER ); + } + + ok = FALSE; + if ( S_PROTO && carDlgProtoStr[0] == '\0' ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter a Prototype name") ); + else if ( S_PART && carDlgManufStr[0] == '\0' ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Select or Enter a Manufacturer") ); + else if ( S_PART && carDlgPartnoStr[0] == '\0' ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter a Part Number") ); + else if ( carDlgDim.carLength <= 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Car Length") ); + else if ( carDlgDim.carWidth <= 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Car Width") ); + else if ( carDlgDim.truckCenter <= 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Truck Centers") ); + else if ( carDlgDim.truckCenter >= carDlgDim.carLength ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Truck Centers must be less than Car Length") ); + else if ( (!S_PROTO) && ( carDlgDim.coupledLength <= 0 || carDlgCouplerLength <= 0 ) ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Coupled Length or Coupler Length") ); + else if ( S_PROTO && carDlgDim.coupledLength <= 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Coupled Length") ); + else if ( S_ITEM && carDlgItemIndex <= 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter a item Index") ); + else if ( S_ITEM && carDlgPurchPrice < 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Purchase Price is not valid") ); + else if ( S_ITEM && carDlgCurrPrice < 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Current Price is not valid") ); + else if ( S_ITEM && carDlgPurchDate < 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Purchase Date is not valid") ); + else if ( S_ITEM && carDlgServiceDate < 0 ) + ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Service Date is not valid") ); + else if ( S_ITEM && carDlgUpdateItemPtr==NULL && + ( valL = carDlgItemIndex , !CheckCarDlgItemIndex(&carDlgItemIndex) ) ) { + sprintf( message, _("Item Index %ld duplicated an existing item: updated to new value"), valL ); + ParamLoadControl( &carDlgPG, I_CD_ITEMINDEX ); + ParamLoadMessage( &carDlgPG, I_CD_MSG, message ); + ok = TRUE; + } else { + ParamLoadMessage( pg, I_CD_MSG, "" ); + ok = TRUE; + } + + if ( redraw ) + CarDlgRedraw(); + + ParamDialogOkActive( pg, ok ); +} + + + +static void CarDlgNewDesc( void ) +{ + carDlgNewPartPtr = NULL; + carDlgNewProtoPtr = NULL; + carDlgUpdatePartPtr = NULL; + carDlgNumberStr[0] = '\0'; + ParamLoadControl( &carDlgPG, I_CD_NUMBER ); + CarDlgDoStateActions( item2partActions ); + carDlgChanged = 0; +} + + +static void CarDlgNewProto( void ) +{ + carProto_p protoP = CarProtoFind( carDlgProtoStr ); + if ( protoP != NULL ) { + carProtoSegCnt = protoP->segCnt;; + carProtoSegPtr = protoP->segPtr;; + } else { + carProtoSegCnt = 0; + carProtoSegPtr = NULL; + } + carDlgUpdateProtoPtr = NULL; + carDlgNewProtoPtr = NULL; + if ( S_ITEM ) + CarDlgDoStateActions( item2protoActions ); + else + CarDlgDoStateActions( part2protoActions ); + carDlgChanged = 0; +} + + +static void CarDlgClose( wWin_p win ) +{ + carDlgState_e oldState; + + if ( carDlgChanged ) { + if ( !inPlayback ) { + if ( NoticeMessage( MSG_CARDESC_CHANGED, _("Yes"), _("No") ) <= 0 ) + return; + } else { + PlaybackMessage( "Car Desc Changed\n" ); + } + } + if ( carDlgStkPtr > 0 ) { + carDlgStkPtr--; + oldState = currState; + currState = carDlgStk[carDlgStkPtr].state; + carDlgChanged = carDlgStk[carDlgStkPtr].changed; + if ( oldState == S_ProtoSel ) + if ( S_PART ) + CarDlgDoStateActions( proto2partActions ); + else + CarDlgDoStateActions( proto2itemActions ); + else + CarDlgDoStateActions( part2itemActions ); + } else { + wTextClear( (wText_p)carDlgPLs[I_CD_NOTES].control ); + wHide( carDlgPG.win ); + } +} + + +static void CarDlgOk( void * junk ) +{ + long options = 0; + int len; + FILE * f; + long number; + char * cp; + long count; + tabString_t tabs[7]; + char title[STR_LONG_SIZE]; + carItem_p itemP=NULL; + carPart_p partP=NULL; + carProto_p protoP; + BOOL_T reloadRoadnameList = FALSE; + char *oldLocale = NULL; + +LOG( log_carDlgState, 3, ( "CarDlgOk()\n" ) ) + + /*ParamUpdate( &carDlgPG );*/ + if ( carDlgDim.carLength <= 0.0 || + carDlgDim.carWidth <= 0.0 || + carDlgDim.truckCenter <= 0.0 || + carDlgDim.coupledLength <= 0.0 ) { + NoticeMessage( MSG_CARDESC_VALUE_ZERO, _("Ok"), NULL ); + return; + } + if ( carDlgDim.carLength <= carDlgDim.carWidth ) { + NoticeMessage( MSG_CARDESC_BAD_DIM_VALUE, _("Ok"), NULL ); + return; + } + if ( carDlgDim.coupledLength <= carDlgDim.carLength ) { + NoticeMessage( MSG_CARDESC_BAD_COUPLER_LENGTH_VALUE, _("Ok"), NULL ); + return; + } + + if ( S_ITEM && carDlgUpdateItemPtr==NULL && !CheckCarDlgItemIndex(&carDlgItemIndex) ) { + NoticeMessage( MSG_CARITEM_BAD_INDEX, _("Ok"), NULL ); + ParamLoadControl( &carDlgPG, I_CD_ITEMINDEX ); + return; + } + + if ( (!S_PROTO) && carDlgCouplerMount != 0 ) + options |= CAR_DESC_COUPLER_MODE_BODY; + if ( carDlgIsLoco == 1 ) + options |= CAR_DESC_IS_LOCO; + + if ( S_ITEM ) { + len = wTextGetSize( (wText_p)carDlgPLs[I_CD_NOTES].control ); + sprintf( title, "%s\t%s\t%s\t%s\t%s\t%s\t%s", carDlgManufStr, carDlgProtoStr, carDlgDescStr, carDlgPartnoStr, carDlgRoadnameStr, carDlgRepmarkStr, carDlgNumberStr ); + partP = NULL; + if ( ( carDlgManufInx < 0 || carDlgPartnoInx < 0 ) && carDlgPartnoStr[0] ) { + partP = CarPartFind( carDlgManufStr, strlen(carDlgManufStr), carDlgPartnoStr, strlen(carDlgPartnoStr), carDlgScaleInx ); + if ( partP != NULL && + NoticeMessage( MSG_CARPART_DUPNAME, _("Yes"), _("No") ) <= 0 ) + return; + partP = CarPartNew( NULL, PARAM_CUSTOM, carDlgScaleInx, title, options, typeListMap[carDlgTypeInx].value, &carDlgDim, carDlgBodyColor ); + if ( partP != NULL ) { + if ( ( f = OpenCustom("a") ) ) { + oldLocale = SaveLocale("C"); + CarPartWrite( f, partP ); + fclose(f); + RestoreLocale(oldLocale); + } + } + } + if ( carDlgUpdateItemPtr!=NULL ) { + carDlgQuantity = 1; + } + for ( count=0; count<carDlgQuantity; count++ ) { + itemP = CarItemNew( carDlgUpdateItemPtr, + PARAM_CUSTOM, carDlgItemIndex, + carDlgScaleInx, title, options, typeListMap[carDlgTypeInx].value, + &carDlgDim, carDlgBodyColor, + carDlgPurchPrice, carDlgCurrPrice, carDlgCondition, + carDlgPurchDate, carDlgServiceDate ); + if ( carDlgUpdateItemPtr==NULL ) { + wPrefSetInteger( "misc", "last-car-item-index", carDlgItemIndex ); + carDlgItemIndex++; + CheckCarDlgItemIndex(&carDlgItemIndex); + ParamLoadControl( &carDlgPG, I_CD_ITEMINDEX ); + if ( carDlgQuantity>1 && carDlgMultiNum==0 ) { + number = strtol( carDlgNumberStr, &cp, 10 ); + if ( cp && *cp == 0 && number > 0 ) { + sprintf( carDlgNumberStr, "%ld", number+1 ); + sprintf( title, "%s\t%s\t%s\t%s\t%s\t%s\t%s", carDlgManufStr, carDlgProtoStr, carDlgDescStr, carDlgPartnoStr, carDlgRoadnameStr, carDlgRepmarkStr, carDlgNumberStr ); + } + } + } + if ( len > 0 ) { + if ( itemP->data.notes ) + itemP->data.notes = MyRealloc( itemP->data.notes, len+2 ); + else + itemP->data.notes = MyMalloc( len+2 ); + itemP->data.notes = (char*)MyMalloc( len+2 ); + wTextGetText( (wText_p)carDlgPLs[I_CD_NOTES].control, itemP->data.notes, len ); + if ( itemP->data.notes[len-1] != '\n' ) { + itemP->data.notes[len] = '\n'; + itemP->data.notes[len+1] = '\0'; + } else { + itemP->data.notes[len] = '\0'; + } + } else if ( itemP->data.notes ) { + MyFree( itemP->data.notes ); + itemP->data.notes = NULL; + } + } + if ( carDlgUpdateItemPtr==NULL ) + CarInvListAdd( itemP ); + else + CarInvListUpdate( itemP ); + changed++; + SetWindowTitle(); + reloadRoadnameList = TRUE; + if ( carDlgUpdateItemPtr==NULL ) { + if ( carDlgQuantity > 1 ) { + sprintf( message, _("Added %ld new Cars"), carDlgQuantity ); + } else { + strcpy( message, _("Added new Car") ); + } + } else { + strcpy( message, _("Updated Car") ); + } + sprintf( message+strlen(message), "%s: %s %s %s %s %s %s", + (partP?_(" and Part"):""), + carDlgManufStr, carDlgPartnoStr, carDlgProtoStr, carDlgDescStr, + (carDlgRepmarkStr?carDlgRepmarkStr:carDlgRoadnameStr), carDlgNumberStr ); + carDlgQuantity = 1; + ParamLoadControl( &carDlgPG, I_CD_QTY ); + + } else if ( S_PART ) { + if ( strcasecmp( carDlgRoadnameStr, "undecorated" ) == 0 ) { + carDlgRoadnameStr[0] = '\0'; + carDlgRepmarkStr[0] = '\0'; + } + if ( carDlgUpdatePartPtr==NULL ) { + partP = CarPartFind( carDlgManufStr, strlen(carDlgManufStr), carDlgPartnoStr, strlen(carDlgPartnoStr), carDlgScaleInx ); + if ( partP != NULL && + NoticeMessage( MSG_CARPART_DUPNAME, _("Yes"), _("No") ) <= 0 ) + return; + } + sprintf( message, "%s\t%s\t%s\t%s\t%s\t%s\t%s", carDlgManufStr, carDlgProtoStr, carDlgDescStr, carDlgPartnoStr, carDlgRoadnameStr, carDlgRepmarkStr, carDlgNumberStr ); + carDlgNewPartPtr = CarPartNew( carDlgUpdatePartPtr, PARAM_CUSTOM, carDlgScaleInx, message, options, typeListMap[carDlgTypeInx].value, + &carDlgDim, carDlgBodyColor ); + if ( carDlgNewPartPtr != NULL && ( f = OpenCustom("a") ) ) { + oldLocale = SaveLocale("C"); + CarPartWrite( f, carDlgNewPartPtr ); + fclose(f); + RestoreLocale(oldLocale); + } + reloadRoadnameList = TRUE; + sprintf( message, _("%s Part: %s %s %s %s %s %s"), carDlgUpdatePartPtr==NULL?_("Added new"):_("Updated"), carDlgManufStr, carDlgPartnoStr, carDlgProtoStr, carDlgDescStr, carDlgRepmarkStr?carDlgRepmarkStr:carDlgRoadnameStr, carDlgNumberStr ); + + } else if ( S_PROTO ) { + if ( carDlgUpdateProtoPtr==NULL ) { + protoP = CarProtoFind( carDlgProtoStr ); + if ( protoP != NULL && + NoticeMessage( MSG_CARPROTO_DUPNAME, _("Yes"), _("No") ) <= 0 ) + return; + } + carDlgNewProtoPtr = CarProtoNew( carDlgUpdateProtoPtr, PARAM_CUSTOM, carDlgProtoStr, options, typeListMap[carDlgTypeInx].value, &carDlgDim, carDlgSegs_da.cnt, &carDlgSegs(0) ); + if ( (f = OpenCustom("a") ) ) { + oldLocale = SaveLocale("C"); + CarProtoWrite( f, carDlgNewProtoPtr ); + fclose(f); + RestoreLocale(oldLocale); + } + sprintf( message, _("%s Prototype: %s%s."), + carDlgUpdateProtoPtr==NULL?_("Added new"):_("Updated"), carDlgProtoStr, + carDlgUpdateProtoPtr==NULL?_(". Enter new values or press Close"):"" ); + } + + if ( reloadRoadnameList ) { + tabs[0].ptr = carDlgRoadnameStr; + tabs[0].len = strlen(carDlgRoadnameStr); + tabs[1].ptr = carDlgRepmarkStr; + tabs[1].len = strlen(carDlgRepmarkStr); + LoadRoadnameList( &tabs[0], &tabs[1] ); + CarDlgLoadRoadnameList(); + ParamLoadControl( &carDlgPG, I_CD_ROADNAME_LIST ); + } + + ParamLoadMessage( &carDlgPG, I_CD_MSG, message ); + + DoChangeNotification( CHANGE_PARAMS ); + + carDlgChanged = 0; + if ( S_ITEM ) { + if ( carDlgUpdateItemPtr==NULL ) { + if ( partP ) { + TabStringExtract( title, 7, tabs ); + if ( CarDlgLoadLists( TRUE, tabs, curScaleInx ) ) + currState = S_ItemSel; + else + currState = S_ItemEnter; + ParamLoadControl( &carDlgPG, I_CD_MANUF_LIST ); + ParamLoadControl( &carDlgPG, I_CD_PROTOKIND_LIST ); + ParamLoadControl( &carDlgPG, I_CD_PROTOTYPE_LIST ); + ParamLoadControl( &carDlgPG, I_CD_PARTNO_LIST ); + ParamLoadControl( &carDlgPG, I_CD_PARTNO_STR ); + ParamLoadControl( &carDlgPG, I_CD_DESC_STR ); + ParamControlShow( &carDlgPG, I_CD_PARTNO_LIST, carDlgPartnoInx>=0 ); + ParamControlShow( &carDlgPG, I_CD_PARTNO_STR, carDlgPartnoInx<0 ); + ParamControlShow( &carDlgPG, I_CD_DESC_STR, carDlgPartnoInx<0 ); + } else if ( carDlgManufInx == -1 ) { + carDlgManufStr[0] = '\0'; + } + return; + } + } else if ( S_PART ) { + if ( carDlgUpdatePartPtr==NULL ) { + number = strtol( carDlgPartnoStr, &cp, 10 ); + if ( cp && *cp == 0 && number > 0 ) + sprintf( carDlgPartnoStr, "%ld", number+1 ); + else + carDlgPartnoStr[0] = '\0'; + carDlgNumberStr[0] = '\0'; + ParamLoadControl( &carDlgPG, I_CD_PARTNO_STR ); + ParamLoadControl( &carDlgPG, I_CD_NUMBER ); + return; + } + } else if ( S_PROTO ) { + if ( carDlgUpdateProtoPtr==NULL ) { + carDlgProtoStr[0] = '\0'; + ParamLoadControl( &carDlgPG, I_CD_PROTOTYPE_STR ); + return; + } + } + CarDlgClose( carDlgPG.win ); +} + + + +static void CarDlgLayout( + paramData_t * pd, + int inx, + wPos_t currX, + wPos_t *xx, + wPos_t *yy ) +{ + static wPos_t col2pos = 0; + wPos_t y0, y1; + + switch (inx) { + case I_CD_PROTOTYPE_STR: + case I_CD_PARTNO_STR: + case I_CD_ISLOCO: + case I_CD_IMPORT: + case I_CD_TYPE_LIST: + *yy = wControlGetPosY(carDlgPLs[inx-1].control); + break; + case I_CD_NEWPROTO: + *yy = wControlGetPosY(carDlgPLs[I_CD_NEW].control); + break; + case I_CD_CPLRMNT: + case I_CD_CPLRLEN: + case I_CD_CARWIDTH: + if ( col2pos == 0 ) + col2pos = wLabelWidth( _("Coupler Length") )+20; + *xx = wControlBeside(carDlgPLs[inx-1].control) + col2pos; + break; + case I_CD_DESC_STR: + *yy = wControlBelow(carDlgPLs[I_CD_PARTNO_STR].control) + 3; + break; + case I_CD_CPLDLEN: + *yy = wControlBelow(carDlgPLs[I_CD_TRKCENTER].control) + 3; + break; + case I_CD_CANVAS: + *yy = wControlBelow(carDlgPLs[I_CD_CPLDLEN].control)+5; + break; + case C: + *yy = wControlGetPosY(carDlgPLs[B].control); + break; + case I_CD_MSG: + y0 = wControlBelow(carDlgPLs[C-1].control); + y1 = wControlBelow(carDlgPLs[D-1].control); + *yy = ((y0>y1)?y0:y1) + 10; + break; + } +} + + +static void DoCarPartDlg( carDlgAction_e *actions ) +{ + paramData_t * pd; + int inx; + + if ( carDlgPG.win == NULL ) { + ParamCreateDialog( &carDlgPG, MakeWindowTitle(_("New Car Part")), _("Add"), CarDlgOk, CarDlgClose, TRUE, CarDlgLayout, F_BLOCK|PD_F_ALT_CANCELLABEL, CarDlgUpdate ); + + if ( carDlgDim.carWidth==0 ) + carDlgDim.carWidth = 12.0*10.0/curScaleRatio; + + for ( pd=carDlgPG.paramPtr; pd<&carDlgPG.paramPtr[carDlgPG.paramCnt]; pd++ ) { + if ( pd->type == PD_FLOAT && pd->valueP ) { + sprintf( message, "%s-%s", pd->nameStr, curScaleName ); + wPrefGetFloat( carDlgPG.nameStr, message, (FLOAT_T*)pd->valueP, *(FLOAT_T*)pd->valueP ); + } + } + roadnameMapChanged = TRUE; + + for ( inx=0; inx<N_CONDLISTMAP; inx++ ) + wListAddValue( (wList_p)carDlgPLs[I_CD_COND].control, _(condListMap[inx].name), NULL, (void*)condListMap[inx].value ); + + for ( inx=0; inx<N_TYPELISTMAP; inx++ ) + wListAddValue( (wList_p)carDlgPLs[I_CD_TYPE_LIST].control, _(typeListMap[inx].name), NULL, (void*)typeListMap[inx].value ); + + for ( inx=0; inx<N_TYPELISTMAP; inx++ ) + wListAddValue( (wList_p)carDlgPLs[I_CD_PROTOKIND_LIST].control, _(typeListMap[inx].name), NULL, (void*)typeListMap[inx].value ); + + wTextSetReadonly( (wText_p)carDlgPLs[I_CD_NOTES].control, FALSE ); + } + + wPrefGetInteger( "misc", "last-car-item-index", &carDlgItemIndex, 1 ); + CheckCarDlgItemIndex(&carDlgItemIndex); + CarDlgLoadRoadnameList(); + carProtoSegCnt = 0; + carProtoSegPtr = NULL; + carDlgScaleInx = curScaleInx; + carDlgFlipToggle = FALSE; + carDlgChanged = 0; + + CarDlgDoStateActions( actions ); + + /*CarDlgShowControls();*/ + +#ifdef LATER +if ( logTable(log_carList).level >= 1 ) { + int inx; + carPart_p partP; + for ( inx=0; inx<carPart_da.cnt; inx++ ) { + partP = carPart(inx); + LogPrintf( "%d %s %d\n", inx, partP->title, partP->paramFileIndex ); + } +} +#endif + wShow( carDlgPG.win ); +} + + +EXPORT void CarDlgAddProto( void ) +{ + /*carDlgPrototypeStr[0] = 0; */ + carDlgTypeInx = 0; + carDlgUpdateProtoPtr = NULL; + DoCarPartDlg( protoNewActions ); +} + +EXPORT void CarDlgAddDesc( void ) +{ + if ( carProto_da.cnt <= 0 ) { + NoticeMessage( MSG_NO_CARPROTO, _("Ok"), NULL ); + return; + } + carDlgIsLoco = FALSE; + carDlgUpdatePartPtr = NULL; + carDlgNumberStr[0] = '\0'; + ParamLoadControl( &carDlgPG, I_CD_NUMBER ); + DoCarPartDlg( partNewActions ); +} + +/* + * Car Inventory List + */ + +static wIndex_t carInvInx; + +static wIndex_t carInvSort[] = { 0, 1, 2, 3 }; +#define N_SORT (sizeof carInvSort/sizeof carInvSort[0]) + +static void CarInvDlgAdd( void ); +static void CarInvDlgEdit( void ); +static void CarInvDlgDelete( void ); +static void CarInvDlgImportCsv( void ); +static void CarInvDlgExportCsv( void ); +static void CarInvDlgSaveText( void ); +static void CarInvListLoad( void ); + +static wPos_t carInvColumnWidths[] = { + -40, 30, 100, -50, 50, 130, 120, 100, + -50, -50, 60, 55, 55, 40, 200 }; +static const char * carInvColumnTitles[] = { + N_("Index"), N_("Scale"), N_("Manufacturer"), N_("Part No"), N_("Type"), + N_("Description"), N_("Roadname"), N_("Rep Marks"), N_("Purc Price"), + N_("Curr Price"), N_("Condition"), N_("Purc Date"), N_("Srvc Date"), + N_("Locat'n"), N_("Notes") }; +static char * sortOrders[] = { + N_("Index"), N_("Scale"), N_("Manufacturer"), N_("Part No"), N_("Type"), + N_("Description"), N_("Roadname"), N_("RepMarks"), N_("Purch Price"), + N_("Curr Price"), N_("Condition"), N_("Purch Date"), N_("Service Date") }; +#define S_INDEX (0) +#define S_SCALE (1) +#define S_MANUF (2) +#define S_PARTNO (3) +#define S_TYPE (4) +#define S_DESC (5) +#define S_ROADNAME (6) +#define S_REPMARKS (7) +#define S_PURCHPRICE (8) +#define S_CURRPRICE (9) +#define S_CONDITION (10) +#define S_PURCHDATE (11) +#define S_SRVDATE (12) +static paramListData_t carInvListData = { 30, 600, sizeof carInvColumnTitles/sizeof carInvColumnTitles[0], carInvColumnWidths, carInvColumnTitles }; +static paramData_t carInvPLs[] = { +#define I_CI_SORT (0) + { PD_DROPLIST, &carInvSort[0], "sort1", PDO_LISTINDEX|0, (void*)110, N_("Sort By") }, + { PD_DROPLIST, &carInvSort[1], "sort2", PDO_LISTINDEX|PDO_DLGHORZ, (void*)110, "" }, + { PD_DROPLIST, &carInvSort[2], "sort3", PDO_LISTINDEX|PDO_DLGHORZ, (void*)110, "" }, + { PD_DROPLIST, &carInvSort[3], "sort4", PDO_LISTINDEX|PDO_DLGHORZ, (void*)110, "" }, +#define S (4) +#define I_CI_LIST (S+0) + { PD_LIST, &carInvInx, "list", PDO_LISTINDEX|PDO_DLGRESIZE|PDO_DLGNOLABELALIGN|PDO_DLGRESETMARGIN, &carInvListData, NULL, BO_READONLY|BL_MANY }, +#define I_CI_EDIT (S+1) + { PD_BUTTON, (void*)CarInvDlgEdit, "edit", PDO_DLGCMDBUTTON, NULL, N_("Edit") }, +#define I_CI_ADD (S+2) + { PD_BUTTON, (void*)CarInvDlgAdd, "add", 0, NULL, N_("Add"), 0, 0 }, +#define I_CI_DELETE (S+3) + { PD_BUTTON, (void*)CarInvDlgDelete, "delete", PDO_DLGWIDE, NULL, N_("Delete") }, +#define I_CI_IMPORT_CSV (S+4) + { PD_BUTTON, (void*)CarInvDlgImportCsv, "import", PDO_DLGWIDE, NULL, N_("Import") }, +#define I_CI_EXPORT_CSV (S+5) + { PD_BUTTON, (void*)CarInvDlgExportCsv, "export", 0, NULL, N_("Export") }, +#define I_CI_PRINT (S+6) + { PD_BUTTON, (void*)CarInvDlgSaveText, "savetext", 0, NULL, N_("List") } }; +static paramGroup_t carInvPG = { "carinv", 0, carInvPLs, sizeof carInvPLs/sizeof carInvPLs[0] }; + +static carItem_p CarInvDlgFindCurrentItem( void ) +{ + wIndex_t selcnt = wListGetSelectedCount( (wList_p)carInvPLs[I_CI_LIST].control ); + wIndex_t inx, cnt; + + if ( selcnt != 1 ) return NULL; + cnt = wListGetCount( (wList_p)carInvPLs[I_CI_LIST].control ); + for ( inx=0; inx<cnt; inx++ ) + if ( wListGetItemSelected( (wList_p)carInvPLs[I_CI_LIST].control, inx ) ) + break; + if ( inx>=cnt ) return NULL; + return (carItem_p)wListGetItemContext( (wList_p)carInvPLs[I_CI_LIST].control, inx ); +} + + +static void CarInvDlgFind( void * junk ) +{ + carItem_p item = CarInvDlgFindCurrentItem(); + coOrd pos; + ANGLE_T angle; + if ( item == NULL || item->car == NULL || IsTrackDeleted(item->car) ) return; + CarGetPos( item->car, &pos, &angle ); + CarSetVisible( item->car ); + DrawMapBoundingBox( FALSE ); + mainCenter = pos; + mainD.orig.x = pos.x-mainD.size.x/2;; + mainD.orig.y = pos.y-mainD.size.y/2;; + MainRedraw(); + DrawMapBoundingBox( TRUE ); +} + + +static void CarInvDlgAdd( void ) +{ + if ( carProto_da.cnt <= 0 ) { + NoticeMessage( MSG_NO_CARPROTO, _("Ok"), NULL ); + return; + } + carDlgUpdateItemPtr = NULL; + DoCarPartDlg( itemNewActions ); +} + + +static void CarInvDlgEdit( void ) +{ + carDlgUpdateItemPtr = CarInvDlgFindCurrentItem(); + if ( carDlgUpdateItemPtr == NULL ) + return; + DoCarPartDlg( itemUpdActions ); +} + + +static void CarInvDlgDelete( void ) +{ + carItem_p item; + wIndex_t inx, inx1, cnt, selcnt; + + selcnt = wListGetSelectedCount( (wList_p)carInvPLs[I_CI_LIST].control ); + if ( selcnt == 0 ) + return; + if ( NoticeMessage( MSG_CARINV_DELETE_CONFIRM, _("Yes"), _("No"), selcnt ) <= 0 ) + return; + cnt = wListGetCount( (wList_p)carInvPLs[I_CI_LIST].control ); + for ( inx=0; inx<cnt; inx++ ) { + if ( !wListGetItemSelected( (wList_p)carInvPLs[I_CI_LIST].control, inx ) ) + continue; + item = (carItem_p)wListGetItemContext( (wList_p)carInvPLs[I_CI_LIST].control, inx ); + if ( item == NULL ) + continue; + if ( item->car && !IsTrackDeleted(item->car) ) + continue; + wListDelete( (wList_p)carInvPLs[I_CI_LIST].control, inx ); + if ( item->title ) MyFree( item->title ); + if ( item->data.number ) MyFree( item->data.number ); + MyFree( item ); + for ( inx1=inx; inx1<carItemInfo_da.cnt-1; inx1++ ) + carItemInfo(inx1) = carItemInfo(inx1+1); + carItemInfo_da.cnt -= 1; + inx--; + cnt--; + } + changed++; + SetWindowTitle(); + carInvInx = -1; + ParamLoadControl( &carInvPG, I_CI_LIST ); + ParamControlActive( &carInvPG, I_CI_EDIT, FALSE ); + ParamControlActive( &carInvPG, I_CI_DELETE, FALSE ); + ParamControlActive( &carInvPG, I_CI_EXPORT_CSV, carItemInfo_da.cnt > 0 ); + ParamDialogOkActive( &carInvPG, FALSE ); +} + + +static int CarInvSaveText( + const char * pathName, + const char * fileName, + void * data ) +{ + FILE * f; + carItem_p item; + int inx; + int widths[9], width; + tabString_t tabs[7]; + char * cp0, * cp1; + int len; + + if ( pathName == NULL ) + return TRUE; + SetCurDir( pathName, fileName ); + f = fopen( pathName, "w" ); + if ( f == NULL ) { + NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Car Inventory"), fileName, strerror(errno) ); + return FALSE; + } + + memset( widths, 0, sizeof widths ); + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) { + item = carItemInfo(inx); + TabStringExtract( item->title, 7, tabs ); + sprintf( message, "%ld", item->index ); + width = strlen( message ); + if ( width > widths[0] ) widths[0] = width; + width = strlen(GetScaleName(item->scaleInx)) + 1 + tabs[T_MANUF].len + 1 + tabs[T_PART].len; + if ( width > widths[1] ) widths[1] = width; + if ( tabs[T_PROTO].len > widths[2] ) widths[2] = tabs[T_PROTO].len; + width = tabs[T_REPMARK].len + tabs[T_NUMBER].len; + if ( tabs[T_REPMARK].len > 0 && tabs[T_NUMBER].len > 0 ) + width += 1; + if ( width > widths[3] ) widths[3] = width; + if ( item->data.purchDate > 0 ) widths[4] = 8; + if ( item->data.purchPrice > 0 ) { + sprintf( message, "%0.2f", item->data.purchPrice ); + width = strlen(message); + if ( width > widths[5] ) widths[5] = width; + } + if ( item->data.condition != 0 ) + widths[6] = 5; + if ( item->data.currPrice > 0 ) { + sprintf( message, "%0.2f", item->data.currPrice ); + width = strlen(message); + if ( width > widths[7] ) widths[7] = width; + } + if ( item->data.serviceDate > 0 ) widths[8] = 8; + } + fprintf( f, "%-*.*s %-*.*s %-*.*s %-*.*s", widths[0], widths[0], "#", widths[1], widths[1], "Part", widths[2], widths[2], "Description", widths[3], widths[3], "Rep Mark" ); + if ( widths[4] ) fprintf( f, " %-*.*s", widths[4], widths[4], "PurDate" ); + if ( widths[5] ) fprintf( f, " %-*.*s", widths[5], widths[5], "PurPrice" ); + if ( widths[6] ) fprintf( f, " %-*.*s", widths[6], widths[6], "Cond" ); + if ( widths[7] ) fprintf( f, " %-*.*s", widths[7], widths[7], "CurPrice" ); + if ( widths[8] ) fprintf( f, " %-*.*s", widths[8], widths[8], "SrvDate" ); + fprintf( f, "\n" ); + + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) { + item = carItemInfo(inx); + TabStringExtract( item->title, 7, tabs ); + sprintf( message, "%ld", item->index ); + fprintf( f, "%.*s", widths[0], message ); + width = tabs[T_MANUF].len + 1 + tabs[T_PART].len; + sprintf( message, "%s %.*s %.*s", GetScaleName(item->scaleInx), tabs[T_MANUF].len, tabs[T_MANUF].ptr, tabs[T_PART].len, tabs[T_PART].ptr ); + fprintf( f, " %-*s", widths[1], message ); + fprintf( f, " %-*.*s", widths[2], tabs[T_PROTO].len, tabs[T_PROTO].ptr ); + width = tabs[T_REPMARK].len + tabs[T_NUMBER].len; + sprintf( message, "%.*s%s%.*s", tabs[T_REPMARK].len, tabs[T_REPMARK].ptr, (tabs[T_REPMARK].len > 0 && tabs[T_NUMBER].len > 0)?" ":"", tabs[T_NUMBER].len, tabs[T_NUMBER].ptr ); + fprintf( f, " %-*s", widths[3], message ); + if ( widths[4] > 0 ) { + if ( item->data.purchDate > 0 ) { + sprintf( message, "%ld", item->data.purchDate ); + fprintf( f, " %*.*s", widths[4], widths[4], message ); + } else { + fprintf( f, " %*s", widths[4], " " ); + } + } + if ( widths[5] > 0 ) { + if ( item->data.purchPrice > 0 ) { + sprintf( message, "%0.2f", item->data.purchPrice ); + fprintf( f, " %*.*s", widths[5], widths[5], message ); + } else { + fprintf( f, " %*s", widths[5], " " ); + } + } + if ( widths[6] > 0 ) { + if ( item->data.condition != 0 ) { + fprintf( f, " %-*.*s", widths[6], widths[6], condListMap[MapCondition(item->data.condition)].name ); + } else { + fprintf( f, " %*s", widths[6], " " ); + } + } + if ( widths[7] > 0 ) { + if ( item->data.purchPrice > 0 ) { + sprintf( message, "%0.2f", item->data.purchPrice ); + fprintf( f, " %*.*s", widths[7], widths[7], message ); + } else { + fprintf( f, " %*s", widths[7], " " ); + } + } + if ( widths[8] > 0 ) { + if ( item->data.serviceDate > 0 ) { + sprintf( message, "%ld", item->data.serviceDate ); + fprintf( f, " %*.*s", widths[8], widths[8], message ); + } else { + fprintf( f, " %*s", widths[8], " " ); + } + } + fprintf( f, "\n" ); + if ( item->data.notes ) { + cp0 = item->data.notes; + while ( 1 ) { + cp1 = strchr( cp0, '\n' ); + if ( cp1 ) { + len = cp1-cp0; + } else { + len = strlen( cp0 ); + if ( len == 0 ) + break; + } + fprintf( f, "%*.*s %*.*s\n", widths[0], widths[0], " ", len, len, cp0 ); + if ( cp1 == NULL ) + break; + cp0 = cp1+1; + } + } + } + fclose( f ); + return TRUE; +} + + +static struct wFilSel_t * carInvSaveText_fs; +static void CarInvDlgSaveText( void ) +{ + if ( carInvSaveText_fs == NULL ) + carInvSaveText_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("List Cars"), + "Text|*.txt", CarInvSaveText, NULL ); + wFilSelect( carInvSaveText_fs, curDirName ); +} + + +static char *carCsvColumnTitles[] = { + "Index", "Scale", "Manufacturer", "Type", "Partno", "Prototype", + "Description", "Roadname", "Repmark", "Number", "Options", "CarLength", + "CarWidth", "CoupledLength", "TruckCenter", "Color", "PurchPrice", + "CurrPrice", "Condition", "PurchDate", "ServiceDate", "Notes" }; +#define M_INDEX (0) +#define M_SCALE (1) +#define M_MANUF (2) +#define M_TYPE (3) +#define M_PARTNO (4) +#define M_PROTO (5) +#define M_DESC (6) +#define M_ROADNAME (7) +#define M_REPMARK (8) +#define M_NUMBER (9) +#define M_OPTIONS (10) +#define M_CARLENGTH (11) +#define M_CARWIDTH (12) +#define M_CPLDLENGTH (13) +#define M_TRKCENTER (14) +#define M_COLOR (15) +#define M_PURCHPRICE (16) +#define M_CURRPRICE (17) +#define M_CONDITION (18) +#define M_PURCHDATE (19) +#define M_SRVDATE (20) +#define M_NOTES (21) + + +static int ParseCsvLine( + char * line, + int max_elem, + tabString_t * tabs, + int * map ) +{ + int elem = 0; + char * cp, * cq, * ptr; + int rc, len; + + cp = line; + for ( cq=cp+strlen(cp)-1; cq>cp&&isspace(*cq); cq-- ); + cq[1] = '\0'; + for ( elem=0; elem<max_elem; elem++ ) { + tabs[elem].ptr = ""; + tabs[elem].len = 0; + } + elem = 0; + while ( *cp && elem < max_elem ) { + while ( *cp == ' ' ) cp++; + if ( *cp == ',' ) { + ptr = ""; + len = 0; + } else if ( *cp == '"' ) { + cp++; + ptr = cq = cp; + while (1) { + while ( *cp!='"' ) { + if ( *cp == '\0' ) { + rc = NoticeMessage( MSG_CARIMP_EOL, _("Continue"), _("Stop"), ptr ); + return (rc<1)?-1:elem; + } + *cq++ = *cp++; + } + cp++; + if ( *cp!='"' ) break; + *cq++ = *cp++; + } + if ( *cp && *cp != ',' ) { + rc = NoticeMessage( MSG_CARIMP_MISSING_COMMA, _("Continue"), _("Stop"), ptr ); + return (rc<1)?-1:elem; + } + len = cq-ptr; + } else { + ptr = cp; + while ( *cp && *cp != ',' ) { cp++; } + len = cp-ptr; + } + if ( map[elem] >= 0 ) { + tabs[map[elem]].ptr = ptr; + tabs[map[elem]].len = len; + } + if ( *cp ) cp++; + elem++; + } + return elem; +} + + +static int CarInvImportCsv( + const char * pathName, + const char * fileName, + void * data ) +{ + FILE * f; + carItem_p item; + tabString_t tabs[40], partTabs[7]; + int map[40]; + int i, j, cnt, numCol, len, rc; + char * cp, * cq; + long type = 0; + char title[STR_LONG_SIZE]; + long index, options, color, condition, purchDate, srvcDate; + carDim_t dim; + FLOAT_T purchPrice, currPrice; + int duplicateIndexError = 0; + SCALEINX_T scale; + carPart_p partP; + int requiredCols; + char *oldLocale = NULL; + + if ( pathName == NULL ) + return TRUE; + SetCurDir( pathName, fileName ); + f = fopen( pathName, "r" ); + if ( f == NULL ) { + NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Import Cars"), fileName, strerror(errno) ); + return FALSE; + } + + oldLocale = SaveLocale("C"); + + if ( fgets( message, sizeof message, f ) == NULL ) { + NoticeMessage( MSG_CARIMP_NO_DATA, _("Continue"), NULL ); + fclose( f ); + RestoreLocale(oldLocale); + return FALSE; + } + for ( j=0; j<40; j++ ) map[j] = j; + numCol = ParseCsvLine( message, 40, tabs, map ); + if ( numCol <= 0 ) { + fclose( f ); + RestoreLocale(oldLocale); + return FALSE; + } + for ( j=0; j<40; j++ ) map[j] = -1; + requiredCols = 0; + for ( i=0; i<numCol; i++ ) { + for ( j=0; j<sizeof carCsvColumnTitles/sizeof carCsvColumnTitles[0]; j++ ) { + if ( TabStringCmp( carCsvColumnTitles[j], &tabs[i] ) == 0 ) { + if ( map[i] >= 0 ) { + NoticeMessage( MSG_CARIMP_DUP_COLUMNS, _("Continue"), NULL, carCsvColumnTitles[j] ); + fclose( f ); + RestoreLocale(oldLocale); + return FALSE; + } + map[i] = j; + /*j = sizeof carCsvColumnTitles/sizeof carCsvColumnTitles[0];*/ + if ( j == M_SCALE || j == M_PROTO || j == M_MANUF || j == M_PARTNO ) + requiredCols++; + } + } + if ( map[i] == -1 ) { + tabs[i].ptr[tabs[i].len] = '\0'; + NoticeMessage( MSG_CARIMP_IGNORED_COLUMN, _("Continue"), NULL, tabs[i].ptr ); + tabs[i].ptr[tabs[i].len] = ','; + } + } + if ( requiredCols != 4 ) { + NoticeMessage( MSG_CARIMP_MISSING_COLUMNS, _("Continue"), NULL ); + fclose( f ); + RestoreLocale(oldLocale); + return FALSE; + } + while ( fgets( message, sizeof message, f ) != NULL ) { + cnt = ParseCsvLine( message, 40, tabs, map ); + if ( cnt > numCol ) cnt = numCol; + tabs[M_SCALE].ptr[tabs[M_SCALE].len] = '\0'; + scale = LookupScale( tabs[M_SCALE].ptr ); + tabs[M_SCALE].ptr[tabs[M_SCALE].len] = ','; + index = TabGetLong( &tabs[M_INDEX] ); + if ( index == 0 ) { + CheckCarDlgItemIndex( &carDlgItemIndex ); + index = carDlgItemIndex; + } else { + carDlgItemIndex = index; + if ( !CheckCarDlgItemIndex(&index) ) { + if ( !duplicateIndexError ) { + NoticeMessage( MSG_CARIMP_DUP_INDEX, _("Ok"), NULL ); + duplicateIndexError++; + } + carDlgItemIndex = index; + } + } +#ifdef OBSOLETE + if ( TabStringCmp( "Unknown", &tabs[M_MANUF] ) != 0 && + TabStringCmp( "Custom", &tabs[M_MANUF] ) != 0 ) { + if ( tabs[M_PARTNO].len == 0 ) { + rc = NoticeMessage( MSG_CARIMP_MISSING_PARTNO, _("Continue"), _("Stop"), tabs[M_MANUF].ptr ); + if ( rc <= 0 ) { + fclose( f ); + RestoreLocale(oldLocale); + return FALSE; + } + continue; + } + } +#endif + dim.carLength = TabGetFloat( &tabs[M_CARLENGTH] ); + dim.carWidth = TabGetFloat( &tabs[M_CARWIDTH] ); + dim.coupledLength = TabGetFloat( &tabs[M_CPLDLENGTH] ); + dim.truckCenter = TabGetFloat( &tabs[M_TRKCENTER] ); + partP = NULL; + if ( tabs[M_MANUF].len > 0 && tabs[M_PARTNO].len > 0 ) + partP = CarPartFind( tabs[M_MANUF].ptr, tabs[M_MANUF].len, tabs[M_PARTNO].ptr, tabs[M_PARTNO].len, scale ); + if ( partP ) { + TabStringExtract( partP->title, 7, partTabs ); + if ( tabs[M_PROTO].len == 0 && partTabs[T_PROTO].len > 0 ) { tabs[M_PROTO].ptr = partTabs[T_PROTO].ptr; tabs[M_PROTO].len = partTabs[T_PROTO].len; } + if ( tabs[M_DESC].len == 0 && partTabs[T_DESC].len > 0 ) { tabs[M_DESC].ptr = partTabs[T_DESC].ptr; tabs[M_DESC].len = partTabs[T_DESC].len; } + if ( tabs[M_ROADNAME].len == 0 && partTabs[T_ROADNAME].len > 0 ) { tabs[M_ROADNAME].ptr = partTabs[T_ROADNAME].ptr; tabs[M_ROADNAME].len = partTabs[T_ROADNAME].len; } + if ( tabs[M_REPMARK].len == 0 && partTabs[T_REPMARK].len > 0 ) { tabs[M_REPMARK].ptr = partTabs[T_REPMARK].ptr; tabs[M_REPMARK].len = partTabs[T_REPMARK].len; } + if ( tabs[M_NUMBER].len == 0 && partTabs[T_NUMBER].len > 0 ) { tabs[M_NUMBER].ptr = partTabs[T_NUMBER].ptr; tabs[M_NUMBER].len = partTabs[T_NUMBER].len; } + if ( dim.carLength <= 0 ) dim.carLength = partP->dim.carLength; + if ( dim.carWidth <= 0 ) dim.carWidth = partP->dim.carWidth; + if ( dim.coupledLength <= 0 ) dim.coupledLength = partP->dim.coupledLength; + if ( dim.truckCenter <= 0 ) dim.truckCenter = partP->dim.truckCenter; + } + cp = TabStringCpy( title, &tabs[M_MANUF] ); + *cp++ = '\t'; + cp = TabStringCpy( cp, &tabs[M_PROTO] ); + *cp++ = '\t'; + cp = TabStringCpy( cp, &tabs[M_DESC] ); + *cp++ = '\t'; + cp = TabStringCpy( cp, &tabs[M_PARTNO] ); + *cp++ = '\t'; + cp = TabStringCpy( cp, &tabs[M_ROADNAME] ); + *cp++ = '\t'; + cp = TabStringCpy( cp, &tabs[M_REPMARK] ); + *cp++ = '\t'; + cp = TabStringCpy( cp, &tabs[M_NUMBER] ); + *cp = '\0'; + options = TabGetLong( &tabs[M_OPTIONS] ); + type = TabGetLong( &tabs[M_TYPE] ); + color = TabGetLong( &tabs[M_COLOR] ); + purchPrice = TabGetFloat( &tabs[M_PURCHPRICE] ); + currPrice = TabGetFloat( &tabs[M_CURRPRICE] ); + condition = TabGetLong( &tabs[M_CONDITION] ); + purchDate = TabGetLong( &tabs[M_PURCHDATE] ); + srvcDate = TabGetLong( &tabs[M_SRVDATE] ); + if ( dim.carLength <= 0 || dim.carWidth <= 0 || dim.coupledLength <= 0 || dim.truckCenter <= 0 ) { + rc = NoticeMessage( MSG_CARIMP_MISSING_DIMS, _("Yes"), _("No"), message ); + if ( rc <= 0 ) { + fclose( f ); + RestoreLocale(oldLocale); + return FALSE; + } + continue; + } + item = CarItemNew( NULL, PARAM_CUSTOM, index, scale, title, options, type, + &dim, wDrawFindColor(color), + purchPrice, currPrice, condition, purchDate, srvcDate ); + if ( tabs[M_NOTES].len > 0 ) { + item->data.notes = cp = MyMalloc( tabs[M_NOTES].len+1 ); + for ( cq=tabs[M_NOTES].ptr,len=tabs[M_NOTES].len; *cq&&len; ) { + if ( strncmp( cq, "<NL>", 4 ) == 0 ) { + *cp++ = '\n'; + cq += 4; + len -= 4; + } else { + *cp++ = *cq++; + len -= 1; + } + } + } + changed++; + SetWindowTitle(); + } + fclose( f ); + RestoreLocale(oldLocale); + CarInvListLoad(); + return TRUE; +} + + + +static struct wFilSel_t * carInvImportCsv_fs; +static void CarInvDlgImportCsv( void ) +{ + if ( carInvImportCsv_fs == NULL ) + carInvImportCsv_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Import Cars"), + _("Comma-Separated-Values|*.csv"), CarInvImportCsv, NULL ); + wFilSelect( carInvImportCsv_fs, curDirName ); +} + + +static void CsvFormatString( + FILE * f, + char * str, + int len, + char * sep ) +{ + while ( str && len>0 && str[len-1]=='\n' ) len--; + if ( *str && len ) { + fputc( '"', f ); + for ( ; *str && len; str++,len-- ) { + if ( !iscntrl( *str ) ) { + if ( *str == '"' ) + fputc( '"', f ); + fputc( *str, f ); + } else if ( *str == '\n' && str[1] && len > 1 ) { + fprintf( f, "<NL>" ); + } + } + fputc( '"', f ); + } + fprintf( f, "%s", sep ); +} + + +static void CsvFormatLong( + FILE * f, + long val, + char * sep ) +{ + if ( val != 0 ) + fprintf( f, "%ld", val ); + fprintf( f, "%s", sep ); +} + + +static void CsvFormatFloat( + FILE * f, + FLOAT_T val, + int digits, + char * sep ) +{ + if ( val != 0.0 ) + fprintf( f, "%0.*f", digits, val ); + fprintf( f, "%s", sep ); +} + + +static int CarInvExportCsv( + const char * pathName, + const char * fileName, + void * data ) +{ + FILE * f; + carItem_p item; + long inx; + tabString_t tabs[7]; + char * sp; + char *oldLocale = NULL; + + if ( pathName == NULL ) + return TRUE; + SetCurDir( pathName, fileName ); + f = fopen( pathName, "w" ); + if ( f == NULL ) { + NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Export Cars"), fileName, strerror(errno) ); + return FALSE; + } + + oldLocale = SaveLocale("C"); + + for ( inx=0; inx<sizeof carCsvColumnTitles/sizeof carCsvColumnTitles[0]; inx++ ) { + CsvFormatString( f, carCsvColumnTitles[inx], strlen(carCsvColumnTitles[inx]), inx<(sizeof carCsvColumnTitles/sizeof carCsvColumnTitles[0])-1?",":"\n" ); + } + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) { + item = carItemInfo( inx ); + TabStringExtract( item->title, 7, tabs ); + CsvFormatLong( f, item->index, "," ); + sp = GetScaleName(item->scaleInx); + CsvFormatString( f, sp, strlen(sp), "," ); + CsvFormatString( f, tabs[T_MANUF].ptr, tabs[T_MANUF].len, "," ); + CsvFormatLong( f, item->type, "," ); + CsvFormatString( f, tabs[T_PART].ptr, tabs[T_PART].len, "," ); + CsvFormatString( f, tabs[T_PROTO].ptr, tabs[T_PROTO].len, "," ); + CsvFormatString( f, tabs[T_DESC].ptr, tabs[T_DESC].len, "," ); + CsvFormatString( f, tabs[T_ROADNAME].ptr, tabs[T_ROADNAME].len, "," ); + CsvFormatString( f, tabs[T_REPMARK].ptr, tabs[T_REPMARK].len, "," ); + CsvFormatString( f, tabs[T_NUMBER].ptr, tabs[T_NUMBER].len, "," ); + CsvFormatLong( f, item->options, "," ); + CsvFormatFloat( f, item->dim.carLength, 3, "," ); + CsvFormatFloat( f, item->dim.carWidth, 3, "," ); + CsvFormatFloat( f, item->dim.coupledLength, 3, "," ); + CsvFormatFloat( f, item->dim.truckCenter, 3, "," ); + CsvFormatLong( f, wDrawGetRGB(item->color), "," ); + CsvFormatFloat( f, item->data.purchPrice, 2, "," ); + CsvFormatFloat( f, item->data.currPrice, 2, "," ); + CsvFormatLong( f, item->data.condition, "," ); + CsvFormatLong( f, item->data.purchDate, "," ); + CsvFormatLong( f, item->data.serviceDate, "," ); + if ( item->data.notes ) + CsvFormatString( f, item->data.notes, strlen(item->data.notes), "\n" ); + else + CsvFormatString( f, "", strlen(""), "\n" ); + } + fclose( f ); + RestoreLocale(oldLocale); + return TRUE; +} + + +static struct wFilSel_t * carInvExportCsv_fs; +static void CarInvDlgExportCsv( void ) +{ + if ( carItemInfo_da.cnt <= 0 ) + return; + if ( carInvExportCsv_fs == NULL ) + carInvExportCsv_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Export Cars"), + _("Comma-Separated-Values|*.csv"), CarInvExportCsv, NULL ); + wFilSelect( carInvExportCsv_fs, curDirName ); +} + + +static void CarInvLoadItem( + carItem_p item ) +{ +/* "Index", "Scale", "Manufacturer", "Type", "Part No", "Description", "Roadname", "RepMarks", + "Purch Price", "Curr Price", "Condition", "Purch Date", "Service Date", "Location", "Notes" */ + char *condition; + char *location; + char *manuf; + char *road; + char notes[100]; + tabString_t tabs[7]; + + TabStringExtract( item->title, 7, tabs ); + if ( item->data.notes ) { + strncpy( notes, item->data.notes, sizeof notes - 1 ); + notes[sizeof notes - 1] = '\0'; + } else { + notes[0] = '\0'; + } + condition = + (item->data.condition < 10) ? N_("N/A"): + (item->data.condition < 30) ? N_("Poor"): + (item->data.condition < 50) ? N_("Fair"): + (item->data.condition < 70) ? N_("Good"): + (item->data.condition < 90) ? N_("Excellent"): + N_("Mint"); + + if ( item->car && !IsTrackDeleted(item->car) ) + location = N_("Layout"); + else + location = N_("Shelf"); + + manuf = TabStringDup(&tabs[T_MANUF]); + road = TabStringDup(&tabs[T_ROADNAME]); + sprintf( message, "%ld\t%s\t%s\t%.*s\t%s\t%.*s%s%.*s\t%s\t%.*s%s%.*s\t%0.2f\t%0.2f\t%s\t%ld\t%ld\t%s\t%s", + item->index, GetScaleName(item->scaleInx), + _(manuf), + tabs[T_PART].len, tabs[T_PART].ptr, + _(typeListMap[CarProtoFindTypeCode(item->type)].name), + tabs[T_PROTO].len, tabs[T_PROTO].ptr, + (tabs[T_PROTO].len>0 && tabs[T_DESC].len)?"/":"", + tabs[T_DESC].len, tabs[T_DESC].ptr, + _(road), + tabs[T_REPMARK].len, tabs[T_REPMARK].ptr, + (tabs[T_REPMARK].len>0&&tabs[T_NUMBER].len>0)?" ":"", + tabs[T_NUMBER].len, tabs[T_NUMBER].ptr, + item->data.purchPrice, item->data.currPrice, _(condition), item->data.purchDate, item->data.serviceDate, _(location), notes ); + if (manuf) MyFree(manuf); + if (road) MyFree(road); + wListAddValue( (wList_p)carInvPLs[I_CI_LIST].control, message, NULL, item ); +} + + +static int Cmp_carInvItem( + const void * ptr1, + const void * ptr2 ) +{ + carItem_p item1 = *(carItem_p*)ptr1; + carItem_p item2 = *(carItem_p*)ptr2; + tabString_t tabs1[7], tabs2[7]; + int inx; + int rc; + + TabStringExtract( item1->title, 7, tabs1 ); + TabStringExtract( item2->title, 7, tabs2 ); + for ( inx=0,rc=0; inx<N_SORT&&rc==0; inx++ ) { + switch ( carInvSort[inx] ) { + case S_INDEX: + rc = (int)(item1->index-item2->index); + break; + case S_SCALE: + rc = (int)(item1->scaleInx-item2->scaleInx); + case S_MANUF: + rc = strncasecmp( tabs1[T_MANUF].ptr, tabs2[T_MANUF].ptr, max(tabs1[T_MANUF].len,tabs2[T_MANUF].len) ); + break; + case S_TYPE: + rc = (int)(item1->type-item2->type); + break; + case S_PARTNO: + rc = strncasecmp( tabs1[T_PART].ptr, tabs2[T_PART].ptr, max(tabs1[T_PART].len,tabs2[T_PART].len) ); + break; + case S_DESC: + rc = strncasecmp( tabs1[T_PROTO].ptr, tabs2[T_PROTO].ptr, max(tabs1[T_PROTO].len,tabs2[T_PROTO].len) ); + if ( rc != 0 ) + break; + rc = strncasecmp( tabs1[T_DESC].ptr, tabs2[T_DESC].ptr, max(tabs1[T_DESC].len,tabs2[T_DESC].len) ); + break; + case S_ROADNAME: + rc = strncasecmp( tabs1[T_ROADNAME].ptr, tabs2[T_ROADNAME].ptr, max(tabs1[T_ROADNAME].len,tabs2[T_ROADNAME].len) ); + break; + case S_REPMARKS: + rc = strncasecmp( tabs1[T_REPMARK].ptr, tabs2[T_REPMARK].ptr, max(tabs1[T_REPMARK].len,tabs2[T_REPMARK].len) ); + break; + case S_PURCHPRICE: + rc = (int)(item1->data.purchPrice-item2->data.purchPrice); + break; + case S_CURRPRICE: + rc = (int)(item1->data.currPrice-item2->data.currPrice); + break; + case S_CONDITION: + rc = (int)(item1->data.condition-item2->data.condition); + break; + case S_PURCHDATE: + rc = (int)(item1->data.purchDate-item2->data.purchDate); + break; + case S_SRVDATE: + rc = (int)(item1->data.serviceDate-item2->data.serviceDate); + break; + default: + break; + } + } + return rc; +} + +static void CarInvListLoad( void ) +{ + int inx; + carItem_p item; + + qsort( carItemInfo_da.ptr, carItemInfo_da.cnt, sizeof item, Cmp_carInvItem ); + ParamControlShow( &carInvPG, I_CI_LIST, FALSE ); + wListClear( (wList_p)carInvPLs[I_CI_LIST].control ); + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) { + item = carItemInfo(inx); + CarInvLoadItem( item ); + } + ParamControlShow( &carInvPG, I_CI_LIST, TRUE ); + ParamControlActive( &carInvPG, I_CI_EDIT, FALSE ); + ParamControlActive( &carInvPG, I_CI_DELETE, FALSE ); + ParamControlActive( &carInvPG, I_CI_EXPORT_CSV, carItemInfo_da.cnt > 0 ); + ParamDialogOkActive( &carInvPG, FALSE ); +} + + +static void CarInvDlgUpdate( + paramGroup_p pg, + int inx, + void * valueP ) +{ + carItem_p item = NULL; + wIndex_t cnt, selinx, selcnt; + wBool_t enableDelete; + + if ( inx >= I_CI_SORT && inx < I_CI_SORT+N_SORT ) { + item = CarInvDlgFindCurrentItem(); + CarInvListLoad(); + if ( item ) { + carInvInx = (wIndex_t)CarItemFindIndex( item ); + if ( carInvInx >= 0 ) + ParamLoadControl( &carInvPG, I_CI_LIST ); + } + } else if ( inx == I_CI_LIST ) { + cnt = wListGetCount( (wList_p)carInvPLs[I_CI_LIST].control ); + enableDelete = TRUE; + for ( selinx=selcnt=0; selinx<cnt; selinx++ ) { + if ( wListGetItemSelected( (wList_p)carInvPLs[I_CI_LIST].control, selinx ) ) { + selcnt++; + item = (carItem_p)wListGetItemContext( (wList_p)carInvPLs[I_CI_LIST].control, selinx ); + if ( item && item->car && !IsTrackDeleted( item->car ) ) { + enableDelete = FALSE; + break; + } + } + } + item = CarInvDlgFindCurrentItem(); + ParamDialogOkActive( pg, selcnt==1 && item && item->car && !IsTrackDeleted(item->car) ); + ParamControlActive( &carInvPG, I_CI_EDIT, selcnt==1 && item && (item->car==NULL || IsTrackDeleted(item->car)) ); + ParamControlActive( &carInvPG, I_CI_DELETE, selcnt>0 && enableDelete ); + } +} + + +static void CarInvListAdd( + carItem_p item ) +{ + CarInvListLoad(); + carInvInx = (wIndex_t)CarItemFindIndex( item ); + if ( carInvInx >= 0 ) { + ParamLoadControl( &carInvPG, I_CI_LIST ); + } +} + + +static void CarInvListUpdate( + carItem_p item ) +{ + CarInvListLoad(); + carInvInx = (wIndex_t)CarItemFindIndex( item ); + if ( carInvInx >= 0 ) { + ParamLoadControl( &carInvPG, I_CI_LIST ); + } +} + + +EXPORT void DoCarDlg( void ) +{ + int inx, inx2; + if ( carInvPG.win == NULL ) { + ParamCreateDialog( &carInvPG, MakeWindowTitle(_("Car Inventory")), _("Find"), CarInvDlgFind, wHide, TRUE, NULL, F_BLOCK|F_RESIZE|F_RECALLSIZE|PD_F_ALT_CANCELLABEL, CarInvDlgUpdate ); + for ( inx=I_CI_SORT; inx<I_CI_SORT+N_SORT; inx++ ) { + for ( inx2=0; inx2<sizeof sortOrders/sizeof sortOrders[0]; inx2++ ) { + wListAddValue( (wList_p)carInvPLs[inx].control, _(sortOrders[inx2]), NULL, NULL ); + ParamLoadControl( &carInvPG, inx ); + } + } + ParamDialogOkActive( &carInvPG, FALSE ); + } + CarInvListLoad(); + wShow( carInvPG.win ); +} + + +static void CarDlgChange( long changes ) +{ + if ( (changes&CHANGE_SCALE) ) { + carPartChangeLevel = 0; + carDlgCouplerLength = 0.0; + } +} + + +EXPORT void ClearCars( void ) +{ + int inx; + for ( inx=0; inx<carItemInfo_da.cnt; inx++ ) + MyFree( carItemInfo(inx) ); + carItemInfo_da.cnt = 0; + carItemInfo_da.max = 0; + if ( carItemInfo_da.ptr ) + MyFree( carItemInfo_da.ptr ); + carItemInfo_da.ptr = NULL; +} + + +static struct { + dynArr_t carProto_da; + dynArr_t carPartParent_da; + dynArr_t carItemInfo_da; + } savedCarState; + +EXPORT void SaveCarState( void ) +{ + savedCarState.carProto_da = carProto_da; + savedCarState.carPartParent_da = carPartParent_da; + savedCarState.carItemInfo_da = carItemInfo_da; + carItemInfo_da.cnt = carItemInfo_da.max = 0; + carItemInfo_da.ptr = NULL; +} + + +EXPORT void RestoreCarState( void ) +{ +#ifdef LATER + carProto_da = savedCarState.carProto_da; + carPartParent_da = savedCarState.carPartParent_da; +#endif + carItemInfo_da = savedCarState.carItemInfo_da; +} + + + +EXPORT void InitCarDlg( void ) +{ + log_carList = LogFindIndex( "carList" ); + log_carInvList = LogFindIndex( "carInvList" ); + log_carDlgState = LogFindIndex( "carDlgState" ); + log_carDlgList = LogFindIndex( "carDlgList" ); + carDlgBodyColor = wDrawFindColor( wRGB(255,128,0) ); + ParamRegister( &carDlgPG ); + ParamRegister( &carInvPG ); + RegisterChangeNotification( CarDlgChange ); + AddParam( "CARPROTO ", CarProtoRead ); + AddParam( "CARPART ", CarPartRead ); + ParamRegister( &newCarPG ); + ParamCreateControls( &newCarPG, CarItemHotbarUpdate ); + newCarControls[0] = newCarPLs[0].control; +} + +/***************************************************************************** + * + * Custom Management Support + * + */ + +static int CarPartCustMgmProc( + int cmd, + void * data ) +{ + tabString_t tabs[7]; + int rd_inx; + + carPart_p partP = (carPart_p)data; + switch ( cmd ) { + case CUSTMGM_DO_COPYTO: + return CarPartWrite( customMgmF, partP ); + case CUSTMGM_CAN_EDIT: + return TRUE; + case CUSTMGM_DO_EDIT: + if ( partP == NULL ) + return FALSE; + carDlgUpdatePartPtr = partP; + DoCarPartDlg( partUpdActions ); + return TRUE; + case CUSTMGM_CAN_DELETE: + return TRUE; + case CUSTMGM_DO_DELETE: + CarPartDelete( partP ); + return TRUE; + case CUSTMGM_GET_TITLE: + TabStringExtract( partP->title, 7, tabs ); + rd_inx = T_REPMARK; + if ( tabs[T_REPMARK].len == 0 ) + rd_inx = T_ROADNAME; + sprintf( message, "\t%s\t%s\t%.*s\t%s%s%.*s%s%.*s%s%.*s", + partP->parent->manuf, + GetScaleName(partP->parent->scale), + tabs[T_PART].len, tabs[T_PART].ptr, + partP->parent->proto, + tabs[T_DESC].len?", ":"", tabs[T_DESC].len, tabs[T_DESC].ptr, + tabs[rd_inx].len?", ":"", tabs[rd_inx].len, tabs[rd_inx].ptr, + tabs[T_NUMBER].len?" ":"", tabs[T_NUMBER].len, tabs[T_NUMBER].ptr ); + return TRUE; + } + return FALSE; +} + + +static int CarProtoCustMgmProc( + int cmd, + void * data ) +{ + carProto_p protoP = (carProto_p)data; + switch ( cmd ) { + case CUSTMGM_DO_COPYTO: + return CarProtoWrite( customMgmF, protoP ); + case CUSTMGM_CAN_EDIT: + return TRUE; + case CUSTMGM_DO_EDIT: + if ( protoP == NULL ) + return FALSE; + carDlgUpdateProtoPtr = protoP; + DoCarPartDlg( protoUpdActions ); + return TRUE; + case CUSTMGM_CAN_DELETE: + return TRUE; + case CUSTMGM_DO_DELETE: + CarProtoDelete( protoP ); + return TRUE; + case CUSTMGM_GET_TITLE: + sprintf( message, "\t%s\t\t%s\t%s", _("Prototype"), _(typeListMap[CarProtoFindTypeCode(protoP->type)].name), protoP->desc ); + return TRUE; + } + return FALSE; +} + + +#include "bitmaps/carpart.xpm" +#include "bitmaps/carproto.xpm" + +EXPORT void CarCustMgmLoad( void ) +{ + long parentX, partX, protoX; + carPartParent_p parentP; + carPart_p partP; + carProto_p carProtoP; + static wIcon_p carpartI = NULL; + static wIcon_p carprotoI = NULL; + + if ( carpartI == NULL ) + carpartI = wIconCreatePixMap( carpart_xpm ); + if ( carprotoI == NULL ) + carprotoI = wIconCreatePixMap( carproto_xpm ); + + for ( parentX=0; parentX<carPartParent_da.cnt; parentX++ ) { + parentP = carPartParent(parentX); + for ( partX=0; partX<parentP->parts_da.cnt; partX++ ) { + partP = carPart(parentP,partX); + if ( partP->paramFileIndex != PARAM_CUSTOM ) + continue; + CustMgmLoad( carpartI, CarPartCustMgmProc, (void*)partP ); + } + } + + for ( protoX=0; protoX<carProto_da.cnt; protoX++ ) { + carProtoP = carProto(protoX); + if ( carProtoP->paramFileIndex != PARAM_CUSTOM ) + continue; + if (carProtoP->paramFileIndex == PARAM_CUSTOM) { + CustMgmLoad( carprotoI, CarProtoCustMgmProc, (void*)carProtoP ); + } + } +} |