/** \file dlayer.c * Functions and dialogs for handling layers. */ /* XTrkCad - Model Railroad CAD * Copyright (C) 2005 Dave Bullis and (C) 2007 Martin Fischer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" #include "cselect.h" #include "custom.h" #include "paths.h" #include "dynstring.h" #include "fileio.h" #include "layout.h" #include "param.h" #include "track.h" #include "include/partcatalog.h" #include "include/stringxtc.h" #include "common-ui.h" /***************************************************************************** * * LAYERS * */ #define NUM_BUTTONS (99) #define LAYERPREF_FROZEN (1) #define LAYERPREF_ONMAP (2) #define LAYERPREF_VISIBLE (4) #define LAYERPREF_MODULE (8) #define LAYERPREF_NOBUTTON (16) #define LAYERPREF_DEFAULT (32) #define LAYERPREF_SECTION ("Layers") #define LAYERPREF_NAME "name" #define LAYERPREF_COLOR "color" #define LAYERPREF_FLAGS "flags" #define LAYERPREF_SCALEINX "scaleInx" #define LAYERPREF_SCLDESCINX "sclDescInx" #define LAYERPREF_GAUGEINX "gaugeInx" #define LAYERPREF_MINRADIUS "minRadius" #define LAYERPREF_MAXGRADE "maxGrade" #define LAYERPREF_TIELENGTH "tieLength" #define LAYERPREF_TIEWIDTH "tieWidth" #define LAYERPREF_TIESPACING "tieSpacing" #define LAYERPREF_LIST "list" #define LAYERPREF_SETTINGS "settings" static paramIntegerRange_t r_nocheck = { 0, 1, 100, PDO_NORANGECHECK_LOW | PDO_NORANGECHECK_HIGH }; static paramFloatRange_t r_tieData = { 0.05, 100.0, 100, PDO_NORANGECHECK_LOW | PDO_NORANGECHECK_HIGH }; static paramFloatRange_t r0_10000 = { 0.0, 10000.0 }; static paramFloatRange_t r0_90 = { 0.0, 90.0 }; EXPORT unsigned int maxLayer; unsigned int curLayer; long layerCount = 10; static long newLayerCount = 10; static unsigned int layerSelected = 0; static BOOL_T layoutLayerChanged = FALSE; static wIcon_p show_layer_bmps[NUM_BUTTONS]; static wButton_p layer_btns[NUM_BUTTONS]; /**< layer buttons on toolbar */ /** Layer selector on toolbar */ static wList_p setLayerL; /** Describe the properties of a layer * Defaults for layout track grade and min radius are in scale.c: SetScale */ typedef struct { char name[STR_SHORT_SIZE]; /**< Layer name */ wDrawColor color; /**< layer color, is an index into a color table */ BOOL_T useColor; /**< Use Layer color */ BOOL_T frozen; /**< Frozen flag */ BOOL_T visible; /**< visible flag */ BOOL_T onMap; /**< is layer shown map */ BOOL_T module; /**< is layer a module (all or nothing) */ BOOL_T button_off; /**< hide button */ BOOL_T inherit; /**< inherit layout defaults */ SCALEINX_T scaleInx; /**< scale override */ SCALEDESCINX_T scaleDescInx; /**< the scale description */ GAUGEINX_T gaugeInx; /**< the gauge desc index */ DIST_T minTrackRadius; /**< minimum track radius */ ANGLE_T maxTrackGrade; /**< maximum track grade */ tieData_t tieData; /**< tie data structure */ long objCount; /**< number of objects on layer */ dynArr_t layerLinkList; /**< other layers that show/hide with this one, 1-based index */ char settingsName[STR_SHORT_SIZE]; /**< name of settings file to load when this is current */ } layer_t; static layer_t layers[NUM_LAYERS]; static layer_t *layers_save = NULL; static Catalog * settingsCatalog; static int oldColorMap[][3] = { { 255, 255, 255 }, /* White */ { 0, 0, 0 }, /* Black */ { 255, 0, 0 }, /* Red */ { 0, 255, 0 }, /* Green */ { 0, 0, 255 }, /* Blue */ { 255, 255, 0 }, /* Yellow */ { 255, 0, 255 }, /* Purple */ { 0, 255, 255 }, /* Aqua */ { 128, 0, 0 }, /* Dk. Red */ { 0, 128, 0 }, /* Dk. Green */ { 0, 0, 128 }, /* Dk. Blue */ { 128, 128, 0 }, /* Dk. Yellow */ { 128, 0, 128 }, /* Dk. Purple */ { 0, 128, 128 }, /* Dk. Aqua */ { 65, 105, 225 }, /* Royal Blue */ { 0, 191, 255 }, /* DeepSkyBlue */ { 125, 206, 250 }, /* LightSkyBlue */ { 70, 130, 180 }, /* Steel Blue */ { 176, 224, 230 }, /* Powder Blue */ { 127, 255, 212 }, /* Aquamarine */ { 46, 139, 87 }, /* SeaGreen */ { 152, 251, 152 }, /* PaleGreen */ { 124, 252, 0 }, /* LawnGreen */ { 50, 205, 50 }, /* LimeGreen */ { 34, 139, 34 }, /* ForestGreen */ { 255, 215, 0 }, /* Gold */ { 188, 143, 143 }, /* RosyBrown */ { 139, 69, 19 }, /* SaddleBrown */ { 245, 245, 220 }, /* Beige */ { 210, 180, 140 }, /* Tan */ { 210, 105, 30 }, /* Chocolate */ { 165, 42, 42 }, /* Brown */ { 255, 165, 0 }, /* Orange */ { 255, 127, 80 }, /* Coral */ { 255, 99, 71 }, /* Tomato */ { 255, 105, 180 }, /* HotPink */ { 255, 192, 203 }, /* Pink */ { 176, 48, 96 }, /* Maroon */ { 238, 130, 238 }, /* Violet */ { 160, 32, 240 }, /* Purple */ { 16, 16, 16 }, /* Gray */ { 32, 32, 32 }, /* Gray */ { 48, 48, 48 }, /* Gray */ { 64, 64, 64 }, /* Gray */ { 80, 80, 80 }, /* Gray */ { 96, 96, 96 }, /* Gray */ { 112, 112, 122 }, /* Gray */ { 128, 128, 128 }, /* Gray */ { 144, 144, 144 }, /* Gray */ { 160, 160, 160 }, /* Gray */ { 176, 176, 176 }, /* Gray */ { 192, 192, 192 }, /* Gray */ { 208, 208, 208 }, /* Gray */ { 224, 224, 224 }, /* Gray */ { 240, 240, 240 }, /* Gray */ { 0, 0, 0 } /* BlackPixel */ }; static void DoLayerOp(void * data); void UpdateLayerDlg(unsigned int); static void InitializeLayers(void LayerInitFunc(void), int newCurrLayer); static void LayerPrefSave(void); static void LayerPrefLoad(void); int IsLayerValid(unsigned int layer) { return (layer <= NUM_LAYERS && layer != -1); } BOOL_T GetLayerVisible(unsigned int layer) { if (!IsLayerValid(layer)) { return TRUE; } else { return layers[layer].visible; } } BOOL_T GetLayerHidden(unsigned int layer) { if (!IsLayerValid(layer)) { return TRUE; } else { return layers[layer].button_off; } } BOOL_T GetLayerFrozen(unsigned int layer) { if (!IsLayerValid(layer)) { return TRUE; } else { return layers[layer].frozen; } } BOOL_T GetLayerOnMap(unsigned int layer) { if (!IsLayerValid(layer)) { return TRUE; } else { return layers[layer].onMap; } } EXPORT BOOL_T GetLayerUseDefault(unsigned int layer) { if (!IsLayerValid(layer)) { return TRUE; } else { return layers[layer].inherit; } } EXPORT SCALEINX_T GetLayerScale( unsigned int layer ) { if ( IsLayerValid(layer) && !GetLayerUseDefault(layer) ) { return layers[layer].scaleInx; } return GetLayoutCurScale(); // layout scale } EXPORT DIST_T GetLayerMinTrackRadius( unsigned int layer ) { if ( IsLayerValid(layer) && !GetLayerUseDefault(layer) ) { return layers[layer].minTrackRadius; } return GetLayoutMinTrackRadius(); } EXPORT ANGLE_T GetLayerMaxTrackGrade( unsigned int layer ) { if ( IsLayerValid(layer) && !GetLayerUseDefault(layer) ) { return layers[layer].maxTrackGrade; } return GetLayoutMaxTrackGrade(); } EXPORT tieData_t GetLayerTieData( unsigned int layer ) { if ( IsLayerValid(layer) && !GetLayerUseDefault(layer) && layers[layer].tieData.valid ) { return layers[layer].tieData; } return GetScaleTieData(GetLayoutCurScale()); // layout scale default tie data } BOOL_T GetLayerModule(unsigned int layer) { if (!IsLayerValid(layer)) { return TRUE; } else { return layers[layer].module; } } void SetLayerModule(unsigned int layer, BOOL_T module) { if (IsLayerValid(layer)) { layers[layer].module = module; } } void SetLayerDefault(unsigned int layer, BOOL_T inherit) { if (IsLayerValid(layer)) { layers[layer].inherit = inherit; } } char * GetLayerName(unsigned int layer) { if (!IsLayerValid(layer)) { return NULL; } else { return layers[layer].name; } } void SetLayerName(unsigned int layer, char* name) { if (IsLayerValid(layer)) { strcpy(layers[layer].name, name); } } BOOL_T GetLayerUseColor(unsigned int layer) { return layers[layer].useColor; } wDrawColor GetLayerColor(unsigned int layer) { return layers[layer].color; } static void RedrawLayer( unsigned int l, BOOL_T draw ) { DoRedraw(); } EXPORT void FlipLayer( void * layerVP ) { unsigned int layer = (unsigned int)VP2L(layerVP); wBool_t visible; if (!IsLayerValid(layer)) { return; } if (layer == curLayer && layers[layer].visible) { if (!layers[layer].button_off) { wButtonSetBusy(layer_btns[layer], layers[layer].visible); } NoticeMessage(MSG_LAYER_HIDE, _("Ok"), NULL); return; } RedrawLayer(layer, FALSE); visible = !layers[layer].visible; layers[layer].visible = visible; if (layer < NUM_BUTTONS) { if (!layers[layer].button_off) { wButtonSetBusy(layer_btns[layer], visible != 0); wButtonSetLabel(layer_btns[layer], (char *)show_layer_bmps[layer]); } } /* Set visible on related layers other than current */ for (int i = 0; i < layers[layer].layerLinkList.cnt; i++) { // .layerLinkList values are 1-based layer indices int l = DYNARR_N(int, layers[layer].layerLinkList, i) - 1; if ((l != curLayer) && (l >= 0) && (l < NUM_LAYERS)) { layers[l].visible = layers[layer].visible; if (!layers[l].button_off) { wButtonSetBusy(layer_btns[l], layers[l].visible); } } } RedrawLayer(layer, TRUE); } static char lastSettings[STR_SHORT_SIZE]; void SetCurrLayer(wIndex_t inx, const char * name, wIndex_t op, void * listContext, void * arg) { unsigned int newLayer = (unsigned int)inx; if (layers[newLayer].frozen) { NoticeMessage(MSG_LAYER_SEL_FROZEN, _("Ok"), NULL); wListSetIndex(setLayerL, curLayer); return; } char *array[1]; if (!layers[inx].settingsName[0] || strcmp(layers[inx].settingsName, " ") == 0) { if (lastSettings[0]) { DoSettingsRead(1, NULL, NULL); } lastSettings[0] = '\0'; } else { if (strcmp(layers[inx].settingsName, lastSettings) != 0) { if (!lastSettings[0]) { wPrefFlush(""); } // Save Last Settings for no settings file array[0] = layers[inx].settingsName; DoSettingsRead(1, array, NULL); } strcpy(lastSettings, layers[inx].settingsName); } curLayer = newLayer; if (!IsLayerValid(curLayer)) { curLayer = 0; //Too big or -1 layers[curLayer].frozen = FALSE; //Make sure the layer is not frozen } if (!layers[curLayer].visible) { FlipLayer(I2VP(inx)); } /* Set visible on related layers other than current */ for (int i = 0; i < layers[curLayer].layerLinkList.cnt; i++) { // .layerLinkList values are 1-based layer indices int l = DYNARR_N(int, layers[curLayer].layerLinkList, i) - 1; if (l != curLayer && l >= 0 && l < NUM_LAYERS) { layers[l].visible = layers[curLayer].visible; if (!layers[l].button_off) { wButtonSetBusy(layer_btns[l], layers[l].visible); } } } if (recordF) { fprintf(recordF, "SETCURRLAYER %d\n", inx); } } static void PlaybackCurrLayer(char * line) { wIndex_t layer; layer = atoi(line); wListSetIndex(setLayerL, layer); SetCurrLayer(layer, NULL, 0, NULL, NULL); } /** * Change the color of a layer. * * \param inx IN layer to change * \param color IN new color */ static void SetLayerColor(unsigned int inx, wDrawColor color) { if (color != layers[inx].color) { if (inx < NUM_BUTTONS) { wIconSetColor(show_layer_bmps[inx], color); wButtonSetLabel(layer_btns[inx], (char*)show_layer_bmps[inx]); } layers[inx].color = color; layoutLayerChanged = TRUE; } } static void SetLayerHideButton(unsigned int inx, wBool_t hide) { if (hide != layers[inx].button_off) { if (inx < NUM_BUTTONS) { wControlShow((wControl_p)layer_btns[inx], !hide); if (!hide) { wButtonSetBusy(layer_btns[inx], layers[inx].visible); } } layers[inx].button_off = hide; layoutLayerChanged = TRUE; } } char * FormatLayerName(unsigned int layerNumber) { DynString string;// = NaS; char *result; DynStringMalloc(&string, 0); DynStringPrintf(&string, "%2d %c %s", layerNumber + 1, (layers[layerNumber].frozen ? '*' : layers[layerNumber].module ? 'm' : layers[layerNumber].objCount > 0 ? '+' : '-'), layers[layerNumber].name); result = strdup(DynStringToCStr(&string)); DynStringFree(&string); return result; } static char *show_layer_bits; static long layerRawColorTab[] = { wRGB( 0, 0, 192), /* blue */ wRGB( 0, 192, 0), /* green */ wRGB(192, 0, 0), /* red */ wRGB(128, 128, 0), /* yellow */ wRGB( 0, 128, 128), /* cyan */ wRGB( 0, 0, 128), /* dk blue */ wRGB( 0, 128, 0), /* dk green */ wRGB(128, 0, 0), /* dk red */ wRGB( 96, 96, 0), /* green-brown */ wRGB( 0, 96, 96) /* dk cyan */ }; static wDrawColor layerColorTab[COUNT(layerRawColorTab)]; static wWin_p layerW; static char layerName[STR_SHORT_SIZE]; static char layerLinkList[STR_LONG_SIZE]; static char settingsName[STR_SHORT_SIZE]; static wDrawColor layerColor; static long layerUseColor = TRUE; static long layerVisible = TRUE; static long layerFrozen = FALSE; static long layerOnMap = TRUE; static long layerModule = FALSE; static long layerNoButton = FALSE; static long layerInherit = FALSE; static SCALEINX_T layerScaleInx; static SCALEDESCINX_T layerScaleDescInx; static GAUGEINX_T layerGaugeInx; static DIST_T layerMinRadius; static ANGLE_T layerMaxGrade; static tieData_t layerTieData; static long layerObjectCount; static void LayerOk(void * unused); static BOOL_T layerRedrawMap = FALSE; #define ENUMLAYER_RELOAD (1) #define ENUMLAYER_SAVE (2) #define ENUMLAYER_CLEAR (3) #define ENUMLAYER_ADD (4) #define ENUMLAYER_DELETE (5) #define ENUMLAYER_DEFAULT (6) static char *visibleLabels[] = { "", NULL }; static char *frozenLabels[] = { "", NULL }; static char *onMapLabels[] = { "", NULL }; static char *moduleLabels[] = { "", NULL }; static char *noButtonLabels[] = { "", NULL }; static char *defaultLabels[] = { "", NULL }; static char *layerColorLabels[] = { "", NULL }; static paramIntegerRange_t i0_20 = { 0, NUM_BUTTONS }; //static paramListData_t layerUiListData = { 10, 370, 0 }; static paramData_t layerPLs[] = { #define I_LIST (0) { PD_DROPLIST, NULL, "layer", PDO_LISTINDEX, I2VP(250), N_("Select Layer:") }, #define I_NAME (1) { PD_STRING, layerName, "name", PDO_NOPREF | PDO_STRINGLIMITLENGTH | PDO_DLGBOXEND, I2VP(250 - 54), N_("Name"), 0, 0, sizeof(layerName) }, #define I_COLOR (2) { PD_COLORLIST, &layerColor, "color", PDO_NOPREF, NULL, N_("Color") }, #define I_USE_COLOR (3) { PD_TOGGLE, &layerUseColor, "layercolor", PDO_NOPREF | PDO_DLGHORZ, layerColorLabels, N_("Use Color"), BC_HORZ | BC_NOBORDER }, #define I_VIS (4) { PD_TOGGLE, &layerVisible, "visible", PDO_NOPREF, visibleLabels, N_("Visible"), BC_HORZ | BC_NOBORDER }, #define I_FRZ (5) { PD_TOGGLE, &layerFrozen, "frozen", PDO_NOPREF | PDO_DLGHORZ, frozenLabels, N_("Frozen"), BC_HORZ | BC_NOBORDER }, #define I_MAP (6) { PD_TOGGLE, &layerOnMap, "onmap", PDO_NOPREF | PDO_DLGHORZ, onMapLabels, N_("On Map"), BC_HORZ | BC_NOBORDER }, #define I_MOD (7) { PD_TOGGLE, &layerModule, "module", PDO_NOPREF | PDO_DLGHORZ, moduleLabels, N_("Module"), BC_HORZ | BC_NOBORDER }, #define I_BUT (8) { PD_TOGGLE, &layerNoButton, "button", PDO_NOPREF | PDO_DLGHORZ, noButtonLabels, N_("No Button"), BC_HORZ | BC_NOBORDER }, #define I_DEF (9) { PD_TOGGLE, &layerInherit, "inherit", PDO_NOPREF | PDO_DLGHORZ | PDO_DLGBOXEND, defaultLabels, N_("Inherit"), BC_HORZ | BC_NOBORDER }, #define I_SCALE (10) { PD_DROPLIST, &layerScaleDescInx, "scale", PDO_NOPREF | PDO_NOPSHUPD | PDO_NORECORD | PDO_NOUPDACT, I2VP(180), N_("Scale"), 0, I2VP(CHANGE_LAYER) }, #define I_GAUGE (11) { PD_DROPLIST, &layerGaugeInx, "gauge", PDO_NOPREF | PDO_NOPSHUPD | PDO_NORECORD | PDO_NOUPDACT | PDO_DLGHORZ, I2VP(180), N_(" Gauge") }, #define I_MINRADIUSENTRY (12) { PD_FLOAT, &layerMinRadius, "mintrackradius", PDO_DIM | PDO_NOPSHUPD | PDO_NOPREF, &r0_10000, N_("Min Track Radius"), 0, I2VP(CHANGE_MAIN | CHANGE_LIMITS) }, #define I_MAXGRADEENTRY (13) { PD_FLOAT, &layerMaxGrade, "maxtrackgrade", PDO_NOPSHUPD | PDO_DLGHORZ | PDO_NOPREF, &r0_90, N_(" Max Track Grade (%)"), 0, I2VP(CHANGE_MAIN) }, #define I_TIELEN (14) { PD_FLOAT, &layerTieData.length, "tielength", PDO_NOPREF, &r_tieData, N_( "Tie Length" ), 0, I2VP( CHANGE_MAIN ) }, #define I_TIEWID (15) { PD_FLOAT, &layerTieData.width, "tiewidth", PDO_NOPREF | PDO_DLGHORZ, &r_tieData, N_( " Width" ), 0, I2VP( CHANGE_MAIN ) }, #define I_TIESPC (16) { PD_FLOAT, &layerTieData.spacing, "tiespacing", PDO_NOPREF | PDO_DLGHORZ | PDO_DLGBOXEND, &r_tieData, N_( " Spacing" ), 0, I2VP( CHANGE_MAIN ) }, { PD_MESSAGE, N_("Layer Actions"), NULL, PDO_DLGRESETMARGIN, I2VP(180) }, #define I_ADD (18) { PD_BUTTON, DoLayerOp, "add", PDO_DLGRESETMARGIN, 0, N_("Add Layer"), 0, I2VP(ENUMLAYER_ADD) }, #define I_DELETE (19) { PD_BUTTON, DoLayerOp, "delete", PDO_DLGHORZ, 0, N_("Delete Layer"), 0, I2VP(ENUMLAYER_DELETE) }, #define I_DEFAULT (20) { PD_BUTTON, DoLayerOp, "default", PDO_DLGHORZ | PDO_DLGBOXEND, 0, N_("Default Values"), 0, I2VP(ENUMLAYER_DEFAULT) }, { PD_LONG, &newLayerCount, "button-count", PDO_DLGBOXEND | PDO_DLGRESETMARGIN, &i0_20, N_("Number of Layer Buttons") }, #define I_LINKLIST (22) { PD_STRING, layerLinkList, "layerlist", PDO_NOPREF | PDO_STRINGLIMITLENGTH, I2VP(250 - 54), N_("Linked Layers"), 0, 0, sizeof(layerLinkList) }, #define I_SETTINGS (23) { PD_DROPLIST, NULL, "settings", PDO_LISTINDEX, I2VP(250), N_("Settings when Current") }, #define I_COUNT (24) { PD_LONG, &layerObjectCount, "objectCount", PDO_DLGBOXEND, &r_nocheck, N_("Object Count:"), 0, 0 }, { PD_MESSAGE, N_("All Layer Preferences"), NULL, PDO_DLGRESETMARGIN, I2VP(180) }, { PD_BUTTON, DoLayerOp, "load", PDO_DLGRESETMARGIN, 0, N_("Load"), 0, I2VP(ENUMLAYER_RELOAD) }, { PD_BUTTON, DoLayerOp, "save", PDO_DLGHORZ, 0, N_("Save"), 0, I2VP(ENUMLAYER_SAVE) }, { PD_BUTTON, DoLayerOp, "clear", PDO_DLGHORZ | PDO_DLGBOXEND, 0, N_("Defaults"), 0, I2VP(ENUMLAYER_CLEAR) }, }; #define settingsListL ((wList_p)layerPLs[I_SETTINGS].control) static paramGroup_t layerPG = { "layer", 0, layerPLs, COUNT( layerPLs ) }; /** * Reload the listbox showing the current catalog */ static int LoadFileListLoad(Catalog *catalog, char * name) { CatalogEntry *currentEntry = catalog->head; DynString description; DynStringMalloc(&description, STR_SHORT_SIZE); wControlShow((wControl_p)settingsListL, FALSE); wListClear(settingsListL); int currset = 0; int i = 0; wListAddValue(settingsListL, " ", NULL, " "); while (currentEntry) { i++; DynStringClear(&description); DynStringCatCStr(&description, currentEntry->contents) ; wListAddValue(settingsListL, DynStringToCStr(&description), NULL, currentEntry->fullFileName[0]); if (strcmp(currentEntry->fullFileName[0], name) == 0) { currset = i; } currentEntry = currentEntry->next; } wListSetIndex(settingsListL, currset); wControlShow((wControl_p)settingsListL, TRUE); DynStringFree(&description); if (currset == 0 && strcmp(" ", name) != 0) { return FALSE; } return TRUE; } #define layerL ((wList_p)layerPLs[I_LIST].control) #define layerS ((wList_p)layerPLs[I_SETTINGS].control) #define scaleL ((wList_p)layerPLs[I_SCALE].control) #define gaugeL ((wList_p)layerPLs[I_GAUGE].control) /** * @brief Reload Layer parameters if changes * @param changes */ static void LayerChange(long changes) { if (changes & (CHANGE_LAYER)) if (layerW != NULL && wWinIsVisible(layerW)) { ParamLoadControls(&layerPG); } } void GetLayerLinkString(int inx, char * list) { char * cp = &list[0]; cp[0] = '\0'; int len = 0; for (int i = 0; i < layers[inx].layerLinkList.cnt && len < STR_LONG_SIZE - 5; i++) { int l = DYNARR_N(int, layers[inx].layerLinkList, i); if (i == 0) { cp += sprintf(cp, "%d", l); } else { cp += sprintf(cp, ";%d", l); } cp[0] = '\0'; } } void PutLayerListArray(int inx, char * list) { char * cp = &list[0]; DYNARR_RESET(int, layers[inx].layerLinkList); while (cp) { cp = strpbrk(list, ",; "); if (cp) { cp[0] = '\0'; int i = abs((int)strtol(list, &list, 0)); if (i > 0 && i != inx - 1 && i < NUM_LAYERS) { DYNARR_APPEND(int, layers[inx].layerLinkList, 1); DYNARR_LAST(int, layers[inx].layerLinkList) = i; } cp[0] = ';'; list = cp + 1; } else { int i = abs((int)strtol(list, &list, 0)); if (i > 0 && i != inx - 1 && i < NUM_LAYERS) { DYNARR_APPEND(int, layers[inx].layerLinkList, 1); DYNARR_LAST(int, layers[inx].layerLinkList) = i; } cp = 0; } } } /** * Set a Layer to System Default */ void LayerSystemDefault( unsigned int inx ) { strcpy(layers[inx].name, inx == 0 ? _("Main") : ""); layers[inx].visible = TRUE; layers[inx].frozen = FALSE; layers[inx].onMap = TRUE; layers[inx].module = FALSE; layers[inx].button_off = FALSE; layers[inx].inherit = TRUE; layers[inx].scaleInx = 0; GetScaleGauge(layers[inx].scaleInx, &layers[inx].scaleDescInx, &layers[inx].gaugeInx); layers[inx].minTrackRadius = GetLayoutMinTrackRadius(); layers[inx].maxTrackGrade = GetLayoutMaxTrackGrade(); layers[inx].tieData.valid = FALSE; layers[inx].tieData.length = 0.0; layers[inx].tieData.width = 0.0; layers[inx].tieData.spacing = 0.0; layers[inx].objCount = 0; DYNARR_RESET(int, layers[inx].layerLinkList); SetLayerColor(inx, layerColorTab[inx % COUNT(layerColorTab)]); } /** * Is a layer the system default? */ BOOL_T IsLayerDefault( unsigned int inx ) { return (!layers[inx].name[0]) && layers[inx].visible && !layers[inx].frozen && layers[inx].onMap && !layers[inx].module && !layers[inx].button_off && layers[inx].inherit && (!layers[inx].layerLinkList.cnt) && (layers[inx].color == layerColorTab[inx % COUNT(layerColorTab)]) && layers[inx].scaleInx == 0 && //layers[inx].scaleDescInx != layerScaleDescInx || //layers[inx].gaugeInx != layerGaugeInx || layers[inx].minTrackRadius == GetLayoutMinTrackRadius() && layers[inx].maxTrackGrade == GetLayoutMaxTrackGrade() && layers[inx].tieData.valid == FALSE && layers[inx].tieData.length == 0.0 && layers[inx].tieData.width == 0.0 && layers[inx].tieData.spacing == 0.0; } /** * Load the layer settings to hard coded system defaults */ EXPORT void LayerAllDefaults(void) { int inx; for (inx = 0; inx < NUM_LAYERS; inx++) { LayerSystemDefault(inx); } } /** * Load the layer listboxes in Manage Layers and the Toolbar with up-to-date information. */ void LoadLayerLists(void) { int inx; /* clear both lists */ wListClear(setLayerL); if (layerL) { wListClear(layerL); } if (layerS) { wListClear(layerS); } /* add all layers to both lists */ for (inx = 0; inx < NUM_LAYERS; inx++) { char *layerLabel; layerLabel = FormatLayerName(inx); if (layerL) { wListAddValue(layerL, layerLabel, NULL, NULL); } wListAddValue(setLayerL, layerLabel, NULL, NULL); free(layerLabel); } /* set current layer to selected */ wListSetIndex(setLayerL, curLayer); if (layerL) { wListSetIndex(layerL, curLayer); } } /** * Add a layer after selected layer */ static void LayerAdd( ) { unsigned int inx; unsigned int newLayer = layerSelected + 1; // UndoStart( _("Add Layer"), "addlayer" ); maxLayer++; for ( inx = maxLayer; inx > newLayer; inx-- ) { layers[inx] = layers[inx - 1]; } TrackInsertLayer(newLayer); LayerSystemDefault(newLayer); strcpy(layers[newLayer].name, "New Layer"); layers[newLayer].objCount = 0; UpdateLayerDlg( newLayer ); layerSelected = newLayer; layoutLayerChanged = TRUE; // UndoEnd(); } /** * Delete the selected layer */ static void LayerDelete( ) { unsigned int inx; if (layers[layerSelected].objCount > 0) { NoticeMessage(_("Layer must not have any objects in it."), _("Ok"), NULL); return; } if (layerSelected <= maxLayer) { for ( inx = layerSelected; inx < maxLayer; inx++ ) { layers[inx] = layers[inx + 1]; } LayerSystemDefault(maxLayer); if (maxLayer > 0) { maxLayer--; } } TrackDeleteLayer( layerSelected ); UpdateLayerDlg( layerSelected ); layoutLayerChanged = TRUE; } /** * Set the Min Radius, Max Grade and Tie values to Layout or Scale defaults */ static void LayerDefault( ) { if ( layers[layerSelected].inherit ) { layers[layerSelected].scaleInx = GetLayoutCurScale( ); GetScaleGauge(layers[layerSelected].scaleInx, &layers[layerSelected].scaleDescInx, &layers[layerSelected].gaugeInx); layers[layerSelected].minTrackRadius = GetLayoutMinTrackRadius(); layers[layerSelected].maxTrackGrade = GetLayoutMaxTrackGrade(); } else { layers[layerSelected].scaleInx = GetLayerScale( layerSelected ); GetScaleGauge(layers[layerSelected].scaleInx, &layers[layerSelected].scaleDescInx, &layers[layerSelected].gaugeInx); layers[layerSelected].minTrackRadius = GetLayoutMinTrackRadius(); layers[layerSelected].maxTrackGrade = GetLayoutMaxTrackGrade(); } layers[layerSelected].tieData = GetScaleTieData(layers[layerSelected].scaleInx); UpdateLayerDlg( layerSelected ); layoutLayerChanged = TRUE; } /** * Handle button presses for the layer dialog. For all button presses in the layer * dialog, this function is called. The parameter identifies the button pressed and * the operation is performed. * * \param[IN] data identifier for the button pressed * \return */ static void DoLayerOp(void * data) { switch (VP2L(data)) { case ENUMLAYER_CLEAR: InitializeLayers(LayerAllDefaults, -1); break; case ENUMLAYER_SAVE: LayerPrefSave(); break; case ENUMLAYER_RELOAD: LayerPrefLoad(); break; case ENUMLAYER_ADD: LayerAdd(); break; case ENUMLAYER_DELETE: LayerDelete(); break; case ENUMLAYER_DEFAULT: LayerDefault(); break; } // UpdateLayerDlg(curLayer); //Reset to current Layer ParamControlActive( &layerPG, I_DELETE, (layerSelected > 0) ? TRUE : FALSE); if (layoutLayerChanged) { MainProc(mainW, wResize_e, NULL, NULL); layoutLayerChanged = FALSE; SetFileChanged(); } } /** * Update all dialogs and dialog elements after changing layers preferences. Once the global array containing * the settings for the labels has been changed, this function needs to be called to update all the user interface * elements to the new settings. */ EXPORT void UpdateLayerDlg(unsigned int layer) { int inx; /* update the globals for the layer dialog */ layerVisible = layers[layer].visible; layerFrozen = layers[layer].frozen; layerOnMap = layers[layer].onMap; layerModule = layers[layer].module; layerColor = layers[layer].color; layerUseColor = layers[layer].useColor; layerNoButton = layers[layer].button_off; layerInherit = layers[layer].inherit; layerScaleInx = layers[layer].scaleInx; layerScaleDescInx = layers[layer].scaleDescInx; layerGaugeInx = layers[layer].gaugeInx; layerMinRadius = layers[layer].minTrackRadius; layerMaxGrade = layers[layer].maxTrackGrade; layerTieData = layers[layer].tieData; layerObjectCount = layers[layer].objCount; strcpy(layerName, layers[layer].name); strcpy(settingsName, layers[layer].settingsName); GetLayerLinkString(layer, layerLinkList); layerSelected = layer; /* now re-load the layer list boxes */ LoadLayerLists(); /* Sync Scale and lists */ if (gaugeL) { LoadGaugeList(gaugeL, layerScaleDescInx); wListSetIndex(gaugeL, layerGaugeInx); } /* Sync Scale and lists */ GetScaleGauge(layerScaleInx, &layerScaleDescInx, &layerGaugeInx); /* force update of the 'manage layers' dialogbox */ if (layerL) { wListSetIndex(layerL, layer); ParamLoadControls(&layerPG); } if (layerS) { if (!LoadFileListLoad(settingsCatalog, settingsName)) { layers[layer].settingsName[0] = '\0'; } } ParamControlActive( &layerPG, I_DELETE, (layerSelected > 0) ? TRUE : FALSE); ParamControlActive( &layerPG, I_COUNT, FALSE ); ParamControlActive( &layerPG, I_SCALE, !layerInherit); ParamControlActive( &layerPG, I_GAUGE, !layerInherit); ParamControlActive( &layerPG, I_MINRADIUSENTRY, !layerInherit); ParamControlActive( &layerPG, I_MAXGRADEENTRY, !layerInherit); ParamControlActive( &layerPG, I_TIELEN, !layerInherit); ParamControlActive( &layerPG, I_TIEWID, !layerInherit); ParamControlActive( &layerPG, I_TIESPC, !layerInherit); /* finally show the layer buttons with balloon text */ for (inx = 0; inx < NUM_BUTTONS; inx++) { if (!layers[inx].button_off) { wButtonSetBusy(layer_btns[inx], layers[inx].visible != 0); wControlSetBalloonText((wControl_p)layer_btns[inx], (layers[inx].name[0] != '\0' ? layers[inx].name : _("Show/Hide Layer"))); } } } /** * Fill a layer dropbox with the current layer settings * * \param listLayers the dropbox * \return */ void FillLayerList( wList_p listLayers) { wListClear(listLayers); // Rebuild list on each invocation for (int inx = 0; inx < NUM_LAYERS; inx++) { char *layerFormattedName; layerFormattedName = FormatLayerName(inx); wListAddValue((wList_p)listLayers, layerFormattedName, NULL, I2VP(inx)); free(layerFormattedName); } /* set current layer to selected */ wListSetIndex(listLayers, curLayer); ParamControlActive( &layerPG, I_DELETE, (curLayer > 0) ? TRUE : FALSE); if ( layerInherit ) { ParamControlActive( &layerPG, I_TIELEN, FALSE); ParamControlActive( &layerPG, I_TIEWID, FALSE); ParamControlActive( &layerPG, I_TIESPC, FALSE); } } /** * Initialize the layer lists. * * \param IN pointer to function that actually initialize tha data structures * \param IN current layer (0...NUM_LAYERS), (-1) for no change */ static void InitializeLayers(void LayerInitFunc(void), int newCurrLayer) { /* reset the data structures to default valuses */ LayerInitFunc(); /* count the objects on each layer */ LayerSetCounts(); /* Switch the current layer when requested or the first above not frozen*/ if (newCurrLayer != -1) { curLayer = -1; for (int i = newCurrLayer; i < NUM_LAYERS; i++) { if (!layers[i].frozen) { curLayer = i; break; } } if (curLayer == -1) { ErrorMessage( MSG_NO_EMPTY_LAYER ); layers[0].frozen = FALSE; curLayer = 0; } } } /** * Save an integer to Prefs */ static void layerSetInteger( unsigned int inx, char prefName[], int value ) { char buffer[80]; char name[80]; strcpy(name, prefName); strcat(name, ".%0u"); sprintf( buffer, name, inx ); wPrefSetInteger( LAYERPREF_SECTION, buffer, value ); } /** * Save a float to Prefs */ static void layerSetFloat( unsigned int inx, char prefName[], double value ) { char buffer[80]; char name[20]; strcpy(name, prefName); strcat(name, ".%0u"); sprintf( buffer, name, inx ); wPrefSetFloat( LAYERPREF_SECTION, buffer, value ); } /** * Save the customized layer information to preferences. */ static void LayerPrefSave(void) { unsigned int inx; int flags; char buffer[ 80 ]; char links[STR_LONG_SIZE]; char layersSaved[ 3 * NUM_LAYERS + 1 ]; /* 0..99 plus separator */ /* FIXME: values for layers that are configured to default now should be overwritten in the settings */ layersSaved[ 0 ] = '\0'; for (inx = 0; inx < NUM_LAYERS; inx++) { /* if a name is set that is not the default value or a color different from the default has been set, information about the layer needs to be saved */ if (inx == 0 || !IsLayerDefault(inx)) { sprintf(buffer, LAYERPREF_NAME ".%0u", inx); wPrefSetString(LAYERPREF_SECTION, buffer, layers[inx].name); layerSetInteger(inx, LAYERPREF_COLOR, wDrawGetRGB(layers[inx].color)); flags = 0; if (layers[inx].frozen) { flags |= LAYERPREF_FROZEN; } if (layers[inx].onMap) { flags |= LAYERPREF_ONMAP; } if (layers[inx].visible) { flags |= LAYERPREF_VISIBLE; } if (layers[inx].module) { flags |= LAYERPREF_MODULE; } if (layers[inx].button_off) { flags |= LAYERPREF_NOBUTTON; } if (layers[inx].inherit) { flags |= LAYERPREF_DEFAULT; } layerSetInteger(inx, LAYERPREF_FLAGS, flags); layers[inx].scaleInx = GetScaleInx( layers[inx].scaleDescInx, layers[inx].gaugeInx ); layerSetInteger(inx, LAYERPREF_SCALEINX, layers[inx].scaleInx); layerSetInteger(inx, LAYERPREF_SCLDESCINX, layers[inx].scaleDescInx); layerSetInteger(inx, LAYERPREF_GAUGEINX, layers[inx].gaugeInx); layerSetFloat(inx, LAYERPREF_MINRADIUS, layers[inx].minTrackRadius); layerSetFloat(inx, LAYERPREF_MAXGRADE, layers[inx].maxTrackGrade); layerSetFloat(inx, LAYERPREF_TIELENGTH, layers[inx].tieData.length); layerSetFloat(inx, LAYERPREF_TIEWIDTH, layers[inx].tieData.width); layerSetFloat(inx, LAYERPREF_TIESPACING, layers[inx].tieData.spacing); if (layers[inx].layerLinkList.cnt > 0) { sprintf(buffer, LAYERPREF_LIST ".%0u", inx); GetLayerLinkString(inx, links); wPrefSetString(LAYERPREF_SECTION, buffer, links); if (settingsName[0] && strcmp(settingsName, " ") != 0) { sprintf(buffer, LAYERPREF_SETTINGS ".%0u", inx); wPrefSetString(LAYERPREF_SECTION, buffer, layers[inx].settingsName); } } /* extend the list of layers that are set up via the preferences */ if (layersSaved[ 0 ]) { strcat(layersSaved, ","); } sprintf(buffer, "%u", inx); strcat(layersSaved, buffer); } } wPrefSetString(LAYERPREF_SECTION, "layers", layersSaved); } /** * Load an integer from Prefs */ static void layerGetInteger( unsigned int inx, char prefName[], long *value, int deflt ) { char buffer[80]; char name[80]; strcpy(name, prefName); strcat(name, ".%0u"); sprintf( buffer, name, inx ); wPrefGetInteger( LAYERPREF_SECTION, buffer, value, deflt ); } /** * Load a float from Prefs */ static void layerGetFloat( unsigned int inx, char prefName[], double *value, double deflt ) { char buffer[80]; char name[20]; strcpy(name, prefName); strcat(name, ".%0u"); sprintf( buffer, name, inx ); wPrefGetFloat( LAYERPREF_SECTION, buffer, value, deflt ); } /** * Load the settings for all layers from the preferences. */ static void LayerPrefLoad(void) { const char *prefString; long rgb; long flags; /* reset layer preferences to system default */ LayerAllDefaults(); prefString = wPrefGetString(LAYERPREF_SECTION, "layers"); if (prefString && prefString[ 0 ]) { char layersSaved[3 * NUM_LAYERS]; strncpy(layersSaved, prefString, sizeof(layersSaved)); prefString = strtok(layersSaved, ","); while (prefString) { int inx; char layerOption[20]; const char *layerValue; char listValue[STR_LONG_SIZE]; int color; inx = atoi(prefString); sprintf(layerOption, LAYERPREF_NAME ".%d", inx); layerValue = wPrefGetString(LAYERPREF_SECTION, layerOption); if (layerValue) { strcpy(layers[inx].name, layerValue); } else { *(layers[inx].name) = '\0'; } /* get and set the color, using the system default color in case color is not available from prefs */ layerGetInteger(inx, LAYERPREF_COLOR, &rgb, layerColorTab[inx % COUNT(layerColorTab)]); color = wDrawFindColor(rgb); SetLayerColor(inx, color); /* get and set the flags */ layerGetInteger(inx, LAYERPREF_FLAGS, &flags, LAYERPREF_ONMAP | LAYERPREF_VISIBLE); layers[inx].frozen = ((flags & LAYERPREF_FROZEN) != 0); layers[inx].onMap = ((flags & LAYERPREF_ONMAP) != 0); layers[inx].visible = ((flags & LAYERPREF_VISIBLE) != 0); layers[inx].module = ((flags & LAYERPREF_MODULE) != 0); layers[inx].button_off = ((flags & LAYERPREF_NOBUTTON) != 0); layers[inx].inherit = ((flags & LAYERPREF_DEFAULT) != 0); layerGetInteger(inx, LAYERPREF_SCALEINX, &layers[inx].scaleInx, GetLayoutCurScale()); layerGetInteger(inx, LAYERPREF_SCLDESCINX, &layers[inx].scaleDescInx, GetLayoutCurScaleDesc()); layerGetInteger(inx, LAYERPREF_GAUGEINX, &layers[inx].gaugeInx, 0); layerGetFloat(inx, LAYERPREF_MINRADIUS, &layers[inx].minTrackRadius, GetLayoutMinTrackRadius()); layerGetFloat(inx, LAYERPREF_MAXGRADE, &layers[inx].maxTrackGrade, GetLayoutMaxTrackGrade()); layerGetFloat(inx, LAYERPREF_TIELENGTH, &layers[inx].tieData.length, 0.0); layerGetFloat(inx, LAYERPREF_TIEWIDTH, &layers[inx].tieData.width, 0.0); layerGetFloat(inx, LAYERPREF_TIESPACING, &layers[inx].tieData.spacing, 0.0); sprintf(layerOption, LAYERPREF_LIST ".%d", inx); layerValue = wPrefGetString(LAYERPREF_SECTION, layerOption); if (layerValue) { strcpy(listValue, layerValue); PutLayerListArray(inx, listValue); } else { listValue[0] = '\0'; PutLayerListArray(inx, listValue); } sprintf(layerOption, LAYERPREF_SETTINGS ".%d", inx); layerValue = wPrefGetString(LAYERPREF_SECTION, layerOption); if (layerValue) { strcpy(layers[inx].settingsName, layerValue); } else { layers[inx].settingsName[0] = '\0'; } prefString = strtok(NULL, ","); } } //Make sure curLayer not frozen for (int i = curLayer; i < NUM_LAYERS; i++) { if (!layers[i].frozen) { curLayer = i; break; } } if (layers[curLayer].frozen) { ErrorMessage( MSG_NO_EMPTY_LAYER ); layers[0].frozen = FALSE; curLayer = 0; } } /** * Increment the count of objects on a given layer. * * \param index IN the layer to change */ void IncrementLayerObjects(unsigned int layer) { CHECK(layer <= NUM_LAYERS); layers[layer].objCount++; } /** * Decrement the count of objects on a given layer. * * \param index IN the layer to change */ void DecrementLayerObjects(unsigned int layer) { CHECK(layer <= NUM_LAYERS); layers[layer].objCount--; } /** * Count the number of objects on each layer and store result in layers data structure. */ void LayerSetCounts(void) { int inx; track_p trk; for (inx = 0; inx < NUM_LAYERS; inx++) { layers[inx].objCount = 0; } for (trk = NULL; TrackIterate(&trk);) { inx = GetTrkLayer(trk); if (inx >= 0 && inx < NUM_LAYERS) { layers[inx].objCount++; } } } int FindUnusedLayer(unsigned int start) { int inx; for (inx = start; inx < NUM_LAYERS; inx++) { if (layers[inx].objCount == 0 && !layers[inx].frozen) { return inx; } } ErrorMessage( MSG_NO_EMPTY_LAYER ); return -1; } /** * Reset layer options to their default values. The default values are loaded * from the preferences file. */ void DefaultLayerProperties(void) { InitializeLayers(LayerPrefLoad, 0); UpdateLayerDlg(curLayer); //Use Current Layer if (layoutLayerChanged) { MainProc(mainW, wResize_e, NULL, NULL); layoutLayerChanged = FALSE; } } /** * Update all UI elements after selecting a layer. * */ static void LayerUpdate(void) { BOOL_T redraw; char *layerFormattedName; ParamLoadData(&layerPG); if (!IsLayerValid(layerSelected)) { return; } if (layerSelected == curLayer && layerFrozen) { NoticeMessage(MSG_LAYER_FREEZE, _("Ok"), NULL); layerFrozen = FALSE; ParamLoadControl(&layerPG, I_FRZ); } if (layerSelected == curLayer && !layerVisible) { NoticeMessage(MSG_LAYER_HIDE, _("Ok"), NULL); layerVisible = TRUE; ParamLoadControl(&layerPG, I_VIS); } if (layerSelected == curLayer && layerModule) { NoticeMessage(MSG_LAYER_MODULE, _("Ok"), NULL); layerModule = FALSE; ParamLoadControl(&layerPG, I_MOD); } char oldLinkList[STR_LONG_SIZE]; GetLayerLinkString((int)layerSelected, oldLinkList); if (strcmp(layers[(int)layerSelected].name, layerName) || layerColor != layers[(int)layerSelected].color || layers[(int)layerSelected].useColor != (BOOL_T)layerUseColor || layers[(int)layerSelected].visible != (BOOL_T)layerVisible || layers[(int)layerSelected].frozen != (BOOL_T)layerFrozen || layers[(int)layerSelected].onMap != (BOOL_T)layerOnMap || layers[(int)layerSelected].module != (BOOL_T)layerModule || layers[(int)layerSelected].button_off != (BOOL_T)layerNoButton || layers[(int)layerSelected].inherit != (BOOL_T)layerInherit || layers[(int)layerSelected].scaleInx != layerScaleInx || layers[(int)layerSelected].scaleDescInx != layerScaleDescInx || layers[(int)layerSelected].gaugeInx != layerGaugeInx || layers[(int)layerSelected].minTrackRadius != layerMinRadius || layers[(int)layerSelected].maxTrackGrade != layerMaxGrade || layers[(int)layerSelected].tieData.length != layerTieData.length || layers[(int)layerSelected].tieData.width != layerTieData.width || layers[(int)layerSelected].tieData.spacing != layerTieData.spacing || strcmp(layers[(int)layerSelected].settingsName, settingsName) || strcmp(oldLinkList, layerLinkList)) { SetFileChanged(); } if (layerL) { strncpy(layers[(int)layerSelected].name, layerName, sizeof layers[(int)layerSelected].name); layerFormattedName = FormatLayerName(layerSelected); wListSetValues(layerL, layerSelected, layerFormattedName, NULL, NULL); free(layerFormattedName); } layerFormattedName = FormatLayerName(layerSelected); wListSetValues(setLayerL, layerSelected, layerFormattedName, NULL, NULL); free(layerFormattedName); if (layerSelected < NUM_BUTTONS && !layers[(int)layerSelected].button_off) { if (strlen(layers[(int)layerSelected].name) > 0) { wControlSetBalloonText((wControl_p)layer_btns[(int)layerSelected], layers[(int)layerSelected].name); } else { wControlSetBalloonText((wControl_p)layer_btns[(int)layerSelected], _("Show/Hide Layer")); } } redraw = (layerColor != layers[(int)layerSelected].color || layers[(int)layerSelected].useColor != (BOOL_T)layerUseColor || (BOOL_T)layerVisible != layers[(int)layerSelected].visible); SetLayerColor(layerSelected, layerColor); if (layerSelected < NUM_BUTTONS && layers[(int)layerSelected].visible != (BOOL_T)layerVisible && !layers[(int)layerSelected].button_off) { wButtonSetBusy(layer_btns[(int)layerSelected], layerVisible); } layers[(int)layerSelected].useColor = (BOOL_T)layerUseColor; if (layers[(int)layerSelected].visible != (BOOL_T)layerVisible) { FlipLayer(I2VP(layerSelected)); } layers[(int)layerSelected].visible = (BOOL_T)layerVisible; layers[(int)layerSelected].frozen = (BOOL_T)layerFrozen; if (layers[(int)layerSelected].frozen) { DeselectLayer(layerSelected); } layers[(int)layerSelected].onMap = (BOOL_T)layerOnMap; layers[(int)layerSelected].scaleDescInx = layerScaleDescInx; layers[(int)layerSelected].gaugeInx = layerGaugeInx; layers[(int)layerSelected].scaleInx = GetScaleInx( layerScaleDescInx, layerGaugeInx ); layers[(int)layerSelected].minTrackRadius = layerMinRadius; layers[(int)layerSelected].maxTrackGrade = layerMaxGrade; layers[(int)layerSelected].tieData = layerTieData; layers[(int)layerSelected].module = (BOOL_T)layerModule; layers[(int)layerSelected].inherit = (BOOL_T)layerInherit; strcpy(layers[(int)layerSelected].settingsName, settingsName); PutLayerListArray((int)layerSelected, layerLinkList); SetLayerHideButton(layerSelected, layerNoButton); MainProc( mainW, wResize_e, NULL, NULL ); if (layerRedrawMap) { DoRedraw(); } else if (redraw) { RedrawLayer(layerSelected, TRUE); } layerRedrawMap = FALSE; } static void LayerSelect( wIndex_t inx) { LayerUpdate(); if (inx < 0 || inx >= NUM_LAYERS) { return; } layerSelected = (unsigned int)inx; strcpy(layerName, layers[inx].name); strcpy(settingsName, layers[inx].settingsName); layerVisible = layers[inx].visible; layerFrozen = layers[inx].frozen; layerOnMap = layers[inx].onMap; layerModule = layers[inx].module; layerColor = layers[inx].color; layerUseColor = layers[inx].useColor; layerNoButton = layers[inx].button_off; layerInherit = layers[inx].inherit; layerScaleInx = layers[inx].scaleInx; layerScaleDescInx = layers[inx].scaleDescInx; layerGaugeInx = layers[inx].gaugeInx; layerMinRadius = layers[inx].minTrackRadius; layerMaxGrade = layers[inx].maxTrackGrade; layerTieData.valid = layers[inx].tieData.valid; layerTieData.length = layers[inx].tieData.length; layerTieData.width = layers[inx].tieData.width; layerTieData.spacing = layers[inx].tieData.spacing; layerObjectCount = layers[inx].objCount; GetLayerLinkString(inx, layerLinkList); // sprintf(message, "%ld", layers[inx].objCount); // ParamLoadMessage(&layerPG, I_COUNT, message); ParamLoadControls(&layerPG); ParamControlActive( &layerPG, I_DELETE, (layerSelected > 0) ? TRUE : FALSE); ParamControlActive( &layerPG, I_SCALE, !layerInherit); ParamControlActive( &layerPG, I_GAUGE, !layerInherit); ParamControlActive( &layerPG, I_MINRADIUSENTRY, !layerInherit); ParamControlActive( &layerPG, I_MAXGRADEENTRY, !layerInherit); ParamControlActive( &layerPG, I_TIELEN, !layerInherit); ParamControlActive( &layerPG, I_TIEWID, !layerInherit); ParamControlActive( &layerPG, I_TIESPC, !layerInherit); if (layerS) { if (!LoadFileListLoad(settingsCatalog, settingsName)) { settingsName[0] = '\0'; layers[inx].settingsName[0] = '\0'; } } } void ResetLayers(void) { int inx; for (inx = 0; inx < NUM_LAYERS; inx++) { strcpy(layers[inx].name, inx == 0 ? _("Main") : ""); layers[inx].visible = TRUE; layers[inx].frozen = FALSE; layers[inx].onMap = TRUE; layers[inx].module = FALSE; layers[inx].button_off = FALSE; layers[inx].inherit = TRUE; layers[inx].objCount = 0; strcpy(layers[inx].settingsName, ""); DYNARR_RESET(int, layers[inx].layerLinkList); SetLayerColor(inx, layerColorTab[inx % COUNT(layerColorTab)]); if (inx < NUM_BUTTONS) { wButtonSetLabel(layer_btns[inx], (char*)show_layer_bmps[inx]); } } wControlSetBalloonText((wControl_p)layer_btns[0], _("Main")); for (inx = 1; inx < NUM_BUTTONS; inx++) { wControlSetBalloonText((wControl_p)layer_btns[inx], _("Show/Hide Layer")); } curLayer = -1; for (int i = 0; i < NUM_LAYERS; i++) { if (!layers[i].frozen) { curLayer = i; break; } } if (curLayer == -1) { ErrorMessage( MSG_NO_EMPTY_LAYER ); layers[0].frozen = FALSE; curLayer = 0; } layerVisible = TRUE; layerFrozen = FALSE; layerOnMap = TRUE; layerModule = FALSE; layerInherit = FALSE; layerColor = layers[0].color; layerUseColor = TRUE; strcpy(layerName, layers[0].name); strcpy(settingsName, layers[0].settingsName); LoadLayerLists(); if (layerL) { ParamLoadControls(&layerPG); // ParamLoadMessage(&layerPG, I_COUNT, "0"); } } void SaveLayers(void) { layers_save = malloc(NUM_LAYERS * sizeof(layers[0])); CHECK(layers_save != NULL); for (int i = 0; i < NUM_LAYERS; i++) { layers[i].settingsName[0] = '\0'; } memcpy(layers_save, layers, NUM_LAYERS * sizeof layers[0]); ResetLayers(); } void RestoreLayers(void) { int inx; char * label; wDrawColor color; CHECK(layers_save != NULL); memcpy(layers, layers_save, NUM_LAYERS * sizeof layers[0]); free(layers_save); for (inx = 0; inx < NUM_BUTTONS; inx++) { color = layers[inx].color; layers[inx].color = -1; SetLayerColor(inx, color); if (layers[inx].name[0] == '\0') { if (inx == 0) { label = _("Main"); } else { label = _("Show/Hide Layer"); } } else { label = layers[inx].name; } wControlSetBalloonText((wControl_p)layer_btns[inx], label); } if (layerL) { ParamLoadControls(&layerPG); //ParamLoadMessage(&layerPG, I_COUNT, "0"); } LoadLayerLists(); } /** * Scan opened directory for the next settings file * * \param dir IN opened directory handle * \param dirName IN name of directory * \param fileName OUT fully qualified filename * * \return TRUE if file found, FALSE if not */ static bool GetNextSettingsFile(DIR *dir, const char *dirName, char **fileName) { bool done = false; bool res = false; /* * get all files from the directory */ while (!done) { struct stat fileState; struct dirent *ent; ent = readdir(dir); if (ent) { if (!XtcStricmp(FindFileExtension(ent->d_name), "xset")) { /* create full file name and get the state for that file */ MakeFullpath(fileName, dirName, ent->d_name, NULL); if (stat(*fileName, &fileState) == -1) { fprintf(stderr, "Error getting file state for %s\n", *fileName); continue; } /* ignore any directories */ if (!(fileState.st_mode & S_IFDIR)) { done = true; res = true; } } } else { done = true; res = false; } } return (res); } /* * Get all the settings files in the working directory */ static CatalogEntry * ScanSettingsDirectory(Catalog *catalog, const char *dirName) { DIR *d; CatalogEntry *newEntry = catalog->head; char contents[STR_SHORT_SIZE]; d = opendir(dirName); if (d) { char *fileName = NULL; while (GetNextSettingsFile(d, dirName, &fileName)) { char *contents_start = strrchr(fileName, PATH_SEPARATOR[0]); if (contents_start[0] == '/') { contents_start++; } char *contents_end = strchr(contents_start, '.'); if (contents_end[0] == '.') { contents_end[0] = '\0'; } strcpy(contents, contents_start); contents_end[0] = '.'; newEntry = InsertInOrder(catalog, contents, NULL); UpdateCatalogEntry(newEntry, fileName, contents, NULL); free(fileName); fileName = NULL; } closedir(d); } return (newEntry); } /***************************************************************************** * * FILE READ/WRITE * */ BOOL_T ReadLayers(char * line) { char *name, *layerLinkList, *layerSettingsName, *extra; int inx, visible, frozen, color, onMap, sclInx, module, dontUseColor, ColorFlags, button_off, inherit; double minRad, maxGrd, tieLen, tieWid, tieSpc; unsigned long rgb; /* older files didn't support layers */ if (paramVersion < 7) { return TRUE; } /* set the current layer */ if (strncmp(line, "CURRENT", 7) == 0) { curLayer = atoi(line + 7); if (!IsLayerValid(curLayer)) { curLayer = 0; } if (layers[curLayer].frozen) { ErrorMessage( MSG_NOT_UNFROZEN_LAYER ); layers[curLayer].frozen = FALSE; } if (layerL) { wListSetIndex(layerL, curLayer); } if (setLayerL) { wListSetIndex(setLayerL, curLayer); } return TRUE; } if (strncmp(line, "LINK", 4) == 0) { if (!GetArgs(line + 4, "dq", &inx, &layerLinkList)) { return FALSE; } PutLayerListArray(inx, layerLinkList); return TRUE; } if (strncmp(line, "SET", 3) == 0) { if (!GetArgs(line + 3, "dq", &inx, &layerSettingsName)) { return FALSE; } strcpy(layers[inx].settingsName, layerSettingsName); return TRUE; } /* get the properties for a layer from the file and update the layer accordingly */ /* No Scale/tie data version */ if (!GetArgs(line, "dddduddddqc", &inx, &visible, &frozen, &onMap, &rgb, &module, &dontUseColor, &ColorFlags, &button_off, &name, &extra)) { return FALSE; } /* Check for old version: name here */ if (extra && strlen(extra) > 0) { /* tie data version */ if (!GetArgs(extra, "dufffff", &inherit, &sclInx, &minRad, &maxGrd, &tieLen, &tieWid, &tieSpc)) { return FALSE; } } else { sclInx = GetLayoutCurScale(); inherit = TRUE; minRad = 0.0; maxGrd = 0.0; tieLen = 0.0; tieWid = 0.0; tieSpc = 0.0; } // Provide defaults if ( minRad < EPSILON ) { minRad = GetScaleMinRadius(sclInx); } if (paramVersion < 9) { if ((int)rgb < COUNT( oldColorMap ) ) { rgb = wRGB(oldColorMap[(int)rgb][0], oldColorMap[(int)rgb][1], oldColorMap[(int)rgb][2]); } else { rgb = 0; } } if (inx < 0 || inx >= NUM_LAYERS) { return FALSE; } tieData_t td = {TRUE, tieLen, tieWid, tieSpc}; ValidateTieData(&td); if ( !td.valid ) { td = GetScaleTieData(sclInx); } color = wDrawFindColor(rgb); SetLayerColor(inx, color); strncpy(layers[inx].name, name, sizeof layers[inx].name); layers[inx].visible = visible; layers[inx].frozen = frozen; layers[inx].onMap = onMap; layers[inx].scaleInx = sclInx; layers[inx].minTrackRadius = minRad; layers[inx].maxTrackGrade = maxGrd; layers[inx].tieData = td; layers[inx].module = module; layers[inx].color = color; layers[inx].useColor = !dontUseColor; layers[inx].button_off = button_off; layers[inx].inherit = inherit; GetScaleGauge(sclInx, &layers[inx].scaleDescInx, &layers[inx].gaugeInx); colorTrack = ( ColorFlags & 1 ) ? 1 : 0; //Make sure globals are set colorDraw = ( ColorFlags & 2 ) ? 1 : 0; if (inx < NUM_BUTTONS && !layers[inx].button_off) { if (strlen(name) > 0) { wControlSetBalloonText((wControl_p)layer_btns[(int)inx], layers[inx].name); } wButtonSetBusy(layer_btns[(int)inx], visible); } MyFree(name); // The last layer will set this correctly maxLayer = inx; return TRUE; } /** * Find out whether layer information should be saved to the layout file. * Usually only layers where settings are off from the default are written. * NOTE: as a fix for a problem with XTrkCadReader a layer definition is * written for each layer that is used. * * \param layerNumber IN index of the layer * \return TRUE if configured, FALSE if not */ BOOL_T IsLayerConfigured(unsigned int layerNumber) { return (layers[layerNumber].name[0] || !layers[layerNumber].visible || layers[layerNumber].frozen || !layers[layerNumber].onMap || layers[layerNumber].module || layers[layerNumber].button_off || layers[layerNumber].color != layerColorTab[layerNumber % (COUNT( layerColorTab))] || layers[layerNumber].layerLinkList.cnt > 0 || layers[layerNumber].objCount); } /** * Save the layer information to the file. * * \paran f IN open file handle * \return always TRUE */ BOOL_T WriteLayers(FILE * f) { unsigned int inx; int ColorFlags = 0; if (colorTrack) { ColorFlags |= 1; } if (colorDraw) { ColorFlags |= 2; } for (inx = 0; inx < NUM_LAYERS; inx++) { if (IsLayerConfigured(inx)) { fprintf(f, "LAYERS %u %d %d %d %ld %d %d %d %d \"%s\" %d %lu %.6f %.6f %.6f %.6f %.6f\n", inx, layers[inx].visible, layers[inx].frozen, layers[inx].onMap, wDrawGetRGB(layers[inx].color), layers[inx].module, layers[inx].useColor ? 0 : 1, ColorFlags, layers[inx].button_off, PutTitle(layers[inx].name), layers[inx].inherit, layers[inx].scaleInx, layers[inx].minTrackRadius, layers[inx].maxTrackGrade, layers[inx].tieData.length, layers[inx].tieData.width, layers[inx].tieData.spacing ); } } fprintf(f, "LAYERS CURRENT %u\n", curLayer); for (inx = 0; inx < NUM_LAYERS; inx++) { unsigned int layerInx = inx; GetLayerLinkString(inx, layerLinkList); if (IsLayerConfigured(inx) && strlen(layerLinkList) > 0) { fprintf(f, "LAYERS LINK %u \"%s\"\n", layerInx, layerLinkList); } if (IsLayerConfigured(inx) && layers[inx].settingsName[0]) { fprintf(f, "LAYERS SET %u \"%s\"\n", layerInx, layers[inx].settingsName); } } return TRUE; } /***************************************************************************** * * DIALOG & MENU * */ /** * This function is called when the Done button on the layer dialog is pressed. It hides the layer dialog and * updates the layer information. * * \param IN ignored * */ static void LayerOk(void * unused) { LayerSelect(layerSelected); if (newLayerCount != layerCount) { layoutLayerChanged = TRUE; if (newLayerCount > NUM_BUTTONS) { newLayerCount = NUM_BUTTONS; } layerCount = newLayerCount; } if (layoutLayerChanged) { MainProc(mainW, wResize_e, NULL, NULL); } wHide(layerW); } static void LayerDlgUpdate( paramGroup_p pg, int inx, void * valueP) { switch (inx) { case I_LIST: LayerSelect((wIndex_t) * (long*)valueP); break; case I_NAME: LayerUpdate(); break; case I_MAP: layerRedrawMap = TRUE; /* No Break */ case I_VIS: case I_FRZ: case I_MOD: case I_BUT: case I_DEF: LayerUpdate(); UpdateLayerDlg(layerSelected); break; case I_SCALE: LoadGaugeList((wList_p)layerPLs[I_GAUGE].control, *((int *)valueP)); // set the first entry as default, usually the standard gauge for a scale wListSetIndex((wList_p)layerPLs[I_GAUGE].control, 0); break; case I_TIELEN: case I_TIEWID: case I_TIESPC: ValidateTieData(&layerTieData); r_tieData.rangechecks = layerTieData.valid ? PDO_NORANGECHECK_LOW | PDO_NORANGECHECK_HIGH : 0; break; case I_SETTINGS: if (strcmp((char*)wListGetItemContext(settingsListL, (wIndex_t) * (long*)valueP), " ") == 0) { settingsName[0] = '\0'; } else { strcpy(settingsName, (char*)wListGetItemContext(settingsListL, (wIndex_t) * (long*)valueP)); } break; } } static void DoLayer(void * unused) { if (layerW == NULL) { layerW = ParamCreateDialog(&layerPG, MakeWindowTitle(_("Layers")), _("Done"), LayerOk, wHide, TRUE, NULL, 0, LayerDlgUpdate); GetScaleGauge(layerScaleInx, &layerScaleDescInx, &layerGaugeInx); LoadScaleList(scaleL); LoadGaugeList(gaugeL, layerScaleDescInx); } if (settingsCatalog) { CatalogDiscard(settingsCatalog); } else { settingsCatalog = InitCatalog(); } ScanSettingsDirectory(settingsCatalog, wGetAppWorkDir()); /* set the globals to the values for the current layer */ UpdateLayerDlg(curLayer); layerRedrawMap = FALSE; wShow(layerW); layoutLayerChanged = FALSE; } #include "bitmaps/background.xpm3" #if NUM_BUTTONS < 100 static int lbmap_width[3] = { 16, 24, 32 }; // For numbers < 100 #else static int lbmap_width[3] = { 20, 28, 36 }; // For numbers > 99 #endif static int lbmap_height[3] = { 16, 24, 32 }; static int lbit0_width[3] = { 6, 10, 14 }; static int lbit1_width[3] = { 4, 5, 6 }; static int lbits_top[3] = { 3, 4, 6 }; static int lbits_height[3] = { 10, 15, 20 }; #include "bitmaps/layer_num.inc" static char** show_layer_digits[3][10] = { { n0_x16, n1_x16, n2_x16, n3_x16, n4_x16, n5_x16, n6_x16, n7_x16, n8_x16, n9_x16 }, { n0_x24, n1_x24, n2_x24, n3_x24, n4_x24, n5_x24, n6_x24, n7_x24, n8_x24, n9_x24 }, { n0_x32, n1_x32, n2_x32, n3_x32, n4_x32, n5_x32, n6_x32, n7_x32, n8_x32, n9_x32 } }; /* Note: If the number of buttons is increased to > ~120, you should * also increase COMMAND_MAX and BUTTON_MAX in command.c * NUM_LAYERS is defined in common.h */ #define ONE_PIXEL v *= 2; if (v > 128) { show_layer_bits[xx + yy] = b; xx += 1; v = 1; b = 0; } void InitLayers(void) { unsigned int i; wPrefGetInteger(PREFSECT, "layer-button-count", &layerCount, layerCount); for (i = 0; i < COUNT(layerRawColorTab); i++) { layerColorTab[i] = wDrawFindColor(layerRawColorTab[i]); } /* build the adjust table for starting bit */ int dx_table[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; /* create the bitmaps for the layer buttons */ /* all bitmaps have to have the same dimensions */ for (int i = 0; i < NUM_LAYERS; i++) { int n = i + 1; int bwid = lbmap_width[iconSize]; int wb = (bwid + 7) / 8; // width in bytes int bhgt = lbmap_height[iconSize]; int h = lbits_height[iconSize]; // if (n > 30) n = n + 70; for testing > 100 show_layer_bits = MyMalloc(bhgt * wb); if (n < 10) { // width of char int wc = 0; // width of char if (n == 1) { wc = lbit1_width[iconSize]; } else { wc = lbit0_width[iconSize]; } // X-adjust int dx = (bwid - wc) / 2; int x0 = 0; if (dx > 7) { dx -= 8; x0++; } char** cp = show_layer_digits[iconSize][n]; for (int y = 0; y < h; y++) { int v = dx_table[dx]; // power of two char b = 0; // bits int yy = wb * (y + (bhgt - h) / 2); int xx = x0; // starting byte for (int x = 0; x < wc; x++) { char z = *(*cp + x + y * wc); if (z != ' ') { b |= v; } ONE_PIXEL } if (v <= 128) { show_layer_bits[xx + yy] = b; } } } else if (n < 100) { // width of chars int wc1 = 0; int wc0 = 0; if ((n / 10) == 1) { wc1 = lbit1_width[iconSize]; } else { wc1 = lbit0_width[iconSize]; } if ((n % 10) == 1) { wc0 = lbit1_width[iconSize]; } else { wc0 = lbit0_width[iconSize]; } // X-adjust int dx = (bwid - wc1 - wc0 - (iconSize >= 1 ? 2 : 1)) / 2; int x0 = 0; if (dx > 7) { dx -= 8; x0++; } char** cp1 = show_layer_digits[iconSize][n / 10]; char** cp0 = show_layer_digits[iconSize][n % 10]; for (int y = 0; y < h; y++) { int v = dx_table[dx]; // powers of two char b = 0; // bits int yy = wb * (y + (bhgt - h) / 2); int xx = x0; // starting byte for (int x = 0; x < wc1; x++) { char z = *(*cp1 + x + y * wc1); if (z != ' ') { b |= v; } ONE_PIXEL } ONE_PIXEL if (iconSize >= 1) { ONE_PIXEL } for (int x = 0; x < wc0; x++) { char z = *(*cp0 + x + y * wc0); if (z != ' ') { b |= v; } ONE_PIXEL } if (v <= 128) { show_layer_bits[xx + yy] = b; } } } else { // n >= 100 // width of chars int wc2 = 0; int wc1 = 0; int wc0 = 0; if ((n / 100) == 1) { wc2 = lbit1_width[iconSize]; } else { wc2 = lbit0_width[iconSize]; } if (((n / 10) % 10) == 1) { wc1 = lbit1_width[iconSize]; } else { wc1 = lbit0_width[iconSize]; } if ((n % 10) == 1) { wc0 = lbit1_width[iconSize]; } else { wc0 = lbit0_width[iconSize]; } // X-adjust and start int dx = (bwid - wc2 - wc1 - wc0 - 2) / 2; int x0 = 0; if (dx > 7) { dx -= 8; x0++; } char** cp2 = show_layer_digits[iconSize][n / 100]; char** cp1 = show_layer_digits[iconSize][(n / 10) % 10]; char** cp0 = show_layer_digits[iconSize][n % 10]; for (int y = 0; y < h; y++) { int v = dx_table[dx]; // powers of two char b = 0; // bits int yy = wb * (y + (bhgt - h) / 2); int xx = x0; // byte for (int x = 0; x < wc2; x++) { char z = *(*cp2 + x + y * wc2); if (z != ' ') { b |= v; } ONE_PIXEL } ONE_PIXEL for (int x = 0; x < wc1; x++) { char z = *(*cp1 + x + y * wc1); if (z != ' ') { b |= v; } ONE_PIXEL } ONE_PIXEL for (int x = 0; x < wc0; x++) { char z = *(*cp0 + x + y * wc0); if (z != ' ') { b |= v; } ONE_PIXEL } if (v <= 128) { show_layer_bits[xx + yy] = b; } } } show_layer_bmps[i] = wIconCreateBitMap( bwid, bhgt, show_layer_bits, layerColorTab[i % (COUNT(layerColorTab))]); layers[i].color = layerColorTab[i % (COUNT(layerColorTab))]; layers[i].useColor = TRUE; MyFree(show_layer_bits); } /* layer list for toolbar */ setLayerL = wDropListCreate(mainW, 0, 0, "cmdLayerSet", NULL, 0, 10, 200, NULL, SetCurrLayer, NULL); wControlSetBalloonText((wControl_p)setLayerL, GetBalloonHelpStr("cmdLayerSet")); AddToolbarControl((wControl_p)setLayerL, IC_MODETRAIN_TOO); backgroundB = AddToolbarButton("cmdBackgroundShow", wIconCreatePixMap(background_xpm3[iconSize]), 0, BackgroundToggleShow, NULL); /* add the help text */ wControlSetBalloonText((wControl_p)backgroundB, _("Show/Hide Background")); wControlActive((wControl_p)backgroundB, FALSE); for (int i = 0; i < NUM_LAYERS; i++) { char *layerName; if (i < NUM_BUTTONS) { /* create the layer button */ sprintf(message, "cmdLayerShow%u", i); layer_btns[i] = AddToolbarButton(message, show_layer_bmps[i], IC_MODETRAIN_TOO, FlipLayer, I2VP(i) ); /* set state of button */ wButtonSetBusy(layer_btns[i], 1); } layerName = FormatLayerName(i); wListAddValue(setLayerL, layerName, NULL, I2VP(i)); free(layerName); } AddPlaybackProc("SETCURRLAYER", PlaybackCurrLayer, NULL); AddPlaybackProc("LAYERS", (playbackProc_p)ReadLayers, NULL); } addButtonCallBack_t InitLayersDialog(void) { ParamRegister(&layerPG); RegisterChangeNotification(LayerChange); return &DoLayer; }