//---------------------------------------------------------------------------
/*
Remote Train Control Program for Windows

© Copyright 2021 by Mark DiVecchio

    This file is part of Remote Train Control.

    Remote Train Control 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 3 of the License, or
    (at your option) any later version.

    Remote Train Control 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 Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

*/
// Home Page : http://www.silogic.com/trains/RTC_Running.html
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Train_Control.h"
#include "Debug_Controls.h"
#include "Setup_Control.h"
#include "SignalX.h"
#include "BlockName_Query.h"
#include "Clipbrd.hpp"
#include "Message_Thread.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "HideButton"
#pragma link "_GClass"
#pragma link "AbLED"
#pragma resource "*.dfm"

TFixedSignalFormX *FixedSignalFormX;

String AspectNames[] = {"Dark", "Stop Signal", "Clear", "Stop and Proceed", "Approach", "Medium Clear",
	"Medium Approach", "Slow Clear", "Slow Approach", "Approach Medium", "Approach Slow",
	"Restricting", "Approach Limited", "Limted Clear", "Limited Approach"};

// Signal Head Aspects 0-x
enum SignalAspect {AsDark = 0, AsStop, AsClear, AsStopandProceed, AsApproach, AsMediumClear, AsMediumApproach,
	AsSlowClear, AsSlowApproach, AsApproachMedium, AsApproachSlow, AsRestricting, AsApproachLimited,
    AsLimitedClear, AsLimitedApproach, AsLast};
//---------------------------------------------------------------------------
__fastcall TFixedSignalFormX::TFixedSignalFormX(TComponent* Owner)
	: TForm(Owner)
{
LocalTransparencyOverride = false;
AutoScroll = true;	// this seems to get lost in dfm file on move to CB10.1
RegFileRootKey =  MainForm->RegFileRootKey;

SignalGrid->ColCount = 10;
SignalGrid->ColWidths[SIGNALNUM] = 50;
SignalGrid->ColWidths[SIGNALCOL] = 30;
SignalGrid->ColWidths[SIGNALROW] = 30;
SignalGrid->ColWidths[SIGNALASPECT] = 30;
SignalGrid->ColWidths[SIGNALNUMLIGHTS] = 30;
SignalGrid->ColWidths[SIGNALNUMBERPLATE] = 30;
SignalGrid->ColWidths[SIGNALNAME] = 80;
SignalGrid->ColWidths[SIGNALCURRENT] = 30;
SignalGrid->ColWidths[SIGNALHOME] = 30;
SignalGrid->ColWidths[SIGNALDISTANT] = 30;
SignalGrid->Width = 395;	// sum of ColWidths + 25 for the scrollbar
SignalGrid->RowCount = SIGNALLIMIT + 1;

// read options from registry if it exist
TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
assert(RegFile);
__try {
    INIFileName = RegFile->ReadString("Signal","InitFile" + String(IntToHex(__TCPLUSPLUS__, 4)), String(MainForm->cStartDir) + "\\Signal.ini");
	Top = RegFile->ReadInteger("Signal", "Top" + String(IntToHex(__TCPLUSPLUS__, 4)), Top);
	Left = RegFile->ReadInteger("Signal", "Left" + String(IntToHex(__TCPLUSPLUS__, 4)), Left);
    // if using multiple monitors and one was removed, pull the window
    // back onto the remaining monitor
    int MC = Screen->MonitorCount;
    if (MC == 1) {
        int Wth = Screen->Monitors[0]->Width;
		if (Left > Wth) Left -= Wth;
        int Hth = Screen->Monitors[0]->Height;
        if (Top > Hth) Top -= Hth;
        }
   	Height = RegFile->ReadInteger("Signal", "Height" + String(IntToHex(__TCPLUSPLUS__, 4)), Height);
	Width = RegFile->ReadInteger("Signal", "Width" + String(IntToHex(__TCPLUSPLUS__, 4)), Width);
    //
	Absolute->Checked = RegFile->ReadInteger("Signal", "Absolute" + String(IntToHex(__TCPLUSPLUS__, 4)), Absolute->Checked);
	ShowText->Checked = RegFile->ReadInteger("Signal", "Text" + String(IntToHex(__TCPLUSPLUS__, 4)), ShowText->Checked);
	SignalGrid->Top = RegFile->ReadInteger("Signal", "GridTop" + String(IntToHex(__TCPLUSPLUS__, 4)), SignalGrid->Top);
	SignalGrid->Left = RegFile->ReadInteger("Signal", "GridLeft" + String(IntToHex(__TCPLUSPLUS__, 4)), SignalGrid->Left);
	}
__finally {
	// Deallocate RegFile
	delete RegFile;
	}

//
if (INIFileName.IsEmpty()) {
    // use cStartDir
	SignalDataFile = String(MainForm->cStartDir) + "\\Signal.ini";
    } else {
    // use INIFileName
    SignalDataFile = INIFileName;
    }
Corrupt = false;
LoadSignalData();

SignalHelp = NULL;

ShowIt();	// make it visible
}
//---------------------------------------------------------------------------

__fastcall TFixedSignalFormX::~TFixedSignalFormX(void)
{
if (SignalHelp) {
	delete SignalHelp;
    SignalHelp = 0;
    }
TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
assert(RegFile);
__try {
    RegFile->WriteString("Signal", "InitFile" + String(IntToHex(__TCPLUSPLUS__, 4)), INIFileName);
    RegFile->WriteInteger("Signal", "Top" + String(IntToHex(__TCPLUSPLUS__, 4)), Top > 0 ? Top : 0);
    RegFile->WriteInteger("Signal", "Height" + String(IntToHex(__TCPLUSPLUS__, 4)), Height);
    RegFile->WriteInteger("Signal", "Left" + String(IntToHex(__TCPLUSPLUS__, 4)), Left > 0 ? Left : 0);
    RegFile->WriteInteger("Signal", "Width" + String(IntToHex(__TCPLUSPLUS__, 4)), Width);
    //
    RegFile->WriteInteger("Signal", "Absolute" + String(IntToHex(__TCPLUSPLUS__, 4)), Absolute->Checked);
    RegFile->WriteInteger("Signal", "Text" + String(IntToHex(__TCPLUSPLUS__, 4)), ShowText->Checked);
    RegFile->WriteInteger("Signal", "GridTop" + String(IntToHex(__TCPLUSPLUS__, 4)), SignalGrid->Top > 0 ? SignalGrid->Top : 0);
    RegFile->WriteInteger("Signal", "GridLeft" + String(IntToHex(__TCPLUSPLUS__, 4)), SignalGrid->Left > 0 ? SignalGrid->Left : 0);
    }
__finally {
    // Deallocate RegFile
    delete RegFile;
    }

if (Corrupt) return;
TStringList * const SignalDat = new TStringList();
assert(SignalDat);		// make sure that construction worked
SignalDat->Clear();
__try {
    try {
        // Save Signal Data to disk with overwrite
        SignalDat->Sorted = false;
        // transfer data from Grid
        for (int SignalNum = 0 ; SignalNum < SignalGrid->RowCount ; SignalNum++) {
            // move it into the SignalDat Object
            SignalDat->Add(SignalGrid->Rows[SignalNum]->CommaText);
            }
        // write it
        SignalDat->SaveToFile(SignalDataFile);
        if (DEBUGGING) DB->Debug_Print("Signal Data Saved to " + SignalDataFile);
        }
        catch (int field) {
            MainForm->DebugMessage("Signal Data Field (" + String(field) + ") is Corrupt - Not Saved : " + SignalDataFile);
			Corrupt = true;
            }
        catch (...) {
            MainForm->DebugMessage("Signal Data is Corrupt - Not Saved : " + SignalDataFile);
			Corrupt = true;
            }
    	}
	__finally {
    delete SignalDat;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::ShowIt()
{
//
SetZOrder(false); 	// put window behind main form
//
Visible = true;		// make the window visible
}
//---------------------------------------------------------------------------
// Workaround for SetLayeredWindowAttributes() to make transparent windows
extern lpfnSetLayeredWindowAttributes m_pSetLayeredWindowAttributes;
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::FormActivate(TObject *Sender)
{
#if __BORLANDC__ >= 0x720      // CB10.1 only
AlphaBlend = false; // Remove Transparency
#else
// Remove WS_EX_LAYERED from this window styles
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) & ~WS_EX_LAYERED);
#endif
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::FormDeactivate(TObject *Sender)
{
if (Setup->TransparentSpin->Value == Setup->TransparentSpin->MaxValue) return;	// Off
if (LocalTransparencyOverride) return;
#if __BORLANDC__ >= 0x720      // CB10.1 only
AlphaBlendValue = (255 * Setup->TransparentSpin->Value) / 100;
AlphaBlend = true;  // Add Transparency
#else
// Set WS_EX_LAYERED on this window
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_LAYERED);
//SetLayeredWindowAttributes
m_pSetLayeredWindowAttributes(Handle, NULL, (255 * Setup->TransparentSpin->Value) / 100, LWA_ALPHA);
#endif
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::FormClick(TObject *Sender)
{
LocalTransparencyOverride = !LocalTransparencyOverride;	// Toggle transparency locally
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::HideButton1Click(TObject *Sender)
{
Hide();
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::LoadSignalData(void)
{
TStringList * const SignalDat = new TStringList();
assert(SignalDat);		// make sure that construction worked
SignalDat->Sorted = false;

__try {
   	try {
    	if (FileExists(SignalDataFile)) {
   			// read it
   	    	SignalDat->LoadFromFile(SignalDataFile);
   	    	// transfer data into TStringGrid from the TStringList
            SignalGrid->Rows[SIGNAL_LABEL_ROW]->CommaText = SignalDat->Strings[SIGNAL_LABEL_ROW];
   	    	for (int SignalNum = SIGNAL_TOPROW ; SignalNum < SignalGrid->RowCount ; SignalNum++) {
	    		SignalGrid->Rows[SignalNum]->CommaText = SignalDat->Strings[SignalNum];
                int Aspect = SignalGrid->Cells[SIGNALASPECT][SignalNum].ToInt();	// adjust for 1 based numbering in Lua
                String SignalName = SignalGrid->Cells[SIGNALNAME][SignalNum];
				// BCB4.0 saves as "", CB10.1 as " ". Can't use IsEmpty()
                int col = SignalGrid->Cells[SIGNALCOL][SignalNum].ToInt();
                int row = SignalGrid->Cells[SIGNALROW][SignalNum].ToInt();
                int Lights = SignalGrid->Cells[SIGNALNUMLIGHTS][SignalNum].ToInt();
                int NumPlate = SignalGrid->Cells[SIGNALNUMBERPLATE][SignalNum].ToInt();
                int Current = SignalGrid->Cells[SIGNALCURRENT][SignalNum].ToInt();
                int Home = SignalGrid->Cells[SIGNALHOME][SignalNum].ToInt();
                int Distant = SignalGrid->Cells[SIGNALDISTANT][SignalNum].ToInt();
                // if number of lights on the signal head > 0 then create the signal
				if (Lights) ConstructSignal(SignalNum, col, row, SignalName, Lights, Aspect, NumPlate, Current, Home, Distant);
				}
			if (DEBUGGING) DB->Debug_Print("Signal Data Loaded from " + SignalDataFile);
   	    	} else {
           	// Signal Data Files does not exist so create an empty TStringGrid
            SignalGrid->Cells[SIGNALNUM][0] = "Signal #";			// Index
            SignalGrid->Cells[SIGNALASPECT][0] = "Aspect";			// Color Value
            SignalGrid->Cells[SIGNALNUMLIGHTS][0] = "# Lights";		// Number of lights on the signal head
            SignalGrid->Cells[SIGNALNUMBERPLATE][0] = "Num Plate";	// Number Plate
            SignalGrid->Cells[SIGNALNAME][0] = "Signal Name";		// SignalName
            SignalGrid->Cells[SIGNALCOL][0] = "Col";				// Column
            SignalGrid->Cells[SIGNALROW][0] = "Row";				// Row
            SignalGrid->Cells[SIGNALCURRENT][0] = "Curr";			// Current Block
            SignalGrid->Cells[SIGNALHOME][0] = "Home";              // Home Block #
            SignalGrid->Cells[SIGNALDISTANT][0] = "Dist";             // Distant Block #
			for (int SignalNum = SIGNAL_TOPROW ; SignalNum < SignalGrid->RowCount ; SignalNum++) {
                SignalGrid->Cells[SIGNALNUM][SignalNum] = SignalNum;		// Index
                SignalGrid->Cells[SIGNALASPECT][SignalNum] = 0;				// not visible
                SignalGrid->Cells[SIGNALNUMLIGHTS][SignalNum] = 0;			// Number of lights on the signal head
                SignalGrid->Cells[SIGNALNUMBERPLATE][SignalNum] = 0;		// Number Plate
                SignalGrid->Cells[SIGNALNAME][SignalNum] = " ";				// SignalName
                SignalGrid->Cells[SIGNALCOL][SignalNum] = 0;				// Column
                SignalGrid->Cells[SIGNALROW][SignalNum] = 0;				// Row
                SignalGrid->Cells[SIGNALCURRENT][SignalNum] = 0;			// Current Block #
            	SignalGrid->Cells[SIGNALHOME][SignalNum] = 0;				// Home Block #
            	SignalGrid->Cells[SIGNALDISTANT][SignalNum] = 0;			// Distant Block #
			    }
            if (DEBUGGING) DB->Debug_Print("Signal Data Created (Empty)");
           	}
	   	}
	catch (int field) {
   		MainForm->DebugMessage("Saved Signal Dat File Field (" + String(field) + ") is Corrupt : " + SignalDataFile);
        Corrupt = true;
       	}
    catch ( ... ){
   		MainForm->DebugMessage("Saved Signal Data File is Corrupt : " + SignalDataFile);
        Corrupt = true;
   		}
    }
	__finally {
    delete SignalDat;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::CopyrightClick(TObject *Sender)
{
// Copy the Form to the clipboard.
// In BCB4.0, there is no SetSize method associated with TBitmap
// so we have to use Width and Height separately.
//
// see:
// https://stackoverflow.com/questions/3190777/how-do-i-copy-a-form-as-an-image-to-the-clipboard
//
Graphics::TBitmap * bm;
bm = new Graphics::TBitmap;
try
	{
    #if __BORLANDC__ >= 0x720
	// Defined for CB10.1 C++ programs that use the VCL.
	bm->SetSize(ClientWidth, ClientHeight);
    #else
    bm->Width = ClientWidth;
    bm->Height = ClientHeight;
    #endif
	BitBlt(bm->Canvas->Handle, 0, 0, ClientWidth, ClientHeight, Canvas->Handle, 0, 0, SRCCOPY);
    Clipboard()->Assign(bm);
    }
__finally
	{
	delete bm;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::ConstructSignal(int SignalNo, int Col, int Row, String SignalName, int iLights, int iAspect,
	int NumPlate, int Current, int Home, int Distant)
{
TPanel * pSignal = NULL;
TLED1Panel * Actual1;
TLED2Panel * Actual2;
TLED3Panel * Actual3;
switch(iLights) {
	case Hd1LED:
        pSignal =  new TLED1Panel(this);
        assert(pSignal);
		pSignal->Parent = this;
        //pSignal->OnMouseDown = MouseDownLocal;
		Actual1 = dynamic_cast <TLED1Panel *> (pSignal);
		if (Actual1) {
			Actual1->LEDHighSpeed->Checked = true;
			if (SignalName != NULL) Actual1->SignalName->Caption = SignalName;
			if (NumPlate != 0) {
				Actual1->NumberPlate->Caption = String(NumPlate);
				Actual1->NumberPlate->Visible = true;
				} else {
                if (Absolute->Checked) {
					Actual1->NumberPlate->Caption = "A";
					Actual1->NumberPlate->Visible = true;
                    }
                }
			Lights(pSignal, iAspect);
			}
		break;
	case Hd2LED:
		pSignal =  new TLED2Panel(this);
		assert(pSignal);
		pSignal->Parent = this;
        //pSignal->OnMouseDown = MouseDownLocal;
		Actual2 = dynamic_cast <TLED2Panel *> (pSignal);
		if (Actual2) {
			Actual2->LEDHighSpeed->Checked = true;
			Actual2->LEDMediumSpeed->Checked = true;
			if (SignalName != NULL) Actual2->SignalName->Caption = SignalName;
			if (NumPlate != 0) {
				Actual2->NumberPlate->Caption = String(NumPlate);
				Actual2->NumberPlate->Visible = true;
				} else {
                if (Absolute->Checked) {
					Actual2->NumberPlate->Caption = "A";
					Actual2->NumberPlate->Visible = true;
                    }
                }
			Lights(pSignal, iAspect);
			}
		break;
	case Hd3LED:
		pSignal =  new TLED3Panel(this);
		assert(pSignal);
		pSignal->Parent = this;
        //pSignal->OnMouseDown = MouseDownLocal;
		Actual3 = dynamic_cast <TLED3Panel *> (pSignal);
		if (Actual3) {
			Actual3->LEDHighSpeed->Checked = true;
			Actual3->LEDMediumSpeed->Checked = true;
			Actual3->LEDLowSpeed->Checked = true;
            if (SignalName != NULL) Actual3->SignalName->Caption = SignalName;
            if (NumPlate != 0) {
                Actual3->NumberPlate->Caption = String(NumPlate);
                Actual3->NumberPlate->Visible = true;
                } else {
                if (Absolute->Checked) {
	                Actual3->NumberPlate->Caption = "A";
    	            Actual3->NumberPlate->Visible = true;
                    }
                }
            Lights(pSignal, iAspect);
            }
    	break;
    default:
    	assert(false);
        break;
    }

pSignal->Top = (Row * 125) + 50;
pSignal->Left = (Col * 50) + 10;
pSignal->Name = "SignalHead" + String(SignalNo);
//pSignal->OnClick = ClickLocal;
pSignal->Cursor = crHandPoint;

// save pointer to Signal in Objects
SignalGrid->Objects[SIGNALNUM][SignalNo] = pSignal;
// Signalname is stored here for case of a signal edit
SignalGrid->Cells[SIGNALNAME][SignalNo] = SignalName;	// put the name in the string grid
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::EditGridButtonClick(TObject *Sender)
{
SignalGrid->Visible = !SignalGrid->Visible;
SignalGrid->BringToFront();
if (SignalGrid->Visible) {
	EditGridButton->Hint = "Close the Signal Definitions Grid";
	} else {
	EditGridButton->Hint = "Directly Edit the Signal Definitions";
    }
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::SignalGridKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
assert(KeyPreview);
switch(Key) {
    case VK_UP:
        if (Shift.Contains(ssCtrl)) {
        	SignalGrid->Top -= 20;
	        Key = 0;	// handled
            }
    	return;
    case VK_DOWN:
        if (Shift.Contains(ssCtrl)) {
        	SignalGrid->Top += 20;
    	    Key = 0;	// handled
            }
    	return;
    case VK_LEFT:
        if (Shift.Contains(ssCtrl)) {
        	SignalGrid->Left -= 20;
	        Key = 0;	// handled
            }
    	return;
    case VK_RIGHT:
        if (Shift.Contains(ssCtrl)) {
        	SignalGrid->Left += 20;
	        Key = 0;	// handled
            }
    	return;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::DeleteAllSignals(void)
{
// TBD
//
for (int iSignalNo = SIGNAL_TOPROW ; iSignalNo < SignalGrid->RowCount ; iSignalNo++) {
    // delete the signal head if it exists
    if (SignalGrid->Cells[SIGNALNUMLIGHTS][iSignalNo].ToInt() > 0) {
        TPanel * Hd = dynamic_cast <TPanel *> (SignalGrid->Objects[SIGNALNUM][iSignalNo]);
        assert(Hd);
        delete Hd;
        SignalGrid->Objects[SIGNALNUM][iSignalNo] = NULL;
        SignalGrid->Cells[SIGNALNUM][iSignalNo] = iSignalNo;		// Index
        SignalGrid->Cells[SIGNALASPECT][iSignalNo] = 0;				// not visible
        SignalGrid->Cells[SIGNALNUMLIGHTS][iSignalNo] = 0;			// Number of lights on the signal head
        SignalGrid->Cells[SIGNALNUMBERPLATE][iSignalNo] = 0;		// Number Plate
        SignalGrid->Cells[SIGNALNAME][iSignalNo] = " ";				// SignalName
        SignalGrid->Cells[SIGNALCOL][iSignalNo] = 0;				// Column
        SignalGrid->Cells[SIGNALROW][iSignalNo] = 0;				// Row
        SignalGrid->Cells[SIGNALCURRENT][iSignalNo] = 0;			// Current Block #
      	SignalGrid->Cells[SIGNALHOME][iSignalNo] = 0;				// Home Block #
       	SignalGrid->Cells[SIGNALDISTANT][iSignalNo] = 0;			// Distant Block #
        }
    }
}
//---------------------------------------------------------------------------

String __fastcall TFixedSignalFormX::GetSignalName(int SignalNo, int &iNumberPlate)
{
// return the name and the Number Plate values.
// SignalNo is 1 to SIGNALLIMIT
assert(SignalNo <= SIGNALLIMIT);
int iLights = SignalGrid->Cells[SIGNALNUMLIGHTS][SignalNo].ToInt();
if (iLights > 0) {
	iNumberPlate = SignalGrid->Cells[SIGNALNUMBERPLATE][SignalNo].ToInt();
	return SignalGrid->Cells[SIGNALNAME][SignalNo];
    }
return "**";
}
//---------------------------------------------------------------------------

int __fastcall TFixedSignalFormX::CreateSignal(int iSignalNo, int iCol, int iRow, String sSignalName, int iAspect, int iLights, int iNumberPlate)
{
assert(iSignalNo <= SIGNALLIMIT);
// delete the head if it exists
if (SignalGrid->Cells[SIGNALNUMLIGHTS][iSignalNo].ToInt() > 0) {
    TPanel * Hd = dynamic_cast <TPanel *> (SignalGrid->Objects[SIGNALNUM][iSignalNo]);
    assert(Hd);
    delete Hd;
    SignalGrid->Objects[SIGNALNUM][iSignalNo] = NULL;
    SignalGrid->Cells[SIGNALNUMLIGHTS][iSignalNo] = 0;	// Lights == 0 indicates no signal here
	}
// if number of lights on the signal head is > 0 then create a new signal head
if (iLights > 0) {
	ConstructSignal(iSignalNo, iCol, iRow, sSignalName, iLights, iAspect, iNumberPlate, 0, 0, 0);
    SignalGrid->Cells[SIGNALNUM][iSignalNo] = iSignalNo;			// Index
    SignalGrid->Cells[SIGNALASPECT][iSignalNo] = iAspect;			// Signal Aspect
    SignalGrid->Cells[SIGNALNUMLIGHTS][iSignalNo] = iLights;		// Number of lights on the signal head
    SignalGrid->Cells[SIGNALNUMBERPLATE][iSignalNo] = iNumberPlate;	// Number Plate
    SignalGrid->Cells[SIGNALNAME][iSignalNo] = sSignalName;			// SignalName
    SignalGrid->Cells[SIGNALCOL][iSignalNo] = iCol;				// Column
    SignalGrid->Cells[SIGNALROW][iSignalNo] = iRow;				// Row
    SignalGrid->Cells[SIGNALCURRENT][iSignalNo] = 0;			// Current Block #
    SignalGrid->Cells[SIGNALHOME][iSignalNo] = 0;				// Home Block #
    SignalGrid->Cells[SIGNALDISTANT][iSignalNo] = 0;			// Distant Block #
    }
return 0;
}
//---------------------------------------------------------------------------

int __fastcall TFixedSignalFormX::SetAspect(int SignalNo, int Aspect)
{
// Set the signal aspect
// SignalNo is 1 to SIGNALLIMIT
assert(SignalNo <= SIGNALLIMIT);
//
int iLights = SignalGrid->Cells[SIGNALNUMLIGHTS][SignalNo].ToInt();
if (iLights > 0) {
    TPanel * Hd = dynamic_cast <TPanel *> (SignalGrid->Objects[SIGNALNUM][SignalNo]);
    assert(Hd);
    Lights(Hd, Aspect);
    SignalGrid->Cells[SIGNALASPECT][SignalNo] = Aspect;
    // If this signal is Registered to a Cab Display, the SetAspect code
    // in the PC Thread will take care of reflecting the new aspect
    // into the Cab.    
    return Aspect;
	}
return AsDark;	// no such signal number, indicate dark
}
//---------------------------------------------------------------------------

int __fastcall TFixedSignalFormX::GetAspect(int SignalNo)
{
// return the aspect number
// SignalNo is 1 to SIGNALLIMIT
assert(SignalNo <= SIGNALLIMIT);
int iLights = SignalGrid->Cells[SIGNALNUMLIGHTS][SignalNo].ToInt();
if (iLights > 0) {
	// return the aspect
	return SignalGrid->Cells[SIGNALASPECT][SignalNo].ToInt();
    }
return AsDark;	// no such signal number, indicate dark
}
//---------------------------------------------------------------------------

bool __fastcall TFixedSignalFormX::Lights(TPanel * pHead, int Aspect)
{
if (!pHead) return false;
pHead->Tag = Aspect;	// put the Aspect into the Tag
TLED3Panel * Actual3 = dynamic_cast <TLED3Panel *> (pHead);
if (Actual3) {
    Actual3->LEDHighSpeed->Flashing = false;
    Actual3->LEDMediumSpeed->Flashing = false;
    Actual3->LEDLowSpeed->Flashing = false;
    switch(Aspect) {
        case AsDark:	// Dark
            Actual3->LEDHighSpeed->LED->ColorOn = clBlack;
            Actual3->LEDMediumSpeed->LED->ColorOn = clBlack;
            Actual3->LEDLowSpeed->LED->ColorOn = clBlack;
            Actual3->Hint = AspectNames[AsDark];
            Actual3->LEDHighSpeed->Hint = "Dark";
            break;
        case AsStop:	// Stop - Rule 292 - The most restrictive case is when all 3 lights are red. This indicates that all 3 routes are impassable at this signal.
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
            Actual3->Hint = AspectNames[AsStop];
			Actual3->LEDHighSpeed->Hint = "Stop Signal.";
            break;
        case AsStopandProceed:	// Stop and Proceed - Rule 291 - Stop then Proceed at Restricting Speed.
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the medium speed route is impassable
            Actual3->Hint = AspectNames[AsStopandProceed];
			Actual3->LEDHighSpeed->Hint = "Stop: Then proceed at Restricting Speed.";
            break;
        case AsClear:	// Clear - Rule 281 - the highest speed route is clear for at least two blocks.
            Actual3->LEDHighSpeed->LED->ColorOn = clLime;		// the highest speed route is clear for at least two blocks.
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
            Actual3->Hint = AspectNames[AsClear];
			Actual3->LEDHighSpeed->Hint = "Proceed.";
            break;
        case AsApproach:	// Approach - Rule 285 - the highest speed route is only clear for one block then the top light will be yellow.
            Actual3->LEDHighSpeed->LED->ColorOn = clYellow; 	// the highest speed route is only clear for one block then the top light will be yellow.
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
            Actual3->Hint = AspectNames[AsApproach];
            Actual3->LEDHighSpeed->Hint = "Proceed prepared to stop at next signal. Train exceeding Medium Speed must at once reduce to that speed.";
            break;
        case AsMediumClear:	// Medium Clear - Rule 283 - The same logic is applied to the center, Medium speed, light.
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks.
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
            Actual3->Hint = AspectNames[AsMediumClear];
            Actual3->LEDHighSpeed->Hint = "Proceed: Medium Speed within interlocking limits.";
            break;
        case AsMediumApproach:	// Medium Approach - Rule 286 - The same logic is applied to the center, Medium speed, light.
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clYellow; 	// the medium speed route is only clear for one block then the center light will be yellow.
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
            Actual3->Hint = AspectNames[AsMediumApproach];
            Actual3->LEDHighSpeed->Hint = "Proceed at Medium Speed preparing to stop at next signal.";
            break;
        case AsSlowClear:	// Slow Clear - Rule 287 - And also to the bottom, Slow speed, light
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clLime;		// the low speed route is clear for at least 2 blocks
            Actual3->Hint = AspectNames[AsSlowClear];
            Actual3->LEDHighSpeed->Hint = "Proceed: Slow Speed within interlocking limits.";
            break;
        case AsSlowApproach:	// Slow Approach - Rule 288 - And also to the bottom, Slow speed, light
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->Flashing = true;
            Actual3->LEDLowSpeed->LED->ColorOn = clYellow;		// the low speed route is clear for 1 block but impassable at the next signal.
            Actual3->Hint = AspectNames[AsSlowApproach];
            Actual3->LEDHighSpeed->Hint = "Proceed preparing to stop at next signal: Slow Speed within interlocking limits.";
            break;
        case AsApproachMedium:	// Approach Medium - Rule 282 - the high speed route is impassable at the next signal. Be prepared to stop at the next signal.
            Actual3->LEDHighSpeed->LED->ColorOn = clYellow;		// the highest speed route is only clear for one block
            Actual3->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
            Actual3->Hint = AspectNames[AsApproachMedium];
            Actual3->LEDHighSpeed->Hint = "Proceed approaching next signal at Medium Speed.";
            break;
        case AsApproachSlow:	// Approach Slow - Rule 284 - the high speed route is impassable at the next signal. Be prepared to stop at the next signal.
            Actual3->LEDHighSpeed->LED->ColorOn = clYellow;     // the highest speed route is only clear for one block
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clLime;		// the low speed route is clear for at least 2 blocks
            Actual3->Hint = AspectNames[AsApproachSlow];
            Actual3->LEDHighSpeed->Hint = "Proceed approaching next signal at Slow Speed. Train exceeding Medium Speed must at once reduce to that speed.";
            break;
        // new
        case AsRestricting:		// Restricting - Rule 290
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual3->LEDLowSpeed->LED->ColorOn = clYellow;		// the low speed route is clear for 1 block but impassable at the next signal.
            Actual3->Hint = AspectNames[AsRestricting];
            Actual3->LEDHighSpeed->Hint = "Proceed at Restricted Speed.";
            break;
        case AsApproachLimited:	// Approach Limited - Rule 281(B)
        	Actual3->LEDHighSpeed->LED->ColorOn = clYellow;		// the highest speed route is only clear for one block
            Actual3->LEDMediumSpeed->Flashing = true;
            Actual3->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
        	Actual3->Hint = AspectNames[AsApproachLimited];
            Actual3->LEDHighSpeed->Hint = "Proceed approaching next signal at Limited Speed.";
        	break;
        case AsLimitedClear:	// Limited Clear - Rule 281(C)
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->Flashing = true;
            Actual3->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
        	Actual3->Hint = AspectNames[AsLimitedClear];
            Actual3->LEDHighSpeed->Hint = "Proceed: Limited Speed within interlocking limits.";
            break;
        case AsLimitedApproach:	// Limited Approach - Rule 281(D)
            Actual3->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual3->LEDMediumSpeed->Flashing = true;
            Actual3->LEDMediumSpeed->LED->ColorOn = clYellow; 	// the medium speed route is only clear for one block then the center light will be yellow.
            Actual3->LEDLowSpeed->LED->ColorOn = clRed;			// the low speed route is impassable
        	Actual3->Hint = AspectNames[AsLimitedApproach];
            Actual3->LEDHighSpeed->Hint = "Proceed at Limited Speed preparing to stop at next signal.";
            break;
        default:
            Actual3->LEDHighSpeed->LED->ColorOn = clBlack;
            Actual3->LEDMediumSpeed->LED->ColorOn = clBlack;
            Actual3->LEDLowSpeed->LED->ColorOn = clBlack;        
			String Msg = "Aspect: " + AspectNames[Aspect];
			if (DEBUGGING) Application->MessageBox(TEXT("Invalid Signal Aspect for 3 light signal Requested. "), Msg.c_str(), MB_OK);
            Actual3->Hint = "Invalid Aspect";
            Actual3->LEDHighSpeed->Hint = "Stop and determine cause of invalid aspect.";
            break;
        }
    Actual3->SignalName->Hint = Actual3->Hint;
    Actual3->NumberPlate->Hint = Actual3->Hint;
    Actual3->LEDMediumSpeed->Hint = Actual3->LEDHighSpeed->Hint;
    Actual3->LEDLowSpeed->Hint = Actual3->LEDHighSpeed->Hint;
    return true;
	}
TLED2Panel * Actual2 = dynamic_cast <TLED2Panel *> (pHead);
if (Actual2) {
    Actual2->LEDHighSpeed->Flashing = false;
    Actual2->LEDMediumSpeed->Flashing = false;
    switch(Aspect) {
        case AsDark:		// Off
            Actual2->LEDHighSpeed->LED->ColorOn = clBlack;
            Actual2->LEDMediumSpeed->LED->ColorOn = clBlack;
            Actual2->Hint = AspectNames[AsDark];
            Actual2->LEDHighSpeed->Hint = "Dark";
            break;
        case AsStop:	// Stop - Rule 292 - The most restrictive case is when both lights are red. This indicates that both routes are impassable at this signal.
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual2->Hint = AspectNames[AsStop];
            Actual2->LEDHighSpeed->Hint = "Stop";
            break;
        case AsStopandProceed:	// Stop and Proceed - Rule 291 - Stop then Proceed at Restricting Speed.
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual2->Hint = AspectNames[AsStopandProceed];
            Actual2->LEDHighSpeed->Hint = "Stop: Then proceed at Restricting Speed";
            break;
        case AsClear:	// Clear - Rule 281 - the highest speed route is clear for at least two blocks.
            Actual2->LEDHighSpeed->LED->ColorOn = clLime;		// the highest speed route is clear for at least two blocks.
            Actual2->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual2->Hint = AspectNames[AsClear];
            Actual2->LEDHighSpeed->Hint = "Proceed";
            break;
        case AsApproach:	// Approach - Rule 285 - the highest speed route is only clear for one block then the top light will be yellow.
            Actual2->LEDHighSpeed->LED->ColorOn = clYellow; 	// the highest speed route is only clear for one block then the top light will be yellow.
            Actual2->LEDMediumSpeed->LED->ColorOn = clRed;		// the medium speed route is impassable
            Actual2->Hint = AspectNames[AsApproach];
            Actual2->LEDHighSpeed->Hint = "Proceed prepared to stop at next signal. Train exceeding Medium Speed must at once reduce to that speed.";
            break;
        case AsMediumClear:	// Medium Clear	- Rule 283
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks.
            Actual2->Hint = AspectNames[AsMediumClear];
            Actual2->LEDHighSpeed->Hint = "Proceed: Medium Speed within interlocking limits.";
            break;
        case AsMediumApproach:	// Medium Approach - Rule 286
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->LED->ColorOn = clYellow; 	// the medium speed route is only clear for one block then the center light will be yellow.
            Actual2->Hint = AspectNames[AsMediumApproach];
            Actual2->LEDHighSpeed->Hint = "Proceed at Medium Speed preparing to stop at next signal.";
            break;
        case AsApproachMedium:	// Approach Medium - Rule 282 - the high speed route is impassable at the next signal. Be prepared to stop at the next signal.
            Actual2->LEDHighSpeed->LED->ColorOn = clYellow;		// the highest speed route is only clear for one block
            Actual2->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks
            Actual2->Hint = AspectNames[AsApproachMedium];
            Actual2->LEDHighSpeed->Hint = "Proceed approaching next signal at Medium Speed.";
            break;
        // new
        case AsRestricting:		// Restricting - Rule 290
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->LED->ColorOn = clYellow;	// the medium speed route is clear for 1 block but impassable at the next signal.
            Actual2->Hint = AspectNames[AsRestricting];
            Actual2->LEDHighSpeed->Hint = "Proceed at Restricted Speed.";
            break;
        case AsApproachLimited:	// Approach Limited - Rule 281(B)
        	Actual2->LEDHighSpeed->LED->ColorOn = clYellow;		// the highest speed route is only clear for one block
            Actual2->LEDMediumSpeed->Flashing = true;
            Actual2->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks
        	Actual2->Hint = AspectNames[AsApproachLimited];
            Actual2->LEDHighSpeed->Hint = "Proceed approaching next signal at Limited Speed.";
        	break;
        case AsLimitedClear:	// Limited Clear - Rule 281(C)
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->Flashing = true;
            Actual2->LEDMediumSpeed->LED->ColorOn = clLime;		// the medium speed route is clear for at least 2 blocks
        	Actual2->Hint = AspectNames[AsLimitedClear];
            Actual2->LEDHighSpeed->Hint = "Proceed: Limited Speed within interlocking limits.";
            break;
        case AsLimitedApproach:	// Limited Approach - Rule 281(D)
            Actual2->LEDHighSpeed->LED->ColorOn = clRed;		// the high speed route is impassable
            Actual2->LEDMediumSpeed->Flashing = true;
            Actual2->LEDMediumSpeed->LED->ColorOn = clYellow; 	// the medium speed route is only clear for one block then the center light will be yellow.
        	Actual2->Hint = AspectNames[AsLimitedApproach];
            Actual2->LEDHighSpeed->Hint = "Proceed at Limited Speed preparing to stop at next signal.";
            break;
        default:
            Actual2->LEDHighSpeed->LED->ColorOn = clBlack;
            Actual2->LEDMediumSpeed->LED->ColorOn = clBlack;
			String Msg = "Aspect: " + AspectNames[Aspect];
			if (DEBUGGING) Application->MessageBox(TEXT("Invalid Signal Aspect for 2 light signal Requested. "), Msg.c_str(), MB_OK);
            Actual2->Hint = "Invalid Aspect";
            Actual2->LEDHighSpeed->Hint = "Stop and determine cause of invalid aspect.";
            break;
        }
    Actual2->SignalName->Hint = Actual2->Hint;
    Actual2->NumberPlate->Hint = Actual2->Hint;
    Actual2->LEDMediumSpeed->Hint = Actual2->LEDHighSpeed->Hint;
    return true;
	}
TLED1Panel * Actual1 = dynamic_cast <TLED1Panel *> (pHead);
if (Actual1) {
    Actual1->LEDHighSpeed->Flashing = false;
    switch(Aspect) {
		case AsDark:		// Off
			Actual1->LEDHighSpeed->LED->ColorOn = clBlack;
			Actual1->Hint = AspectNames[AsDark];
			Actual1->LEDHighSpeed->Hint = "Dark";
			break;
		case AsStop:	// Stop - Rule 292 - The most restrictive case is when the light is red.
			Actual1->LEDHighSpeed->LED->ColorOn = clRed;
			Actual1->Hint = AspectNames[AsStop];
			Actual1->LEDHighSpeed->Hint = "Stop";
			break;
		case AsStopandProceed:	// Stop and Proceed - Rule 291 - Stop then Proceed at Restricting Speed.
			Actual1->LEDHighSpeed->LED->ColorOn = clRed;
			Actual1->Hint = AspectNames[AsStopandProceed];
			Actual1->LEDHighSpeed->Hint = "Stop: Then proceed at Restricting Speed";
			break;
		case AsClear:	// Clear - Rule 281
			Actual1->LEDHighSpeed->LED->ColorOn = clLime;
			Actual1->Hint = AspectNames[AsClear];
			Actual1->LEDHighSpeed->Hint = "Proceed";
			break;
		case AsApproach:	// Approach - Rule 285
			Actual1->LEDHighSpeed->LED->ColorOn = clYellow;
			Actual1->Hint = AspectNames[AsApproach];
			Actual1->LEDHighSpeed->Hint = "Proceed prepared to stop at next signal. Train exceeding Medium Speed must at once reduce to that speed.";
			break;
		default:
	        Actual1->LEDHighSpeed->LED->ColorOn = clBlack;
			String Msg = "Aspect: " + AspectNames[Aspect];
			if (DEBUGGING) Application->MessageBox(TEXT("Invalid Signal Aspect for 1 light signal Requested. "), Msg.c_str(), MB_OK);
            Actual1->Hint = "Invalid Aspect";
            Actual1->LEDHighSpeed->Hint = "Stop and determine cause of invalid aspect.";
			break;
        }
    Actual1->SignalName->Hint = Actual1->Hint;
    Actual1->NumberPlate->Hint = Actual1->Hint;
    return true;
	}
return false;
}
//---------------------------------------------------------------------------

bool __fastcall TFixedSignalFormX::Reset(TPanel * pHead)
{
if (!pHead) return false;
pHead->Tag = AsDark;
TLED3Panel * Actual3 = dynamic_cast <TLED3Panel *> (pHead);
if (Actual3) {
	Actual3->LEDHighSpeed->Checked = true;
	Actual3->LEDMediumSpeed->Checked = true;
	Actual3->LEDLowSpeed->Checked = true;
	Actual3->SignalName->Caption = "**";
	Actual3->NumberPlate->Visible = false;
    Actual3->NumberPlate->Caption = "";
	Actual3->LEDHighSpeed->LED->ColorOn = clBlack;
	Actual3->LEDMediumSpeed->LED->ColorOn = clBlack;
	Actual3->LEDLowSpeed->LED->ColorOn = clBlack;
	return true;
	}
TLED2Panel * Actual2 = dynamic_cast <TLED2Panel *> (pHead);
if (Actual2) {
	Actual2->LEDHighSpeed->Checked = true;
	Actual2->LEDMediumSpeed->Checked = true;
	Actual2->SignalName->Caption =  "**";;
	Actual2->NumberPlate->Visible = false;
    Actual2->NumberPlate->Caption = "";
	Actual2->LEDHighSpeed->LED->ColorOn = clBlack;
	Actual2->LEDMediumSpeed->LED->ColorOn = clBlack;
	return true;
	}
TLED1Panel * Actual1 = dynamic_cast <TLED1Panel *> (pHead);
if (Actual1) {
	Actual1->LEDHighSpeed->Checked = true;
	Actual1->SignalName->Caption =  "**";;
	Actual1->NumberPlate->Visible = false;
    Actual1->NumberPlate->Caption = "";
	Actual1->LEDHighSpeed->LED->ColorOn = clBlack;
	return true;
	}
return false;
}
//---------------------------------------------------------------------------

bool __fastcall TFixedSignalFormX::SignalName(TPanel * pHead, String sName, int iNumberPlate)
{
// sName == "" means don't change the Signal Name
// iNumberPlate == -1 means don't change the Number Plate
// iNumberPlate == 0 means make the Number Plate invisible or an 'A' depending on FixedSignalForm->Absolute>Checked
if (!pHead) return false;
TLED3Panel * Actual3 = dynamic_cast <TLED3Panel *> (pHead);
if (Actual3) {
    if (sName != "") Actual3->SignalName->Caption = sName;
	if (iNumberPlate == -1) {
    	return true;
        }
    if (iNumberPlate == 0) {
        //Actual3->NumberPlate->Caption = "A";
        Actual3->NumberPlate->Caption = (FixedSignalFormX && FixedSignalFormX->Absolute->Checked) ? "A" : "";
        Actual3->NumberPlate->Visible = true;
		return true;
        }
    Actual3->NumberPlate->Caption = String(iNumberPlate);
    Actual3->NumberPlate->Visible = true;
    return true;
    }
TLED2Panel * Actual2 = dynamic_cast <TLED2Panel *> (pHead);
if (Actual2) {
    if (sName != "") Actual2->SignalName->Caption = sName;
	if (iNumberPlate == -1) {
    	return true;
        }
    if (iNumberPlate == 0) {
        //Actual2->NumberPlate->Caption = "A";
        Actual2->NumberPlate->Caption = (FixedSignalFormX && FixedSignalFormX->Absolute->Checked) ? "A" : "";
        Actual2->NumberPlate->Visible = true;
		return true;
        }
    Actual2->NumberPlate->Caption = String(iNumberPlate);
    Actual2->NumberPlate->Visible = true;
    return true;
    }
TLED1Panel * Actual1 = dynamic_cast <TLED1Panel *> (pHead);
if (Actual1) {
    if (sName != "") Actual1->SignalName->Caption = sName;
	if (iNumberPlate == -1) {
    	return true;
        }
    if (iNumberPlate == 0) {
        //Actual1->NumberPlate->Caption = "A";
        Actual1->NumberPlate->Caption = (FixedSignalFormX && FixedSignalFormX->Absolute->Checked) ? "A" : "";
        Actual1->NumberPlate->Visible = true;
		return true;
        }
    Actual1->NumberPlate->Caption = String(iNumberPlate);
    Actual1->NumberPlate->Visible = true;
    return true;
    }
return false;
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::SignalGridMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
int ARow, ACol;
if (Button == mbRight) {
	SignalGrid->MouseToCell(X, Y, ACol, ARow);
    SignalGrid->Row = ARow;
	SignalGrid->Col = ACol;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::CopytoClipboard1Click(TObject *Sender)
{
CopyrightClick(Sender);		
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::InfoClick(TObject *Sender)
{
// Info window - You must delete this form in the destructor
//
// Fill the Help Text Memo
//
const String SpeedsFile = String(MainForm->cStartDir) + "\\Speeds.txt";
if (SignalHelp == NULL) {
	SignalHelp = new TRTCHelp(this);
	assert(SignalHelp != NULL);		// make sure that construction worked
    SignalHelp->HelpInfo->Clear();
	SignalHelp->Caption = "Fixed Signals Information";
    // if the Speeds.txt file exists, overwrite the internal data
	if (FileExists(SpeedsFile)) {
	    SignalHelp->HelpInfo->Lines->LoadFromFile(SpeedsFile);
        if (DEBUGGING) DB->Debug_Print("Speed Text Read from " + SpeedsFile);
		} else {
	    SignalHelp->HelpInfo->Lines->Text = Information->Lines->Text;
        }
    }
SignalHelp->Show();		// show Info window
}
//---------------------------------------------------------------------------

void __fastcall TFixedSignalFormX::ShowTextClick(TObject *Sender)
{
WBLabel->Visible = !WBLabel->Visible;
EBLabel->Visible = !EBLabel->Visible;
}
//---------------------------------------------------------------------------

