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

© Copyright 2015 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/>.

*/
//---------------------------------------------------------------------------
#include <vcl.h>
#include <tchar.h>
#pragma hdrstop

#include "Train_Control.h"
#include "TMCC_Control.h"
#include "Setup_Control.h"
#include "Debug_Controls.h"
#include "Message_Popup.h"
#include "LashUp_Selection.h"
#include "Comm_Thread.h"
#include "Clipbrd.hpp"

#include <math.h>
#include <stdio.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "_GClass"
#pragma link "AbCBitBt"
#pragma link "AbLED"
#pragma link "AbSwitch"
#pragma link "AbVSlide"
#pragma link "HideButton"
#pragma link "ColorButton"
#pragma resource "*.dfm"
TTMCCOp *TMCCOp;	// NOTE: this is public static variable, you can never use
			// this when you create multiple instances of a Form

extern TCommThread * ptrTIUCommThread;				// pointer to TIU communications thread

//---------------------------------------------------------------------------
__fastcall TTMCCOp::TTMCCOp(TComponent* Owner)
	: TForm(Owner)
{
assert(false);	// never called since I used the overloaded constructor below
}
//---------------------------------------------------------------------------
__fastcall TTMCCOp::TTMCCOp(TComponent* Owner, int Remote, int Consist, int TIU, String ConName, char * ptrLUEngineList)
    : TForm(Owner)
{
// grab the Remote, Engine/LashUp, TIU numbers and Consist Name, LashUpEngineList is not used
RemoteNo = Remote;
assert(RemoteNo >= 0 && RemoteNo <= REMOTEMAX); // 0-15
ConsistNo =  Consist;
assert(ConsistNo >= 1 && ConsistNo <= ENGINEMAX);	// 1-99
TIUNo = TIU;
assert(TIUNo >= 1 && TIUNo <= TIUMAX);  // 1-5
ConsistName = ConName;
assert(ptrLUEngineList == NULL);	// must be NULL
LashUpEngineList = NULL;
// Normal Engine
Operation_Controls_Label->Caption = "Engine " + String(ConsistNo) + " " +
        ConsistName + " - TIU " + String(TIUNo);

this->Caption = "Controls for " + Operation_Controls_Label->Caption;

// read Preferences from registry if they exist
TRegIniFile * const RegFile = new TRegIniFile(MainForm->RegFileRootKey);
assert(RegFile != NULL);
__try {
	Speed_Steps = RegFile->ReadInteger("Options", "Speed_Steps", 32);
    }
__finally {
	// Deallocate RegFile
	delete RegFile;
    }

if (Setup->DisableEmergencyStopButton->Checked) {
	ESTOP->Visible = false;
    ESTOP->Enabled = false;
    ESTOP->Hint = "Disabled in Setup";
    ESTOP->Cursor = crNo;
    }

MotionSoundRequest->Checked = true;	// request sound on next train movement
// but make it visible only in debug mode
if (DEBUGGING) {
	MotionSoundRequest->Visible = true;
	}

AutoCouplerSwitch->Checked = Setup->AutoCoupler->Checked;
AutoCouplerSwitch->Enabled = Setup->AutoCoupler->Checked;
// TODO : Setup->AutoWhistle should also be part of this equation
AutoBellWhistleSwtich->Checked = Setup->AutoBell->Checked;
AutoBellWhistleSwtich->Enabled = Setup->AutoBell->Checked;
// Set Maximum Steps  128  or 32
if (SpeedStepSwitch->Checked) {
	// 128 steps
	StepSlider->SignalSettings->DigitalTo = 127;
	StepSlider->SignalSettings->ValueTo = 127;
	StepSlider->ScaleSettings->Steps = 10;
	StepSlider->ScaleSettings->SubSteps = 2;
    } else {
    // 32 steps
	StepSlider->SignalSettings->DigitalTo = 31;
	StepSlider->SignalSettings->ValueTo = 31;
	StepSlider->ScaleSettings->Steps = 10;
	StepSlider->ScaleSettings->SubSteps = 2;
    }
//
// bug in the TAbVslider causes it to start out at 10
// this sets the slider to zero without sending a "T60-T7F" command
void __fastcall (__closure *StepSliderOnValueChange)(TObject *Sender);
StepSliderOnValueChange = StepSlider->OnValueChange;
StepSlider->OnValueChange = NULL;
StepSlider->Value = 0;
StepSlider->OnValueChange = StepSliderOnValueChange;
//
}
//---------------------------------------------------------------------------
__fastcall TTMCCOp::~TTMCCOp(void)
{
if (MainForm->bSaveRegistryInfo) {
    // write preferences to the Registry
    TRegIniFile * const RegFile = new TRegIniFile(MainForm->RegFileRootKey);
    assert(RegFile != NULL);
    __try {
        RegFile->WriteInteger("Options", "Speed_Steps", Speed_Steps);
        }
    __finally {
        // Deallocate RegFile
        delete RegFile;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::WhistleButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// start whistle
// Send CM_WHISTLE message to ourselves which will perform this function
(void) PostMessage(Handle, CM_WHISTLE, true, NULL);	// true = button down
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::WhistleButtonMouseUp(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// stop whistle : -2  : FFFD one's complement
// Send CM_WHISTLE message to ourselves which will perform this function
(void) PostMessage(Handle, CM_WHISTLE, false, NULL);	// false = button up
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CMWhistle(TMessage &Message)
{
//
if (DEBUGGING) DB->Debug_Print("CMWhistle");
const bool Dn = Message.WParam;		// set button state from Word Parameter
if (Dn) {
	// start whistle
    (void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T15", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
    }
if (!Dn) {
	// stop whistle
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T16", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
	}
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::DIRButtonClick(TObject *Sender)
{
// Send CM_DIR message to ourselves which will perform this function
(void) PostMessage(Handle, CM_DIR, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CMDir(TMessage &Message)
{
//
if (DEBUGGING) DB->Debug_Print("CMDir");
// DIR button pressed
// https://stackoverflow.com/questions/31649315/c-builder-button-click-function-reentry
LOCKEM()
// set speed to zero
StepSlider->Value = 0;	// causes the 's' command to be sent if the speed isn't already zero
MotionSoundRequest->Checked = true; 	// request sound on next train movement
// Send Direction Toggle
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T02", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
StepSlider->SetFocus();	// focus to speed slider
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CPLRFButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
//CPLR-F
// Uncouple Front
// Send CM_CPRLF message to ourselves which will perform this function
(void) PostMessage(Handle, CM_CPLRF, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CPLRRButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
//CPLR-R
// Uncouple Rear
// Send CM_CPRLR message to ourselves which will perform this function
(void) PostMessage(Handle, CM_CPLRR, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CMCPLRF(TMessage &Message)
{
// Uncouple Front
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T05", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CMCPLRR(TMessage &Message)
{
// Uncouple Rear
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T06", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::SmokeSwitchStatusChanged(TObject *Sender)
{
switch (EngineTypeComboBox->ItemIndex) {
	case STEAM_ENGINE:
    case DIESEL_ENGINE:
	// Send Smoke on or Smoke off
	if (SmokeSwitch->Checked) {
	    // ON
		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T13", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
		} else {
	   	// OFF
		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T12", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
	    }
    break;
    }
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::BoostButtonStatusChanged(TObject *Sender)
{
// Boost
// Increase speed by 1 Step per timer interval until released
static float SavedStep;

if (BoostButton->Checked) {
	if ((StepSlider->Value <= 0.01) || (StepSlider->Value == StepSlider->SignalSettings->ValueTo)) return;	// no effect when stopped or max
    SavedStep = StepSlider->Value;
	Boosting = true;
    BoostBrakeTimerTimer(BoostBrakeTimer);	// Immediate Boost
    BoostBrakeTimer->Enabled = true;
    // every timer interval, boost the speed
	}

if (!BoostButton->Checked) {
	// button released - turn off the timer
    Boosting = false;
    BoostBrakeTimer->Enabled = false;
    if (Setup->BrakeBoost->ItemIndex == 0) {
    	// stay at new speed - so do nothing
        return;
        } else {
        // return to saved speed
        StepSlider->Value = SavedStep;	// causes the 'T60-T7F' command to be sent
        return;
        }
	}	
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::BrakeButtonStatusChanged(TObject *Sender)
{
// Brake
// Decrease speed by 1 Step per timer interval until released
static float SavedStep;

if (BrakeButton->Checked) {
	if (StepSlider->Value == 0) return;	// no effect when stopped
	SavedStep = StepSlider->Value;
	Braking = true;
    BoostBrakeTimerTimer(BoostBrakeTimer);	// Immediate Brake
    BoostBrakeTimer->Enabled = true;
    // every timer interval, brake the speed
	}

if (!BrakeButton->Checked) {
	// button released - turn off the timer
    Braking = false;
    BoostBrakeTimer->Enabled = false;
    if (Setup->BrakeBoost->ItemIndex == 0) {
    	// stay at new speed - so do nothing
        return;
        } else {
        // return to saved speed
        StepSlider->Value = SavedStep; 	// causes the 'T60-T7F' command to be sent
        return;
        }
	}
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::BoostBrakeTimerTimer(TObject *Sender)
{
BoostBrakeTimer->Enabled = false;	// disable the time while in this routine
if (Boosting) {
	if ((StepSlider->Value != 0) && (StepSlider->Value != StepSlider->SignalSettings->ValueTo)) {	// only when moving at non max speed
		int Step = StepSlider->Value + 1.0;	// increment by 1;
    	StepSlider->Value = Step;	// causes the 'T60-T7F' command to be sent preceeded by Bell and Whistle
    	}
    }
if (Braking) {
	if (StepSlider->Value != 0) {	// Only when not stopped
		int Step = StepSlider->Value - 1.0;	// decrement by 1
    	StepSlider->Value = Step;	// causes the 'T60-T7F' command to be sent
        }
	}
BoostBrakeTimer->Enabled = true;	// enable the timer on normal exit
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::BellButtonClick(TObject *Sender)
{
// Bell Toggle
// Send CM_BELL message to ourselves which will perform this function
(void) PostMessage(Handle, CM_BELL, true, NULL);	// true = button down
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::CMBell(TMessage &Message)
{
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T14", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TTMCCOp::HeadlightButtonClick(TObject *Sender)
{
// Headlight Toggle
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T09", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::MOMGroupClick(TObject *Sender)
{
// Momentum Level
// 0	Low  T1A
// 1	Medium  T1B
// 2	High  T1C
char str[15];
snprintf(str, sizeof str, "T1%c", MOMGroup->ItemIndex + 'A');
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, str, TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::AUXLightsSwitchStatusChanged(TObject *Sender)
{
// Turn Aux Lights on or off
//
if (AXLightsSwitch->Checked) {
    // ON
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T27", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T59", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
	} else {
   	// OFF
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T27", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T58", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::VolUpButtonClick(TObject *Sender)
{
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T0B", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::VolDnButtonClick(TObject *Sender)
{
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T0E", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::SpeedStepSwitchStatusChanged(TObject *Sender)
{
// Set Speed Steps
// change slider
// Set Maximum Steps  128  or 32
if (SpeedStepSwitch->Checked) {
	Speed_Steps = 128;
    // 128 steps
	StepSlider->SignalSettings->DigitalTo = 127;
	StepSlider->SignalSettings->ValueTo = 127;
	StepSlider->ScaleSettings->Steps = 10;
	StepSlider->ScaleSettings->SubSteps = 2;
	} else {
	Speed_Steps = 32;
    // 32 steps
	StepSlider->SignalSettings->DigitalTo = 31;
	StepSlider->SignalSettings->ValueTo = 31;
	StepSlider->ScaleSettings->Steps = 10;
	StepSlider->ScaleSettings->SubSteps = 2;
    }
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::OpShutdownClick(TObject *Sender)
{
// Send CM_TMCCSHUTDOWN message to MainForm which will set speed to zero and issue shutdown command
(void) PostMessage(ParentHandle, CM_TMCCSHUTDOWN, TIUNo, ConsistNo);
}
//---------------------------------------------------------------------------
//
// Sometimes the IDE cannot find this event handler if you double click on
// the Events in the Object Inspector. This is in BCB4.0. In CB10.1 it seems
// to find it. With both compilers, it seems to link ok and operates correctly.
//
// Caused by the addition of the declaration of the __closure *XXXXOnValueChange
// inside of XXXXValueChange. It seems to work correctly, if I declare
// the __closure outside of the function.
//
static void __fastcall (__closure *StepSliderOnValueChange)(TObject *Sender);
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::StepSliderValueChange(TObject *Sender)
{
static float LastSentStepValue;
if (Speed_Steps == 128) return;	// not used for speed steps of 128
//
// Send speed command based on value of slider
// https://stackoverflow.com/questions/31649315/c-builder-button-click-function-reentry
LOCKEM()
LastSentStepValue = StepSlider->Value;	// save the current setting voltage

if (DEBUGGING) DB->Debug_Print("StepSliderValueChange : " + String(StepSlider->Value));

// disconnect event handler while processing the MasterVolumeValueChange();
StepSliderOnValueChange = StepSlider->OnValueChange;
StepSlider->OnValueChange = NULL;

const int Step = StepSlider->Value;

if (SpeedStepSwitch->Checked) {
	// 128 steps
    // NOP
    } else {
	// for 32 steps
	// Scale the speed if requested in Setup
	const int ScaledStep = Step / MainForm->GlobalMPHScaling;
	// Convert value into chars
	char str[10];
	(void) snprintf(str, sizeof str, "T%02X", (ScaledStep) + 0x60);
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, str, TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
    }

if (Step != 0) {
    MotionSoundRequest->Checked = false; 	// no sound on next train movement
    }

// if the speed is set to zero, request sounds on next move off zero
if (Step == 0) {
	MotionSoundRequest->Checked = true;	// request sound on next train movement
    }

// Restore Event Handler
StepSlider->OnValueChange = StepSliderOnValueChange;

// Check for slider movement while setting voltage
if (LastSentStepValue != StepSlider->Value) {
    if (DEBUGGING) DB->Debug_Print("StepSliderValueChange Speed Changed on Exit : " + String(StepSlider->Value) +
    	" from " + String(LastSentStepValue));
    StepSliderValueChange(Sender);	// call me again to process the changed speed value
	}
return;
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::EngineTypeComboBoxClick(TObject *Sender)
{
switch (EngineTypeComboBox->ItemIndex) {
	case STEAM_ENGINE:
    // Steam
    EngineTypeLED->LED->ColorOff = clAqua;
    EngineTypeLED->LED->ColorOn = clAqua;
    EngineTypeLED->Caption = "Steam";

    ChuffRateSwitch->Enabled = true;
    ChuffRateSwitch->LEDColorOff = clRed;
    ChuffRateSwitch->LEDColorOn = clLime;

    ProtoChuffSwitch->Enabled = true;
    ProtoChuffSwitch->LEDColorOff = clRed;
    ProtoChuffSwitch->LEDColorOn = clLime;
    ProtoChuffSwitch->Text = "Proto|Chuff";

    AutoBellWhistleSwtich->Text = "Bell|Whistle";

    SmokeSwitch->Visible = true;
    SmokeSwitch->Text = "Smoke";

    LaborRevUpButton->TextOff = "LABOR|CHUFF";
    LaborRevUpButton->Hint = "Labor Chuff";

    DriftRevDnButton->TextOff = "DRIFT|CHUFF";
    DriftRevDnButton->Hint = "Drift Chuff";
    break;

    case DIESEL_ENGINE:
	// Diesel
    EngineTypeLED->LED->ColorOff = clWhite;
    EngineTypeLED->LED->ColorOn = clWhite;
    EngineTypeLED->Caption = "Diesel";

    ChuffRateSwitch->Enabled = false;
    ChuffRateSwitch->LEDColorOff = clInactiveBorder;
    ChuffRateSwitch->LEDColorOn = clInactiveBorder;
    ProtoChuffSwitch->Text = "Proto|Rev";

    AutoBellWhistleSwtich->Text = "Auto|Horn";

    SmokeSwitch->Visible = true;
    SmokeSwitch->Text = "Exhaust";

    LaborRevUpButton->TextOff = "REV UP";
    LaborRevUpButton->Hint = "Rev Up";

    DriftRevDnButton->TextOff = "REV DN";
    DriftRevDnButton->Hint = "Rev Down";
    break;

    case ELECTRIC_ENGINE:
    EngineTypeLED->LED->ColorOff = clGreen;
    EngineTypeLED->LED->ColorOn = clGreen;
    EngineTypeLED->Caption = "Electric";

    ChuffRateSwitch->Enabled = false;
    ChuffRateSwitch->LEDColorOff = clInactiveBorder;
    ChuffRateSwitch->LEDColorOn = clInactiveBorder;

    ProtoChuffSwitch->Text = "Proto|Rev";
    AutoBellWhistleSwtich->Text = "Auto|Horn";

    SmokeSwitch->Visible = false;
    SmokeSwitch->Text = "";

    LaborRevUpButton->TextOff = "REV UP";
    LaborRevUpButton->Hint = "Rev Up";

    DriftRevDnButton->TextOff = "REV DN";
    DriftRevDnButton->Hint = "Rev Down";
    break;
	}	
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::EngineTypeLEDClick(TObject *Sender)
{
// toggle through engine types
EngineTypeComboBox->ItemIndex = (EngineTypeComboBox->ItemIndex + 1) % 3;
EngineTypeComboBoxClick(Sender);	// process the change	
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::SpeedUpButtonStatusChanged(TObject *Sender)
{
// Speed Step double increment
// Increase speed by 1 Speed Step per timer interval until released

if (SpeedUpButton->Checked) {
	if (StepSlider->Value == StepSlider->SignalSettings->ValueTo) return;	// no effect when max speed
	SpeedUp1x = true;
    SpeedStepTimer->Enabled = true;
    // every timer interval, Step the speed Up
	}

if (!SpeedUpButton->Checked) {
	// button released - turn off the timer
    SpeedUp1x = false;
    SpeedStepTimer->Enabled = false;
	}
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::SpeedDnButtonStatusChanged(TObject *Sender)
{
// Speed Step double decrement
// Decrease speed by 1 Speed Step per timer interval until released

if (SpeedDnButton->Checked) {
	if (StepSlider->Value == 0) return;	// no effect when stopped
    SpeedDn1x = true;
    SpeedStepTimer->Enabled = true;
    // every timer interval, Step the speed Down
	}

if (!SpeedDnButton->Checked) {
	// button released - turn off the timer
    SpeedDn1x = false;
    SpeedStepTimer->Enabled = false;
	}
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::SpeedStepTimerTimer(TObject *Sender)
{
SpeedStepTimer->Enabled = false;	// disable the time while in this routine
if (SpeedUp1x) {
	if ((StepSlider->Value != 0) && (StepSlider->Value != StepSlider->SignalSettings->ValueTo)) {	// only when moving at non max speed
		int Step = StepSlider->Value + 1.0;	// increment by 1
    	StepSlider->Value = Step;
   		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T46", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
    	}
    }
if (SpeedDn1x) {
	if (StepSlider->Value != 0) {	// Only when not stopped
		int Step = StepSlider->Value - 1.0;	// decrement by 1
    	StepSlider->Value = Step;
   		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T44", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
        }
	}
SpeedStepTimer->Enabled = true;	// enable the timer on normal exit
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::LaborRevUpButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// Rev Up On
switch (EngineTypeComboBox->ItemIndex) {
    case DIESEL_ENGINE:
		// for Diesel
		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T27", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T53", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
        break;
	}
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::DriftRevDnButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// Rev Down On
switch (EngineTypeComboBox->ItemIndex) {
    case DIESEL_ENGINE:
		// for Diesel Engines
		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T27", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
		(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "T56", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineList, NULL, NULL);
    	break;
	}
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::FormKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
// Make sure KeyPreview is true for this form
assert(KeyPreview);
MainForm->FormKeyDown(Sender, Key, Shift);
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::StopButtonOpMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// speed 0
StepSlider->Value = 0;	// causes the 'T60-T7F' command to be sent
StepSlider->SetFocus();	// focus to speed slider
MotionSoundRequest->Checked = true;	// request sound on next train movement	
}
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::Operation_Controls_LabelClick(TObject *Sender)
{
LocalTransparencyOverride = !LocalTransparencyOverride;	// Toggle transparency locally	
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Workaround for SetLayeredWindowAttributes() to make transparent windows
extern lpfnSetLayeredWindowAttributes m_pSetLayeredWindowAttributes;
//---------------------------------------------------------------------------

void __fastcall TTMCCOp::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 TTMCCOp::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 TTMCCOp::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;
    }
}
//---------------------------------------------------------------------------



