summaryrefslogtreecommitdiff
path: root/app/bin/dcar.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2016-12-28 16:52:56 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2016-12-28 16:52:56 +0100
commit7b358424ebad9349421acd533c2fa1cbf6cf3e3e (patch)
tree686678532eefed525c242fd214d0cfb2914726c5 /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.c5150
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, &notesData, 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 );
+ }
+ }
+}