{****************************************************************************
 ***                                                                      ***
 *** New Fabbo Singing Dancing OOP                                        ***
 ***                        MATERIAL SHOP QUOTATIONS                      ***
 ***                                                                      ***
 *** M Hill                                                      Aug 1993 ***
 ****************************************************************************}
{A series of invoice items that bolt in to the invoice module}
{$I compdirs}  {Compiler directives}

unit kmatshop;

INTERFACE

uses views, objects, drivers,
		 global, scodes, dattime,
		 tuiedit, notes, devices, forms,
		 multcurr,
		 jimmys,
		 measures,
		 files,{}
		 setup,
		 ordproc;

type
	{*************************************************
	 ***        MATERIAL GOODS                     ***
	 *************************************************}
	PFabric = ^TFabric;
	TFabric = object(TJimmy)
		Name 				: string[20];
		Colour 			: string[12];
		Collection 	: String[12];
		SupplierID 	: longint;  {Pointer to person}
		SupplierCode : string[20];
		Width 			: TLength;
		PatternRepeat : TLength;
		Pricepm 		: TMoney;

		FabricIdx 	: longint;

		constructor Init(Param : PJimmyInitParam);

		function MakeInputGroup(const X,Y : integer) : PInputGroup; virtual;

		procedure SetFormCodes(const FormCodes: PFormCodeCollection); virtual;

		{database}
		function RecSize : word; virtual;
		function srType : word; virtual;

		procedure Load(var S : TDataStream);
		procedure StoreFields(var S : TDataStream); virtual;

		{--- Indexing ----}
		function NumixTypes : byte; virtual;
		procedure GetIndex(const ixType : byte; var IdxRec : Plongint; var fiType : byte); virtual;
		function GetIndexKey(const ixType : byte) : string; virtual;
	end;



	{*************************************************
	 ***        ACCESSORY                          ***
	 *************************************************}
	PCQAccessory = ^TCQAccessory;
	TCQAccessory = object(TOrderItem)

		Code 			: TSCode;  		{what is it}
		Quantity 	: byte; 			{how many}

		FabricID	: longint;

		FabricLength : TLength;
		TotalFabricPrice  : TMOney;

		MakingPrice : TMoney;

		Notes : PFreeTextData;

		Fabric : PFabric;

		{-- Methods --}
		constructor Init(Param : PJimmyInitParam);
		procedure CommonInit;                       virtual;
		destructor Done; virtual;

	 {Display}
		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;

		procedure SetFormCodes(const FormCodes: PFormCodeCollection); virtual;

		function GetFabric : PFabric;

		{DataBase}
		function RecSize : word; virtual;
		function srType : word; virtual;

		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream); virtual;

		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView); virtual;

	 {Works out calculated fields above in prep for CalculateResults and
	 for worksheets, etc}
	 procedure CalculateWorkingValues;
{	 procedure CalculateTotals; virtual;{}
	end;


	{*************************************************
	 ***        PANEL   QUOTER                     ***
	 *************************************************}
	PCQPanel = ^TCQPanel;
	TCQPanel = object(TOrderItem)

		Code 			: TSCode;  		{what is it}
		Quantity 	: byte; 		{how many}

		Height   	: TLength;
		Width 		: TLength;

		FabricID	: longint;

		MakingType	: TScode;
		Heading   	: TScode;

		TBHem   		: TLength;
		SideHem   	: TLength;

		NumWidths 	: byte;

		FabricLength : TLength;

		TotalFabricPrice : TMoney;

		PriceMakingpW : TMoney;

		PleatGap  : TLength;

		Fabric : PFabric;

		{---- Calculated Fields -----}
		TotalMakingPrice : TMoney;

		CutDrop : TLength;

		NumPleats : byte;
		PleatWidth : TLength;
		PleatStart : TLength;

		{-- Methods --}
		constructor Init(Param : PJimmyInitParam);
		procedure CommonInit;                       virtual;
		destructor Done; virtual;

		{Display}
		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;

		function GetFabric : PFabric;

		procedure SetFormCodes(const FormCodes: PFormCodeCollection); virtual;

		{DataBase}
		function RecSize : word; virtual;
		function srType : word; virtual;

		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream); virtual;

		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView); virtual;

	 {Works out calculated fields above in prep for CalculateResults and
	 for worksheets, etc}
	 procedure CalculateWorkingValues;
{	 procedure CalculateTotals; virtual;{}
	end;


	{*************************************************
	 ***  SPECIAL QUOTER - CURTAINS                ***
	 *************************************************}
	PCurtainQuote = ^TCurtainQuote;
	TCurtainQuote = object(TOrderItem)

		Code : TSCode;
		Quantity : byte;

		NoCurtspW 	: byte;
		Drop		   	: TLength;
		RailWidth 	: TLength;
		Return		 	: TLength;
		Overlap	 		: TLength;{}
		HeadedWidth : TLength;

		FabricID		: longint;
		Lining    	: TScode;
		Interlining : TSCode;

		MakingType  : TScode;
		Heading   	: TScode;

		TBHem   		: TLength;
		SideHem   	: TLength;
		LiningTBHem : TLength;
		LiningSideHem : TLength;

		NumWidths 		: byte;

		FabricLength 	: TLength;
		LiningLength 	: TLength;

		TotalFabricPrice : TMoney;
		TotalLiningPrice : TMoney;
		TotalInterliningPrice : TMoney;

		PriceMakingpW : TMoney;

		PleatGap  		: TLength;

		{---- Calculated Fields -----}
		TotalMakingPrice : TMoney;

		CutDrop 			: TLength;

		NumPleats 		: byte;
		PleatWidth 		: TLength;
		PleatStart 		: TLength;

		Fabric : PFabric;

		{-- Methods --}
		constructor Init(Param : PJimmyInitParam);
		procedure CommonInit;                       virtual;
		destructor Done; virtual;

		{Display}
		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;

		procedure SetFormCodes(const FormCodes: PFormCodeCollection); virtual;

		function GetFabric : PFabric;

		{DataBase}
		function RecSize : word; virtual;
		function srType : word; virtual;

		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream); virtual;

		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView); virtual;

	 {Works out calculated fields above in prep for CalculateResults and
	 for worksheets, etc}
	 procedure CalculateWorkingValues;
{	 procedure CalculateTotals; virtual;{}
	end;


	{*********************************
	 *** SPECIAL QUOTER - EDGINGS  ***
	 *********************************}

const
	poLeading = 0;
	poTrailing = 1;
	poBottom = 2;
	poTop = 3;

type
	PCQEdging = ^TCQEdging;
	TCQEdging = object(TOrderItem)

		Code : TSCode;   {eg braiding, piping, border etc with price material per meter length & price making}
		Quantity : byte; {how many curtains with this, eg a pair?}

		Position : word; {1 = leading, 2 = bottom, 3 = trailing, 4 = top}

		{From parent curtain}
		Drop  : TLength;
		Width : TLength;

		Name : string[20];
		Colour : string[20];
		Pricepm : TMOney; {Price of edging per meter (eg braiding, the piping itself, etc)}

		MakingPricepm : TMoney; {Price of making per meter}

		{-- Methods --}
		constructor Init(Param : PJimmyInitParam);
		procedure CommonInit;                       virtual;
		destructor Done; virtual;

		{Results}
{		procedure CalculateTotals;                       virtual; {Returns calc error if problem}

		{Display}
		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;

		procedure SetFormCodes(const FormCodes: PFormCodeCollection); virtual;

		{DataBase}
		function RecSize : word; virtual;
		function srType : word; virtual;

		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream);              virtual;

		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView); virtual;
	end;

type
	PMatShopSetup = ^TMatShopSetup;
	TMatShopSetup = object(TSetup)
		DefaultCurtainType : TSCode;
		DefaultMake : TSCode;
		DefaultFabricWidth : TLength;
		DefaultSideHems : TLength;
		DefaultLiningTBHem : TLength;
		DefaultLiningSideHem : TLength;
		RoundOff : word;

		procedure Load; virtual;
		procedure Store; virtual;
		procedure AddSetupLines(EditBox : PEditBox); virtual;
	end;

procedure EditMatShopSetup;

	{**********************************************
	 ***             SUPPLEMENTARY SCODES       ***
	 **********************************************}
	{Header short codes - with gathering added}
type
	PHeaderSCodeItem = ^THeaderSCodeItem;
	THeaderSCodeItem = object(TScodeItem)
		GathLo : integer;
		GathHi : integer;
		Hem : TLength;
		constructor Init(const NCode, NDesc : string);
		constructor Load(var S : TDataStream);
		procedure Store(var S : TDataStream);
		function DisplayLine(Maxlen : integer) : string; virtual;
		procedure AddEditFields(P : PObjectEditBox);           virtual;
	end;

	{FabricQuote type short codes - with price of making & usual amount of material}
	PFQSCodeItem = ^TFQSCodeItem;
	TFQSCodeItem = object(TCostedScodeItem)
		DefaultLength : TLength;
		constructor Init(const NCode, NDesc : string);
		constructor Load(var S : TDataStream);
		procedure Store(var S : TDataStream);
		function DisplayLine(Maxlen : integer) : string; virtual;
		procedure AddEditFields(P : PObjectEditBox);           virtual;
	end;


var
	MatshopSetup : TMatShopSetup;
	CalcErr : word;


IMPLEMENTATION

uses inpdnt, dialogs, minilib,
			kamsetup,
			tui, tuijimmy, tuimsgs,
			help,
			lstrings,
			kdirctry,
			app, {for desktop}
			tasks, menus;

var
	RepeatFabricID : longint;

{**********************************************
 ***                                        ***
 ***           MATSHOP  SET UP              ***
 ***                                        ***
 **********************************************}
const
	siDefCurtainType 	= 'Default Curtain Type';
	siDefMake 				= 'Default Curtain Making';
	siDefFabricWidth 	= 'Default Fabric Width';
	siDefSideHems			= 'Default Side Hem';
	siDefLiningTBHem	= 'Default Lining T/B Hem';
	siDefLiningSideHem= 'Default Lining Side Hem';
	siCQRounding			= 'Round off';

	{Rounding off constants}
	roNone = 0;
	roMeters = 1;
	roHalfMeters = 2;
	ro10cm = 3;

procedure EditMatShopSetup;
begin MatShopSetUp.Edit; end;

procedure TMatShopSetup.Load;
begin
	with ProgramSetup do begin
		DefaultCurtainType 	:= 					Get(siDefCurtainType,'');
		DefaultMake 				:= 					Get(siDefMake,'');
		DefaultFabricWidth.	SetToString(Get(siDefFabricWidth,''));
		DefaultSideHems.		SetToString(Get(siDefSideHems,''));
		DefaultLiningTBHem.	SetToString(Get(siDefLiningTBHem,''));
		DefaultLiningSideHem.SetToString(Get(siDefLiningSideHem,''));
		RoundOff 						:= S2Num(	Get(siCQRounding,''));
		SetGroup('');
	end;
end;


procedure TMatShopSetup.Store;
begin
	with ProgramSetup do begin
		Put(siDefCurtainType, 	DefaultCurtainType);
		Put(siDefMake, 					DefaultMake);
		Put(siDefFabricWidth,		DefaultFabricWidth.	Text(unAuto,dcAuto,0));
		Put(siDefSideHems,			DefaultSideHems.		Text(unAuto,dcAuto,0));
		Put(siDefLiningTBHem, 	DefaultLiningTBHem.	Text(unAuto, dcAuto, 0));
		Put(siDefLiningSideHem, DefaultLiningSideHem.Text(unAuto,dcAuto,0));
		Put(siCQRounding, 			N2Str(RoundOff));
		SetGroup('');
		Store;
	end;
end;

{============ EDIT ======================}
procedure TMAtshopsetup.AddSetupLines(EditBox : PEditBox);
var R : TRect;
begin
	with EditBox^ do begin
		GrowTo(46,17);

		InsTitledField(26,  2,10, 1, 'Default Curtain ~T~ype', New(PinputSCode, init(R, scCQType)));
		InsTitledField(26,  3,10, 1, 'Default Curtain Making', New(PInputSCode, init(R, scMaking)));
		InsTitledField(26,  4, 6, 1, 'Default Fabric ~W~idth', New(PInputLength, init(R, 6)));
		InsTitledField(26,  5, 6, 1, 'Default Side Hem', New(PInputLength, init(R, 6)));
		InsTitledField(26,  6, 6, 1, 'Default TB Lining Hem', New(PinputLength, init(R, 6)));
		InsTitledField(26,  7, 6, 1, 'Default Side Lining Hem', New(PinputLength, init(R, 6)));

		InsTitledField(26,  9,14, 4, 'Fabric ~R~ound off',
							New(PRadioButtons, init(R,	NewSItem('~N~one',
																					NewSITem('~M~eter',
																					NewSITem('~H~alf Meter',
																					NewSITem('~1~0cm',
							nil)))))));

		Insert(New(PSetupButton, init(1,14, '~M~easures', @MeasuresSetup)));{}

	end;
end;


{************************************************************************
 ***                                                                  ***
 ***                MATERIAL SHOP CALCULATIONS                        ***
 ***                                                                  ***
 ************************************************************************}

{=================== WIDTHS FROM FLAT, PATTERNLESS PANEL =====================}

{Work out number of widths from a flat panel, given "width" the width of the
panel, "FabricWidth", the width of the fabric.  Return "ExactNumWidths" (eg
2.1235) and the rounded up "NumWidths".{}

procedure CalculateNumFlatWidths(const Width, FabricWidth : TLength; var ExactNumWidths : single; var NumWidths : byte);
begin
	CalcErr := 0;

	if FabricWidth.inmm=0 then begin
		CalcErr := 1;
		ExactNumWidths := 0;
		NumWidths := 0;
	end else begin
		{Calculate no widths - Round up Curtain Width / Fabric Width to nearest 1/2}
		ExactNumWidths := Width.inmm / FabricWidth.inmm;
		if trunc(ExactNumWidths)<>ExactNumWidths then
			NumWidths := trunc(ExactNumWidths+1)  {ie, if any remainder, add one}
		else
			NumWidths := trunc(ExactNumWidths);
	end;
end;

{================== WIDTHS FROM HEADED, PATTERNLESS PANEL ======================}

{Pass Width and FabricWidth as above, and "Gathering" word as percentage
gathering (100% = flat).  Returns as above}

procedure CalculateNumHeadedWidths(Width, FabricWidth : TLength; Gathering : word;
																		var ExactNumWidths : single; var NumWidths : byte);
begin
	Width.Settomm(Width.inmm * Gathering div 100);

	CalculateNumFlatWidths(Width, FabricWidth, ExactNumWidths, NumWidths);
end;

{================== CUT DROP FROM PATTERNED MATERIAL ===========================}

{Rounds up made drop to whole number of fabric repeats}

procedure CalculateCutDrop(const MadeDrop, FabricPatRpt  :TLength; var CutDrop : Tlength);
begin
	if (FabricPatRpt.inmm >0) then
		{Move UP to next whole PatternRepeat - even if exact match}
		CutDrop.SetTomm(trunc(MadeDrop.inmm/FabricPatRpt.inmm +1) * FabricPatRpt.inmm)
	else
		CutDrop.SetTo(MadeDrop);
end;


{---- Total Length of Material -----}
{Work out length of material required for NumWidths of curtain, Drop depth, with Fabric of Pattern repeat}
{Note drop will be with hem - ie made drop + hems}
procedure CalculateFabricLength(const NumWidths : byte; MadeDrop, FabricPatRpt : TLength; var FabricLength : TLength);
var CutDrop : TLength;
begin
	CalculateCutDrop(MadeDrop, FabricPatRpt, CutDrop);

	FabricLength.Settomm(CutDrop.inmm * NumWidths);  {Round up - see extras - to nearest 10cm}
end;


{Work out length of material required to fill a square Drop x Width with Material of Width & Pattern repeat}
procedure CalculateFlatFabricFill(const Drop, Width, FabricWidth, FabricPatRpt : TLength; var FabricLength : Tlength);
var NumWidths : byte;
		ExactNumWidths : single;
begin
	CalculateNumFlatWidths(Width, FabricWidth, ExactNumWidths, NumWidths);

	CalculateFabricLength(NumWidths, Drop, FabricPatRpt, FabricLength);
end;

{General curtain calculator.  Work out length of material required to fill
a square box Drop x Width, adding top/bottom & side hems & gathering, o/w as above}

{NOTE THAT Side hems should cover all side hems within square - eg if curtain
made in a pair, need twice the side hem to allow for the cut in the middle}
procedure CalculateCurtainFill(const TBHem, SideHem : TLength; const Gathering : word;
																const Drop, Width, FabricWidth, FabricPatRpt : TLength;
																var FabricLength : Tlength);
begin
	Width.Settomm((Width.inmm + SideHem.inmm)*Gathering div 100);
	Drop.SetTomm(Drop.inmm + TBHem.inmm);

	CalculateFlatFabricFill(Drop, Width, FabricWidth, FabricPatRpt, FabricLength);
end;

{==== PLEATS ===========================}
procedure CalculatePleats(const RailWidth, FlatWidth, SideHem, Return,PleatGap : TLength;
													var NumPleats : byte; var PleatWidth, PleatStart : TLength);
var SurplusWidth : TLength;
begin
	{---pleat gap calculations---}
	{User wants to know: Distance to first pleat from edge of material,
	then marking start and end points for each pleat, ie flat pleat gap and width}
	{So want to work out:
		1) How many pleats required
		2) Width of material gathered into each pleat
		3) Distance to first pleat}
	if PleatGap.inmm >0 then begin
		{surplus material beyond rail width (for a flat curtain) that is therefore
		available for gathering up into pleats}
		SurplusWidth.SetTomm(FlatWidth.inmm - SideHem.inmm - RailWidth.inmm - Return.inmm);

		{#pleats in used width - starting half a pleat gap in}
		NumPleats := trunc((FlatWidth.inmm-SurplusWidth.inmm-(PleatGap.inmm/2))/PleatGap.inmm);

		{Width of material used for each individual pleat}
		PleatWidth.SetTomm(round(SurplusWidth.inmm/NumPleats));
		PleatStart.Settomm(SideHem.inmm + Return.inmm + (PleatGap.inmm div 2));

		{set units to same as gap}
		PleatWidth.SetUnits(PleatGap.Units);
		PleatStart.SetUnits(PleatGap.Units);

	end else begin
		NumPleats := 0;
		PleatWidth.Clear;
		PleatStart.Clear;
	end;
end;




{************************************************************************
 ***                                                                  ***
 ***                FABRIC GOODS                                      ***
 ***                                                                  ***
 ************************************************************************}
constructor TFabric.Init;
begin
	inherited Init;
	Name := '';
	Colour := '';
	Collection := '';
	SupplierID := -1;
	SupplierCode := '';
	Width.Clear;
	Width.Setto(MatShopSetup.DefaultFabricWidth);
	PatternRepeat.Clear;
	PricepM.Clear;
end;

function TFabric.MakeInputGroup;
var R : TRect;
		InputGroup : PInputGroup;
begin
	R.XYLD(X,Y,20,9);
	InputGroup := New(PJimmyInputGroup, init(R,srFabric));

	with InputGroup^ do begin
		{Tall, narrow block}
		R.XYLD(1, 1,14,1); Insert(New(PInputELine, Init(R, 20))); AddLabel('~F~abric Name',Current);
		R.XYLD(1, 2,12,1); Insert(New(PInputELine, Init(R, 12))); AddLabel('Colour',Current);
		R.XYLD(1, 3,12,1); Insert(New(PInputELine, Init(R, 12))); AddLabel('Collection',Current);
{$IFDEF kdirctry}
		R.XYLD(1, 4,14,1); Insert(New(PInputDirectory, init(R, 20, fiFullDirIdx, lsDirectory, 'SUP')));
		AddLabel( 'Supplier',Current);
{$ELSE}
		Insert(New(PSkipBytes, init(4)));
{$ENDIF}
		R.XYLD(1, 5,20,1); Insert(New(PInputELine, Init(R, 20))); AddLabel('Code',Current);

		R.XYLD(1, 6, 6,1); Insert(New(PInputLength, Init(R, 6))); AddLabel('Width',Current);
{		WidthLine := PINputLength(Current);{}
		R.XYLD(1, 7, 6,1); Insert(New(PInputLength, Init(R, 6))); AddLabel('Pat Rpt',Current);
{		PatRptLine := PINputLength(Current);{}
		R.XYLD(1, 8, 6,1); Insert(New(PinputMoney, Init(R)));  AddLabel('Price/m',Current);
{		PriceLine := PINputMoney(Current);{}
	end;
end;

function TFabric.RecSize : word;
begin RecSize := 150; end;

function TFabric.srType : word;
begin srType := srFabric; end; {for identifying in hooking, etc}

procedure TFabric.StoreFields;
var Ver : byte;
begin
	Ver := 1; S.Write(Ver, 1);

	inherited StoreFields(S);

	S.WriteStr(@Name);
	S.WriteStr(@Colour);
	S.WriteStr(@Collection);
	S.Write(SupplierID, 4);
	S.WriteStr(@SupplierCode);

	Width.Store(S);
	Pricepm.Store(S);
	PatternRepeat.Store(S);
end;

procedure TFabric.Load;
var Ver : byte;
begin
	S.Read(Ver, 1);
	case Ver of
		1 : begin

			inherited Load(S);

			Name 		:= S.ReadStr;
			Colour 	:= S.ReadStr;
			Collection := S.REadStr;
			S.Read(SupplierID, 4);
			SupplierCode := S.ReadStr;
			Width.Load(S);
			Pricepm.Load(S);
			PatternRepeat.Load(S);
		end;
	else
		ProgramError('Unrecognised version:'+N2Str(Ver)+#13#10'TFabric.Load', hcInternalErrorMsg);
	end;
end;

function TFabric.NumixTypes : byte;
begin
	NumixTypes := 1;
end;

procedure TFabric.GetIndex(const ixType : byte; var IdxRec : Plongint; var fiType : byte);
begin
	inherited GetIndex(ixType, IdxRec, fiType);
	case ixType of
		1 : begin IdxRec := @FabricIdx; fiType := fiFabricIdx; end;
	end;
end;

function TFabric.GetIndexKey(const ixType : byte) : string;
begin
	GetIndexKey := '';
	case ixType of
		1 : GetIndexKey := Name;
	end;
end;

procedure TFabric.SetFormCodes;
begin
	with FormCodes^ do begin
		SetStr('NAME', Name);
		SetStr('COL', Colour);
		SetStr('CLL', Collection);
		SetStr('WID', Width.Text(unAuto, dcAuto, 0));
		SetStr('PAT', PatternRepeat.Text(unAuto, dcAuto, 0));

		Insert(New(PMoneyFormCode, init('PPM', Pricepm)));
		Insert(New(PJimmyFormCode, init('SUP', SupplierID)));

		SetStr('CODE', SupplierCode);
	end;
end;

{****************************************************
 ***                                              ***
 ***               INPUT FABRIC  DEF              ***
 ***                                              ***
 ****************************************************}

type
	{expects data to be a longint ID ptr}
	PInputFabric = ^TInputFabric;
	TInputFabric = object(TJimmyInputGroup)
		FabricOWner : PJimmy; {probably an order item descendant, eg cqaccessory}

		PatRptLine : PView;
		WidthLine : PView;
		PricepmLine : PView;

		constructor Init(X,Y : byte; NFabricOwner : PJimmy);
		procedure HandleEvent(var Event : TEvent); virtual;
		procedure ExecuteList(const ListAddOwner : PJimmy);
		procedure InsertEditFields; virtual;

		procedure MakeInitParam(var InitParam : TJimmyInitParam); virtual;
		procedure SetForWho; virtual; {*MUST* be overriden}
	end;

constructor TInputFabric.Init;
var R : TRect;
begin
	R.XYLD(X,Y,20,9);
	inherited Init(R,srFabric);

	FabricOwner := NFabricOwner;
end;

procedure TInputFabric.SetForWho;
begin
{	if PFabric(Jimmy)^.ForWho = -1 then PAddress(Jimmy)^.ForWho := AddressOwner^.RecNo;{}
end;

procedure TInputFabric.MakeInitParam;
begin
	inherited MakeInitParam(Initparam); {clear}
	if FabricOwner<>nil then InitParam.ForWho := FabricOwner^.RecNo;
end;

procedure TInputFabric.HandleEvent;
begin
	inherited HandleEvent(Event);

	if (Owner^.Phase = phFocused) then begin

		if (Event.What = evKeydown) and (Event.KeyCode = kbList) then begin
			ClearEvent(Event);
			ExecuteList(FabricOwner);
		end;

		if (Event.COmmand=cmAcceptJimmy) and GetState(sfSelected) then begin
			{$IFDEF fixit}
				Owner^.SetData(FabricOwner^); {update any changes - ie ptr2addresses}
				Owner^.ReDraw;
			{$ENDIF}

			{accept address from list}
			Owner^.Lock;
			SetChanged;
			SetData(Event.InfoPtr);
			ReDraw;
			Owner^.Unlock;

			ClearEvent(Event);
		end;
	end;

end;

procedure TInputFabric.InsertEditFields;
var R : TRect;
begin
	HelpCtx := hcFabric;

	inherited InsertEditFields;

	{Skip admin stuff}
	Insert(New(PSkipBytes, init(sizeof(TJimmy))));
	R.XYLD(10, 0, 20,1); Insert(New(PInputELine, init(R,20))); AddLabel('Fabric', Current);
	R.XYLD(10, 1, 12,1); Insert(New(PInputELine, init(R,12))); AddLabel('Colour', Current);
	R.XYLD(10, 2, 12,1); Insert(New(PInputELine, init(R,12))); AddLabel('Cllction', Current);
	R.XYLD(10, 3, 20,1); Insert(New(PInputDirectory, init(R, 30, fiFullDirIdx, lsDirectory, 'SUP')));
																															AddLabel('Supplier', Current);
	R.XYLD(10, 4, 20,1); Insert(New(PInputELine, init(R,20))); AddLabel('Sup Code', Current);
	R.XYLD(10, 5, 10,1); Insert(New(PInputLength, init(R,10))); AddLabel('Width', Current); 	WidthLine 	:= Current;
	R.XYLD(10, 6, 10,1); Insert(New(PInputLength, init(R,10))); AddLabel('Pat Rpt', Current); PatRptLine 	:= Current;

	R.XYLD(10, 7, 10,1); Insert(New(PInputMoney, init(R))); AddLabel('Price/m', Current); 		PricepmLine := Current;

	SelectNext(False); {move to first one}
end;

procedure TInputFabric.ExecuteList;
begin end;




{********************************************************************
 ***                                                              ***
 ***            CQ ACCESSORY (EG TIE BACK)                        ***
 ***                                                              ***
 ********************************************************************}

function CreateCQAccessory(P : pointer) : pointer; far;
begin	CreateCQAccessory := New(PCQAccessory, init(P)); end;

{--- Inititalise - set ptrs to SC ---}
constructor TCQAccessory.Init;
begin
	inherited Init(nil);

	Quantity := 1;
	FabricLength.Clear;
	FabricID := RepeatFabricID;  {Set to last lot of fabrics used}
end;

{--- Set SCode Collection Pointers ----}
{Has to be separate so it can be used after a Get to tell it where
the existing code collections are located}
procedure TCQAccessory.CommonInit;
begin
	inherited CommonInit;
	New(Notes, init);
	SCodeCollection[scCQAccessory]^.LogOn;
	Fabric := nil;
end;

destructor TCQAccessory.Done;
begin
	SCodeCollection[scCQAccessory]^.LogOff;
	dispose(Notes, done);
	inherited Done;
end;

{*************************************************
 ***              CALCULATIONS                 ***
 *************************************************}

procedure TCQAccessory.CalculateWorkingValues;
begin
end;

{procedure TCQAccessory.CalculateTotals;
var Money : TMoney;
begin
	MOney.SetTo(MakingPrice); Money.MultiplyBy(Quantity);
	PriceGroup.SubTotal.SetTo(TotalFabricPrice);
	PriceGroup.SubTotal.Add(Money);

	PriceGroup.CalculateFromPrice; {work out VAT, etc}
{end;{}



{*********************************************
 ** DISPLAY LINE FOR LISTS                 ***
 *********************************************}
function TCQAccessory.DisplayLine;
var S :string;
begin
	S := expandscode(scCQAccessory, Code);

	if Quantity >1 then S := S +' x'+N2Str(Quantity);

	S := S + ' ('+FabricLength.Text(unAuto, dcAuto, 0)+' '+GetJimmyIDName(FabricID, naDisplay,0)+')';

	DisplayLine := Setlength(S, Maxlen);
end;

function TCQAccessory.GetFabric;
var Param : TJimmyInitParam;
begin
	if Fabric=nil then
		Fabric := PFabric(GetJimmy(FabricID));

	{safety check}
	if (Fabric<>nil) and (Fabric^.srType<>srFabric) then begin
		ProgramError('Fabric ID ('+N2Str(FabricID)+') not Fabric object, sr='+N2Str(Fabric^.srType),hcNoContext);
		dispose(Fabric, done);
		Param.ForWho := RecNo;
		FabricID := -1;
		Fabric := nil; {New(PFabric, init(@Param));{}
	end;

	GetFabric := Fabric;{}
end;

{*****************************************
 ***        SCREEN INPUT BOX           ***
 *****************************************}
{===== SPecial boxes for below =====}
{Takes length (source 1) and price per meter (source 2) and sets total
price (target 1)}
procedure LinkPriceLength(const Linker : PInputLinker; const CallingView : PView); far;
var L : TLength;
		M : TMoney;

begin
	M.Init;
	with Linker^ do begin
		SourceView[1]^.GetData(L);
		SourceView[2]^.GetData(M);

		M.MultiplyBy(L.inMeters);
		with TargetView[1]^ do begin
			SetData(M);
			DrawView;
		end;
	end;
	M.Done;
end;

{Takes FQ SCode type from source[1] and sets length used target[2] from it
(for automatic standard lengths)}
procedure LinkCodeLength(const Linker : PInputLinker; const CallingView : PView); far;
var SCode : PScodeItem;
		S : TScode;
begin
	with Linker^ do begin
		SourceView[1]^.GetData(S);
		Scode := GetScode(scCQAccessory, S);
		if SCode<>nil then
			TargetView[1]^.SetData(PFQSCodeItem(SCode)^.DefaultLength);
	end;
end;


procedure TCQAccessory.MakeEditBox;
var
	R: TRect;
	Control : word;
	TypeLine : PView;
	FabLine, FabLenLine, LinLine, LinLenLine, IntLine, IntLenLine : PView;
	MakingPriceLine : PView;
	PriceLengthLinker,CodeLengthLinker : PInputLinker;

begin
	R.Assign(0, 0, 47, 18);

	EditBox := New(PJimmyEditBox, Init(R, 'Fabric Item',Caller,@Self));

	New(PriceLengthLinker, init(@LinkPriceLength, EditBox));
	New(CodeLengthLinker, init(@LinkCodeLength, EditBox));

	{----Position box, in centre of calling view----}
	with EditBox^ do begin
		Insert(New(PSkipBytes, init(sizeof(TOrderItem)-sizeof(TPriceGroup))));  {Skip detail fields & VMT}

		Insert(New(PInputPriceGroup, init(Size.X-30,Size.Y-7, EditBox))); {for prices, vat, etc}

		{-- Buttons --}
		{inserted here so after price group}
		Insert(New(PJimmyOKButton, Init(2,Size.Y-5, @Self)));
		Insert(New(PjimmyCancelButton, init(2,Size.Y-3, @Self)));

		InsTitledField(13, 1,30, 1, '~T~ype',       New(PInputSCode, init(R, scCQAccessory)));
		TypeLine := Current;
		InsTitledField(13, 2, 3, 1, '~Q~uantity',   New(PInputByte, init(R, 3)));

		{Fabric}
		Insert(New(PInputFabric, init(13,4, @Self)));
		InsTitledField(13,11, 6, 1, '~L~ength', New(PinputLength, init(R, 6))); FabLenLine := Current;

		InsTitledField(36,10, 8, 1, 'Fabric ~T~otal', New(PinputMoney, init(R)));

		{Price Making}
		InsTitledField(36,11, 8, 1,'~M~aking Price', New(PInputMoney, init(R))); MakingPriceLine := Current;

		InsTitledField( 7,13,25, 3, '~N~otes', New(PInputFreeText, Init(R, 150, 0, nil)));
		Current^.GrowMode := 0;

		{-- Buttons --}
		Insert(New(PJimmyOKButton, 			init(Size.X-12,Size.Y-5, @Self)));
		Insert(New(PJimmyCancelButton, 	init(Size.X-12,Size.Y-3, @Self)));

		{Set links}

		EndInit;
	end;
end;


{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}
function TCQAccessory.RecSize : word;
begin RecSize := 170; end; {gives record size}

function TCQAccessory.srType : word;
begin srType := srCQAccessory; end; {for identifying in hooking, etc}

const
	{--- Required for Stream ----}
	RCQAccessory : TStreamRec = (
		ObjType : srCQAccessory;
		VmtLink : Ofs(TypeOf(TCQAccessory)^);
		Load : @TCQAccessory.Load;
		Store : @TCQAccessory.Store
	);

constructor TCQAccessory.Load(var S : TDataStream);
var Ver : byte; {local so that inherited Load does not overwrite}
begin
	S.Read(Ver, 1);

	case Ver of
		4 : begin
			{v4.3, descended from orderitem jimmy}
			inherited Load(S);
			S.Read(Code, sizeof(Code));
			S.Read(Quantity, 1);

			S.Read(FabricID,4);
			S.Read(FabricLength, sizeof(FabricLength));
			TotalFabricPrice.Load(S);

			MakingPrice.Load(S);

			Notes^.Load(S);
		end;
	else
		ProgramError('Unrecognised CQAccessory Version:'+N2Str(Ver), hcInternalErrorMsg); {case}
	end;

end;

procedure TCQAccessory.StoreFields(var S : TDataStream);
var	Ver : byte;

begin
	Ver := 4; S.Write(Ver, 1);

	inherited StoreFields(S);

	S.Write(Code, sizeof(Code));
	S.Write(Quantity, 1);

	S.Write(FabricID, 4);
	S.Write(FabricLength, sizeof(FabricLength));
	TotalFabricPrice.Store(S);

	MakingPrice.Store(S);

	Notes^.Store(S);
end;



{***************************************************
 ***       SET STANDARD FORM CODES               ***
 ***************************************************}
procedure TCQAccessory.SetFormCodes;
begin
	inherited SetFormCodes(FormCodes); {calculate done in here?}

	with FormCodes^ do begin
		SetStr('TYPE',ExpandSCode(scCQAccessory, Code));
		SetStr('QTY', N2Str(QUantity));
		Insert(NEw(PFreeTextFormCode, init('NOTE', Notes^)));

		{General text to fit with standard invoice forms - notes}
		SetStr('TEXT', LS2String(Notes^.Text));

		SetStr('FABLEN', FabricLength.Text(unAuto, dcAuto +dcBlankZero, 0));

		Insert(New(PJimmyFormCode, init('FABRIC', FabricID)));
	end;
end;

{*******************************************
 *** PRINT SUMMARY (FOR QUOTE)           ***
 *******************************************}

{function TCQAccessory.Print;
begin
	Print := cmCancel;
	SetFormCodes(Output, nil);

	if (prType and pmPrintAs)=0 then begin
		{"Print" pressed from nodeviewer - do worksheet with its own header}
{    ThinkingOn('Printing');
		Output^.StartPrint('','FABRICWS');
		if not Output^.FormFound then Output^.PrintForm('CQUOTEWS'); {default to curtainquote header}
{		PrintTree(prWorkSheet + (prType and pmScope) + (prType and pmTarget), Output, @Self); {print self & descendants}
{		Output^.EndPrint;
		ThinkingOff;
	end;

	if (prType and prWorkSheet)>0 then Output^.PrintForm('FABRICWS.FRM');
	if (prType and prEstimate)>0 then Output^.PrintForm('FABRICEI.FRM'); {Curtain estimate item}

{	if ((prType and prInvoice)>0) or
			(((prType and prEstimate)>0) and not Output^.FormFound) then Output^.PrintForm('FABRICII.FRM');
end;


{*****************************************************
 ***           SPECIAL short CODES              ***
 *****************************************************}

{===== Header short Code ===================}
constructor THeaderScodeItem.Init;
begin
	inherited Init(NCode, NDesc);
	GathLo := 100;
	GathHi := 100;
	Hem.Clear;
end;

constructor THeaderSCodeItem.Load;
begin
	inherited Load(S);
	S.Read(GathLo, 2);
	S.Read(GathHi, 2);
	Hem.Load(S);
end;

procedure THeaderSCodeItem.Store;
begin
	inherited Store(S);
	S.Write(GathLo, 2);
	S.Write(GathHi, 2);
	Hem.Store(S);
end;

function THeaderSCodeItem.DisplayLine;
var S : string;
		SS : string;
begin
	S := inherited DisplayLine(Maxlen);
	SS := N2Str(GathLo); if (GathHi<>0) and (GathHi<>GathLo) then SS := SS+'-'+N2Str(GathHi);
	SS := SS +'%';
	DisplayLine := SetLength(S, Maxlen-length(SS))+SS;
end;

procedure THeaderSCodeItem.AddEditFields(P : PObjectEditBox);
var R : TRect;
begin
	inherited AddEditFields(P);
	P^.GrowTo(P^.Size.X, P^.Size.Y+2); {make room for extra fields}
	P^.InsTitledField(9, 4, 3, 1, '%Gath', 	New(PInputInt, init(R,3)));
	P^.InsTitledField(17,4, 3, 1,'-', 			New(PInputInt, init(R,3)));
	P^.InsTitledField(9, 5, 6, 1, 'T+B Hem',New(PInputLength, init(R,6)));
end;

function CreateHeaderScodeItem(const NCode, NDesc : string) : PScodeItem; far;
begin
	CreateHeaderSCodeItem := New(PHeaderScodeItem, init(NCode, NDesc));
end;


{===== FabricQuote short Code ===================}

constructor TFQSCodeItem.Init;
begin
	inherited Init(NCode, NDesc);
	DefaultLength.Clear;
end;

constructor TFQSCodeItem.Load;
begin
	inherited Load(S);
	DefaultLength.Load(S);
end;

procedure TFQSCodeItem.Store;
begin
	inherited Store(S);
	DefaultLength.Store(S);
end;

function TFQSCodeItem.DisplayLine;
var S : string;
		SS : string;
begin
	S := PadSpaceR(Code,4) + Description^;
	SS := Cost.Text(mtValue)+' '+DefaultLength.Text(unAuto, dcAuto,0);

	DisplayLine := SetLength(S, Maxlen-length(SS))+SS;
end;

procedure TFQSCodeItem.AddEditFields(P : PObjectEditBox);
var R : TRect;
begin
	inherited AddEditFields(P);
	P^.GrowTo(P^.Size.X, P^.Size.Y+1); {make room for extra fields}
	P^.InsTitledField(9,5,  6, 1, 'Fabric', New(PInputLength, init(R,6)));
end;

function CreateFQSCodeItem(const NCode, NDesc : string) : PScodeItem; far;
begin
	CreateFQSCodeItem := New(PFQSCodeItem, init(NCode, NDesc));
end;



{********************************************************************
 ***                                                              ***
 ***             CURTAIN QUOTE ITEM DEFINITION                    ***
 ***                                                              ***
 ********************************************************************}
function CreateCQPanel(P : pointer) : pointer; far;
begin	CreateCQPanel := New(PCQPanel, init(P)); end;

{--- Inititalise - set ptrs to SC ---}
constructor TCQPanel.Init;
var Focused : PJimmy;
		CQUote : PCurtainQuote;
		CQFabric : PFabric;
begin
	inherited Init(Param);

	{Set defaults}
	Quantity := 1;
	Code := '';
	MakingType := MatshopSetup.DefaultMake;

	Height.Clear;
	Width.Clear;

	TBHem.Clear;
	SideHem.SetTo(MatshopSetup.DefaultSideHems);
	PleatGap.Clear;

	CutDrop.Clear;
	FabricID := RepeatFabricID;

	if Param<>nil then with Param^ do begin
		if FocusedID<>-1 then begin
			Focused := GetJimmy(FocusedID);
			{Check focused - if a curtain, assume this is a border - set drop & width to same to be re-set}
			if (Focused <> nil) and (typeof(Focused^)=typeof(TCurtainQuote)) then begin
				CQuote := PCurtainQuote(Focused);
				CQFabric := PFabric(GetJimmy(CQuote^.FabricID));
				FabricID := CQuote^.FabricID;
				Width.SetTomm((CQuote^.NumWidths * CQFabric^.Width.inmm div CQuote^.NoCurtspW)
												-CQuote^.SideHem.inmm);
				Width.SetUnits(CQuote^.RailWidth.Units);
				Height.SetTo(CQuote^.Drop);
				Quantity := CQuote^.Quantity * CQuote^.NoCurtspW;

				dispose(CQFabric, done);
			end;
			if Focused<>nil then dispose(Focused, done);
		end;
	end;

end;

{--- Set SCode Collection Pointers ----}
{Has to be separate so it can be used after a Get to tell it where
 the existing code collections are located}
procedure TCQPanel.CommonInit;
begin
	inherited CommonInit;
	SCodeCollection[scCQAccessory]^.LogOn;
	SCodeCollection[scHeading]^.LogOn;
	SCodeCollection[scMaking]^.LogOn;
	Fabric := nil;
end;

destructor TCQPanel.Done;
begin
	SCodeCollection[scCQAccessory]^.LogOff;
	SCodeCollection[scHeading]^.LogOff;
	SCodeCollection[scMaking]^.LogOff;
	inherited Done;
end;

{*************************************************
 ***              CALCULATIONS                 ***
 *************************************************}
procedure TCQPanel.CalculateWorkingValues;
var FlatWidth, Return : TLength; {for purposes of this item, there is no return to wall/etc}

begin
	{--- Useful running calculations ----}
	{Gathering}
{  HeaderSCodeItem := PHeaderSCodeItem(GetScode(scHeadings, Heading));
	if HeaderSCodeItem <> nil then
		Gathering := {not really all that useful - maybe at some time may work
		out *actual* gathering?}

	{cut drop might be useful for worksheet, etc}
	CalculateCutDrop(Height, GetFabric^.PatternRepeat, CutDrop);

	TotalFabricPrice.SetTo(GetFabric^.Pricepm);
	TotalFabricPrice.MultiplyBy(FabricLength.inMeters);
	TotalMakingPrice.SetTo(PriceMakingpW);
	TotalMakingPrice.MultiplyBy(NumWidths);

	{---pleat gap calculations---}
	Return.Clear;
	FlatWidth.SetTomm(round(GetFabric^.Width.inmm * NumWidths)); {ie when material laid out flat on table}
	CalculatePleats(Width, FlatWidth, SideHem, Return,PleatGap, NumPleats, PleatWidth, PleatStart);
end;

{procedure TCQPanel.CalculateTotals;
begin
	CalculateWorkingValues;

	Total.SetToPence(TotalFabricPrice.inPence + Quantity*TotalMakingPrice.inPence);

	inherited CalculateTotals; {work out VAT, etc}
{end;{}


{*********************************************
 ** DISPLAY LINE FOR LISTS                 ***
 *********************************************}
function TCQPanel.DisplayLine;
var S :string;
begin
	S := ExpandSCode(scCQAccessory, Code);
	if Quantity >1 then S := S + ' x'+N2Str(Quantity);

	S := S + ' ('+FabricLength.Text(unAuto, dcAuto, 0)+' '+GetFabric^.Name+')';

	DisplayLine := S;
end;

function TCQPanel.GetFabric;
var Param : TJimmyInitParam;
begin
	if Fabric=nil then
		Fabric := PFabric(GetJimmy(FabricID));

	{safety check}
	if (Fabric<>nil) and (Fabric^.srType<>srFabric) then begin
		ProgramError('Fabric ID ('+N2Str(FabricID)+') not Fabric object, sr='+N2Str(Fabric^.srType),hcNoContext);
		dispose(Fabric, done);
		Param.ForWho := RecNo;
		FabricID := -1;
		Fabric := nil; {New(PFabric, init(@Param));{}
	end;

	GetFabric := Fabric;{}
end;

{*****************************************
 ***        SCREEN INPUT BOX           ***
 *****************************************}
{==== Top & Bottom Hem - picks up "default" from heading ======}
{takes heading scode source[1] and sets hem line target[1]}
procedure LinkHeaderHem(const Linker : PInputLinker; const CallingView : PView); far;
var	Header : PSCodeItem;
begin
	Header := GetScode(scHeading, PInputSCode(Linker^.SourceView[1])^.Data^);
	if Header<>nil then begin
		Linker^.TargetView[1]^.SetData(PHeaderSCodeItem(Header)^.Hem);
		Linker^.TargetView[1]^.DrawView;
	end;
end;

{==== Number of Widths calculation & entry/override box ======}
{takes "Rail" Width source[1], sidehem source[2], fabric width source[3] and
 heading scode source[4], and works out width range string target[1] and
 number widths byte target[2]}
procedure LinkNumWidthsCalc(const Linker : PInputLinker; const CallingView : PView); far;
var
	ExactNumLo, ExactNumHi : single;
	Gathering : word;
	HeadingItem : PScodeItem;
	Width, SideHem, FabricWidth : TLength;
	WholeNumHi, WholeNumLo : byte;
	GathHi,GathLo : word;
	S : string;

begin
	with Linker^ do begin
		SourceView[1]^.GetData(Width);
		SourceView[2]^.GetData(SideHem);
		SourceView[3]^.GetData(FabricWidth);
		HeadingItem := GetSCode(scHeading, PInputScode(SourceView[4])^.Data^);

		if HeadingItem<>nil then begin
			GathHi := PHeaderSCodeItem(HeadingItem)^.GathHi;
			GathLo := PHeaderSCodeItem(HeadingItem)^.GathLo;
		end else begin
			GathHi := 100;
			GathLo := 100;
		end;

		{Set up for calc}
		Width.Settomm(Width.inmm + SideHem.inmm);

		{work out no. widths for hi & lo gathering range - see procedure in this unit}
		CalculateNumHeadedWidths(Width, FabricWidth, GathLo, ExactNumLo, WholeNumLo);
		CalculateNumHeadedWidths(Width, FabricWidth, GathHi, ExactNumHi, WholeNumHi);

		{set up text for range}
		if TargetView[1]<>nil then begin
			S := {L2Str(Gathering)+'% }'('+R2Str(ExactNumLo, dcUpTo+1,0);
			if ExactNumHi<>0 then S := S+'-'+R2Str(ExactNumHi, dcUpTo+1,0); {if high range gathering not entered, don't do anything}
			S := S + ')';
			DisposeStr(PStaticText(TargetView[1])^.Text);
			PStaticText(TargetView[1])^.Text := NewStr(S);
			TargetView[1]^.DrawView;
		end;

		{now guesstimate what WholeNum should be set to}
		{Should just be WholeNumLo...}
		TargetView[2]^.SetData(WholeNumLo);
		TargetView[2]^.DrawView;

		{Work out actual gathering}
		{unused at the moment... not that important
		Gathering := round(100*(WholeNumLo*FabricWidth.inMeters)/Width.inMeters);{}
	end;
end;

{============ FABRIC LENGTH Calculation and entry/override box =============}
{takes drop length source[1], tob/bot hems source[2], pattern repeat source[3]
 num widths source[4] quantity source[5] (optional) and calculates fabric length}
procedure LinkFabricLengthCalc(const Linker : PInputLinker; const CallingView : PView); far;
var	Drop, TBHem, PatRpt : TLength;
		Quantity, NumWidths : byte;
		FabricLength : TLength;

begin
	with Linker^ do begin
		{Set parameters for working out length}
		SourceView[1]^.GetData(Drop);
		SourceView[2]^.GetData(TBHem);
		SourceView[3]^.GetData(PatRpt);
		SourceView[4]^.GetData(NumWidths);
		if SourceView[5]<>nil then SourceView[5]^.GetData(Quantity) else Quantity := 1;

		Drop.Settomm(Drop.inmm + TBHem.inmm);

		{work out no. widths for hi & lo gathering range - see procedure in this unit}
		CalculateFabricLength(NumWidths, Drop, PatRpt, FabricLength);

		FabricLength.Settomm(FabricLength.inmm * Quantity);

		{Round off as per setup}
		case MatshopSetup.RoundOff of
			roMeters 			: FabricLength.SettoMeters(roundup(FabricLength.inMeters));
			roHalfMeters 	:	FabricLength.SettoMeters(roundup(FabricLength.inMeters*2)/2);
			ro10cm 				: FabricLength.SettoMeters(roundup(FabricLength.inMeters*10)/10);
		end;

		TargetView[1]^.SetData(FabricLength);
		TargetView[1]^.DrawView;
	end;
end;


procedure TCQPanel.MakeEditBox;
var
	R: TRect;
	TBHemLinker,NumWidthsLinker, FabricLengthLinker,MakingCostLinker : PInputLinker;
	HeadingCodeLine, MakingCodeLine : PInputSCode; {For link}
	DropLine, WidthLine, TBHemLine, SideHemLine : PInputLength;
	InputFabric : PInputFabric;

begin
	R.Assign(0, 0, 61, 18);

	EditBox := New(PJimmyEditBox, Init(R, 'FabricQuote',Caller, @Self));

	New(TBHemLinker, init(@LinkHeaderHem, EditBox));
	New(NumWidthsLinker, init(@LinkNumWidthsCalc, EditBox));
	New(FabricLengthLinker, init(@LinkFabricLengthCalc, EditBox));
	New(MakingCostLinker, init(nil, EditBox));

	with EditBox^ do begin
		HelpCtx := hcEditBox;

		Options := Options or ofCenterX or ofCenterY;
		Insert(New(PSkipBytes, init(sizeof(TOrderItem){-sizeof(Date)})));
		{--- Set up box interior ---}

		InsTitledField(14, 1,17, 1, '~T~ype',   New(PInputSCode, init(R, scCQAccessory)));
		InsTitledField(14, 2, 3, 1, '~Q~uantity',   New(PInputByte, init(R, 3)));
		FabricLengthLinker^.SetSourceView(Current, 5);

		InsTitledField(14, 4, 6, 1, '~D~rop',  New(PInputLength, Init(R, 6)));
		PInputELine(Current)^.MustInput := True;
		FabricLengthLinker^.SetSourceView(Current, 1);

		InsTitledField(14, 5, 6, 1, '~W~idth',   New(PInputLength, Init(R, 6)));
		PInputELine(Current)^.MustInput := True;
		NumWidthsLinker^.SetSourceView(Current, 1);

		New(InputFabric, init(14, 7, @Self)); Insert(InputFabric);
		NumWidthsLinker^.SetSourceView(InputFabric^.WidthLine, 3);
		FabricLengthLinker^.SetSourceView(InputFabric^.PatRptLine, 3);

		InsTitledField(41, 4,17, 1, '~M~aking', 		New(PInputSCOde, Init(R, scMaking)));
		MakingCostLinker^.SetSourceView(Current, 1);
		InsTitledField(41, 5,17, 1, '~H~eading',    New(PinputSCode, Init(R, scHeading)));
		TBHemLinker^.SetSourceView(Current, 1);
		NumWidthsLinker^.SetSourceView(Current, 4);

		InsTitledField(41, 7, 6, 1, 'T+B Hem',  		New(PInputLength, Init(R, 6)));
		TBHemLinker^.SetTargetView(Current,1);
		FabricLengthLinker^.SetSourceView(Current, 2);

		InsTitledField(41, 8, 6, 1, 'Side Hems',   	New(PInputLength, Init(R, 6)));
		NumWidthsLinker^.SetSourceView(Current, 2);

		InsTitledField(41,10, 3, 1, 'Widths', 		New(PinputByte, Init(R, 3)));
		NumWidthsLinker^.SetTargetView(Current, 2);
		FabricLengthLinker^.SetSourceView(Current, 4);

		{and set the widths range static text}
		R.XYLD(45, 10, 10, 1); Insert(New(PStaticText, init(R, '')));
		NumWidthsLinker^.SetTargetView(Current, 1);

		InsTitledField(41,11, 6, 1, 'Fabric ~L~ength', New(PInputLength, init(R, 6)));
		FabricLengthLinker^.SetTargetView(Current, 1);

		InsTitledField(41,13, 6, 1, 'Making/w',   New(PInputScodePrice, Init(R)));{}
		MakingCostLinker^.SetTargetView(Current, 1);

		InsTitledField(41,14, 6, 1, 'Pleat ~G~ap',  New(PInputLength, init(R, 6)));

		{-- Buttons --}
		Insert(New(PJimmyOKButton, 			init(Size.X-12,18, @Self)));
		Insert(New(PJimmyCancelButton, 	init(Size.X-12,20, @Self)));

		EndInit;

		{but make sure extra bits of numwidths line - gathering, etc - is recalced.
		Actual Data^ value will be overwritten below}
{		Message(NumWIdthsLine, evCommand, cmUpdateFromLink, nil);{}
	end;
end;


{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}
function TCQPanel.RecSize : word;
begin RecSize := 300; end; {gives record size}

function TCQPanel.srType : word;
begin srType := srCQPanel; end; {for identifying in hooking, etc}

const
	{--- Required for Stream ----}
	RCQPanel : TStreamRec = (
		ObjType : srCQPanel;
		VmtLink : Ofs(TypeOf(TCQPanel)^);
		Load : @TCQPanel.Load;
		Store : @TCQPanel.Store
	);

constructor TCQPanel.Load(var S : TDataStream);
var Ver : byte;
begin
	S.Read(Ver, 1);

	case Ver of
		1 : begin
			{v4.3}
			inherited Load(S);

			S.Read(COde, sizeof(Code));
			S.Read(Quantity, 1);
			S.Read(Height, sizeof(Height));
			S.Read(Width, sizeof(Width));

			S.Read(FabricID, 4);

			S.Read(MakingType, sizeof(MakingType));
			S.Read(Heading, sizeof(Heading));

			S.Read(TBHem, sizeof(TBHem));
			S.Read(SideHem,    sizeof(SideHem));

			S.Read(NumWidths, sizeof(NumWidths));

			FabricLength.Load(S);

			PriceMakingpW.Load(S);

			PleatGap.Load(S);
		end;
	else
		ProgramError('Unrecognised CQPanel version:'+N2Str(Ver), hcInternalErrorMsg); {case}
	end;

end;

procedure TCQPanel.StoreFields(var S : TDataStream);
var	Ver : byte;

begin
	Ver := 1; S.Write(Ver, 1);

	inherited Store(S);

	S.Write(Code, sizeof(Code));
	S.Write(Quantity, 1);
	S.Write(Height, sizeof(Height));
	S.Write(Width, sizeof(Width));

	S.Write(FabricID, 4);

	S.Write(MakingType, sizeof(MakingType));
	S.Write(Heading, sizeof(Heading));

	S.Write(TBHem , sizeof(TBHem));
	S.Write(SideHem,    sizeof(SideHem));

	S.Write(numWidths, sizeof(NumWidths));

	FabricLength.Store(S);

	PriceMakingpW.Store(S);

	PleatGap.Store(S);
end;


{***************************************************
 ***       SET STANDARD FORM CODES               ***
 ***************************************************}
procedure TCQPanel.SetFormCodes;
var	HeadingItem : PHeaderSCodeItem;
		S : string;

begin
	CalculateWorkingValues;

	inherited SetFormCodes(FormCodes);

	with FormCodes^ do begin
		Insert(New(PSCodeFormCode, init('TYPE', Code, scCQAccessory)));
		SetStr('QTY', N2Str(Quantity));

		{Measurements}
		SetStr('HEIGHT', Height.Text(unAuto, dcAuto, 0));
		SetStr('CUTDROP', CutDrop.Text(unAuto, dcAuto, 0));
		SetStr('WIDTH', Width.Text(unAuto, dcAuto, 0));

		{style}
		S := ExpandSCode(scMaking, MakingType);
		if ExpandSCode(scHeading, Heading)<>'' then S := S +', '+ExpandSCode(scHeading, Heading);
		SetStr('TEXT', S);

		{making details}
		SetStr('MAKING', ExpandSCode(scMaking, MakingType));
		SetStr('HEADING', ExpandSCode(scHeading, Heading));
		HeadingItem := PHeaderSCodeItem(GetSCode(scHeading, Heading));
		if HeadingItem<>nil then begin
			SetStr('HEADGATHLO',N2Str(HeadingItem^.GathLo));
			SetStr('HEADGATHHI',N2Str(HeadingItem^.GathHi));
    end else begin
			SetStr('HEADGATHLO','');
			SetStr('HEADGATHHI','');
		end;

		SetStr('WIDTHS', N2Str(NumWidths));

		SetStr('FABLEN', FabricLength.Text(unAuto, dcAuto +dcBlankZero, 0));

		SetStr('TBHem', TBHem.Text(unAuto, dcAuto, 0));
		SetStr('SHEM', SideHem.Text(unAuto, dcAuto, 0));

		SetStr('NUMPLEATS', N2Str(NumPleats));
		SetStr('PLEATWIDTH', PleatWidth.Text(unAuto, dcUpTo+3, 6));
		SetStr('PLEATGAP', PleatGap.Text(unAuto, dcUpTo+3, 6));
		SetStr('PLEATSTART', PleatSTart.Text(unAuto, dcUpTo+3, 6));

		Insert(New(PJimmyFormCode, init('FABRIC', FabricID)));
	end;
end;


{*******************************************
 *** PRINT SUMMARY (FOR QUOTE)           ***
 *******************************************}
{function TCQPanel.Print;
begin
	Print := cmCancel;
	SetFormCodes(Output, nil);

	if (prType and pmPrintAs)=0 then begin
		{"Print" pressed from nodeviewer - do worksheet with its own header}
{    ThinkingOn('Printing');
		Output^.StartPrint('','FQUOTEWS');
		if not Output^.FormFound then Output^.PrintForm('CQUOTEWS'); {default to curtainquote header}
{    PrintTree(prWorkSheet + (prType and pmScope) + (prType and pmTarget), Output, @Self); {print self & descendants}
{    Output^.EndPrint;
		ThinkingOff;

	end;

	if (prType and prWorkSheet)>0 then Output^.PrintForm('FQUOTEWS.FRM');
	if (prType and prEstimate)>0 	then Output^.PrintForm('FQUOTEEI.FRM');
	if (prType and prInvoice)>0 	then Output^.PrintForm('FQUOTEII.FRM');
end;

{********************************************************************
 ***                                                              ***
 ***             CURTAIN QUOTE ITEM DEFINITION                    ***
 ***                                                              ***
 ********************************************************************}
function CreateCurtainQuote(P : pointer) : pointer; far;
begin	CreateCurtainQuote := New(PCurtainQuote, init(P)); end;

{--- Inititalise - set ptrs to SC ---}
constructor TCurtainQuote.Init;
var SCode : PCostedSCodeItem;
begin
	inherited Init(Param);

	{Set defaults}
  Code := MatshopSetup.DefaultCurtainType;
	MakingType := MatshopSetup.DefaultMake;

	PriceMakingpW.Clear;
  if delspace(MakingType)<>'' then begin
		{get automatic making price pW}
		SCode := PCostedSCodeItem(GetSCode(scMaking, MakingType));
		if Scode<>nil then PriceMakingpW.Add(Scode^.Cost);
  end;

	Quantity := 1;
	NoCurtspW := 2;
	Drop.Clear;
	RailWidth.Clear;
	Return.Clear;
	Overlap.Clear;

  TBHem.Clear;
	SideHem.SetTo(MatshopSetup.DefaultSideHems);
	LiningTBHem.SetTo(MAtshopSetup.DefaultLiningTBHem);
  LiningSideHem.SetTo(MAtshopSetup.DefaultLiningTBHem);
	PleatGap.Clear;

	CutDrop.SetToMeters(0);

	FabricID := RepeatFabricID;
end;

{--- Set SCode Collection Pointers ----}
{Has to be separate so it can be used after a Get to tell it where
 the existing code collections are located}
procedure TCurtainQuote.CommonInit;
begin
	inherited CommonInit;
	SCodeCollection[scCQType]^.LogOn;
	SCodeCollection[scHeading]^.LogOn;
	SCodeCollection[scLining]^.LogOn;
	SCodeCollection[scMaking]^.LogOn;
	SCodeCollection[scInterlining]^.LogOn;
	Fabric := nil;
end;

destructor TCurtainQuote.Done;
begin
	SCodeCollection[scCQType]^.LogOff;
	SCodeCollection[scHeading]^.LogOff;
	SCodeCollection[scLining]^.LogOff;
	SCodeCollection[scMaking]^.LogOff;
	SCodeCollection[scInterlining]^.LogOff;
	inherited Done;
end;

{*************************************************
 ***              CALCULATIONS                 ***
 *************************************************}
procedure TCurtainQuote.CalculateWorkingValues;
var FlatWidth : TLength;
begin
	{cut drop might be useful for worksheet, etc}
	CalculateCutDrop(Drop, GetFabric^.PatternRepeat, CutDrop);

	TotalFabricPrice.SetTo(GetFabric^.Pricepm);
	TotalFabricPrice.MultiplyBy(FabricLength.inMeters);
	TotalMakingPrice.SetTo(PriceMakingpW);
	TotalMakingPrice.MultiplyBy(NumWidths);

	{---pleat gap calculations---}
	FlatWidth.SetTomm(round(GetFabric^.Width.inmm * NumWidths)); {ie when material laid out flat on table}
	CalculatePleats(HeadedWidth, FlatWidth, SideHem, Return,PleatGap, NumPleats, PleatWidth, PleatStart);
end;

{procedure TCurtainQuote.CalculateTotals;
begin
	CalculateWorkingValues;

	Total.SetToPence(TotalFabricPrice.inPence
									+TotalMakingPrice.inPence
									+TotalLiningPrice.inPence
                  +TotalInterliningPrice.inPence);

	inherited CalculateTotals;
end;


{*********************************************
 ** DISPLAY LINE FOR LISTS                 ***
 *********************************************}
function TCurtainQuote.DisplayLine;
var S :string;
begin
	S := ExpandSCode(scCQType, Code);

	if Quantity >1 then S := S +' x'+N2Str(Quantity);

	S := S + ' ('+FabricLength.Text(unAuto, dcAuto, 0)+' '+GetFabric^.Name+')';

	DisplayLine := S;
end;


{*********************************************************************
 ***                        SCREEN INPUT BOX                       ***
 *********************************************************************}
{======= CALCULATE LINING LENGTH  ==========}
{takes quantity source[1], lining tb hems source[2], drop length source[3]
and num widths source[4], and calcs lining length target[1]}
procedure LinkLiningLength(const Linker : PInputLinker; const CallingView : PView); far;
var	Drop, PatRpt : TLength;
		NumWidths : byte;
		LiningLength, LiningTBHem : TLength;
		Quantity : byte;

begin
	with Linker^ do begin
		{Set parameters for working out length}
		SourceView[1]^.GetData(Quantity);
		SourceView[2]^.GetData(LiningTBHem);
		SourceView[3]^.GetData(Drop);
		SourceView[4]^.GetData(NumWidths);

		{Set vars for calculation}
		PatRpt.Clear; {no pat rpt for lining!}
		Drop.Settomm(Drop.inmm + LiningTBHem.inmm);

		{work out no. widths for hi & lo gathering range - see procedure in this unit}
		CalculateFabricLength(NumWidths, Drop, PatRpt, LiningLength);

		LiningLength.SetTomm(LiningLength.inmm * Quantity);

		{Round off as per setup}
		case MatshopSetup.RoundOff of
			roMeters 			: LiningLength.SettoMeters(roundup(LiningLength.inMeters));
			roHalfMeters 	:	LiningLength.SettoMeters(roundup(LiningLength.inMeters*2)/2);
			ro10cm 				: LiningLength.SettoMeters(roundup(LiningLength.inMeters*10)/10);
		end;

		TargetView[1]^.SetData(LiningLength);
		TargetView[1]^.DrawView;
	end;
end;

{======= CALCULATE HEADED WIDTH  ==========}
{takes rail width source[1], return source[2], overlap source[3], quantity
of curtains per rail width source[4] and calcs headed width target[1]}
procedure LinkHeadedWidth(const Linker : PInputLinker; const CallingView : PView); far;
var	HeadedWidth, RailWidth, Return, Overlap : TLength;
		NumCurtspW : byte;

begin
	with Linker^ do begin
		{Set parameters for working out length}
		SourceView[1]^.GetData(RailWidth);
		SourceView[2]^.GetData(Return);
		SourceView[3]^.GetData(Overlap);
		SourceView[4]^.GetData(NumCurtspW);

		{work out total headed width - ie 2xreturns, rail width and appropriate overlaps}
		HeadedWidth.SetTomm(RailWidth.inmm + (2*Return.inmm) + ((NumCurtspW-1) * Overlap.inmm));
		HeadedWidth.SetUnits(RailWidth.Units);

		TargetView[1]^.SetData(HeadedWidth);
		TargetView[1]^.DrawView;
	end;
end;

{==== SET LINING PRICE ===========================}
{Takes lining code source[1] and lining length source[2] and calcs multiple target[1]}
procedure LinkLiningPrice(const Linker : PInputLinker; const CallingView : PView); far;
var	Length : TLength;
		Price : TMOney;
		SCodeItem : PSCodeItem;

begin
	with Linker^ do begin
		{Set parameters for working out length}
		SCodeItem := GetSCode(PInputSCode(SourceView[1])^.scType, PInputSCode(SourceView[1])^.Data^);
		SourceView[2]^.GetData(Length);

		{calculate total fabric price}
		if SCodeItem<>nil then begin
			Price.SetTo(PCostedSCodeItem(SCodeItem)^.Cost);
			Price.MultiplyBy(Length.inMeters);
			TargetView[1]^.SetData(Price);
			TargetView[1]^.DrawView;
		end;
	end;
end;


{========== CREATE EDITBOX ============================}
procedure TCurtainQuote.MakeEditBox;
var
	R: TRect;
	LiningLengthLinker, HeadedWidthLinker, FabricPriceLinker, LiningPriceLinker,
	FabricLengthLinker, NumWidthsLInker, InterLiningPriceLinker,
	MakingPriceLinker, HeaderHemLinker : PInputLinker;
	InputFabric : PInputFabric;

begin
	R.Assign(0, 0, 67, 22);

	EditBox := New(PJimmyEditBox, Init(R, 'CurtainQuote',Caller,@Self));

	New(FabricLengthLinker, init(@LinkFabricLengthCalc, EditBox));
	New(NumWidthsLinker, 		init(@LinkNumWidthsCalc, EditBox));
	New(LiningLengthLinker, init(@LinkLiningLength, EditBox));
	New(HeadedWidthLinker, 	init(@LinkHeadedWidth, EditBox));
	New(FabricPriceLinker, 	init(@LinkPriceLength, EditBox));
	New(LiningPriceLinker, 	init(@LinkLiningPrice, EditBox));
	New(InterLiningPriceLinker, 	init(@LinkLiningPrice, EditBox));
	New(MakingPriceLinker, 	init(nil, EditBox));
	New(HeaderHemLinker, 	init(@LinkHeaderHem, EditBox));

	with EditBox^ do begin
		HelpCtx := hcEditBox;

		Options := Options or ofCenterX or ofCenterY;
		Insert(New(PSkipBytes, init(sizeof(TOrderItem){-sizeof(Date)})));

		InsTitledField(14, 1,17, 1, '~T~ype',   	New(PInputSCode, init(R, scCQType)));
		InsTitledField(14, 2, 3, 1, '~Q~uantity', New(PInputByte, init(R, 3)));
		FabricLengthLinker^.SetSourceView(Current, 5);
		LiningLengthLinker^.SetSourceView(Current, 1);

		InsTitledField(14, 3, 3, 1, 'No per Win',   New(PInputByte, init(R, 3)));
		HeadedWidthLinker^.SetSourceView(Current, 4);

		InsTitledField(14, 5, 6, 1, '~D~rop',  New(PInputLength, Init(R, 6)));
		PInputEline(Current)^.MustInputtoClose := True;
		FabricLengthLinker^.SetSourceView(Current, 1);
		LiningLengthLinker^.SetSourceView(Current, 3);

		InsTitledField(14, 6, 6, 1, 'Rail ~W~idth',   New(PInputLength, Init(R, 6)));
		PInputELine(Current)^.MustInputtoClose := True;
		HeadedWidthLinker^.SetSourceView(Current, 1);
		InsTitledField(14, 7, 6, 1, 'Return', New(PInputLength, init(R, 6)));
		HeadedWidthLinker^.SetSourceView(Current, 2);
		InsTitledField(14, 8, 6, 1, 'Overlap', New(PInputLength, init(R, 6)));
		HeadedWidthLinker^.SetSourceView(Current, 3);
		InsTitledField(14, 9, 6, 1, 'Headed Width', New(PInputLength, init(R, 6)));
		HeadedWidthLinker^.SetSourceView(Current, 1);
		NumWidthsLinker^.SetSourceView(Current, 1);

		InputFabric := New(PInputFabric, init(14,11, @Self));	Insert(InputFabric);
		NumWidthsLinker^.SetSourceView(		InputFabric^.WidthLine, 	3);
		FabricLengthLinker^.SetSourceView(InputFabric^.PatRptLine, 	3);
		FabricPriceLinker^.SetSourceView(	InputFabric^.PricepmLine, 2);

		InsTitledField(14,19,17, 1, '~L~ining', 		New(PInputSCOde, Init(R, scLining)));
		LiningPriceLinker^.SetSourceView(Current, 1);

		InsTitledField(14,20,17, 1, '~I~nterlining',New(PInputSCOde, Init(R, scInterlining)));
		InterliningPriceLinker^.SetSourceView(Current, 1);

		InsTitledField(46, 2,17, 1, '~M~aking', 		New(PInputSCOde, Init(R, scMaking)));
		MakingPriceLinker^.SetSourceView(Current, 1);
		InsTitledField(46, 3,17, 1, '~H~eading',    New(PinputSCode, Init(R, scHeading)));
		NumWidthsLinker^.SetSourceView(Current, 4);
		HeaderHemLinker^.SetSourceView(Current, 1);

		InsTitledField(46, 5, 5, 1, 'Hems T+B',  		New(PInputLength, Init(R, 6)));
		HeaderHemLinker^.SetTargetView(Current, 1);
		FabricLengthLinker^.SetSourceView(Current, 2);

		InsTitledField(59, 5, 5, 1, 'Side',   	New(PInputLength, Init(R, 6)));
		NumWidthsLinker^.SetSourceView(Current, 2);

		InsTitledField(46, 6, 5, 1, 'Lining T+B', New(PInputLength, init(r, 6)));
		LiningLengthLinker^.SetSourceView(Current, 2);

		InsTitledField(59, 6, 5, 1, 'Side',   	New(PInputLength, Init(R, 6)));

		InsTitledField(41,10, 3, 1, 'Widths', 		New(PinputByte, Init(R, 3)));
		NumWidthsLinker^.SetTargetView(Current, 2);
		FabricLengthLinker^.SetSourceView(Current, 4);
		LiningLengthLinker^.SetSourceView(Current, 4);

		{and set the widths range static text}
		R.XYLD(45, 10, 10, 1); Insert(New(PStaticText, init(R, '')));
		NumWidthsLinker^.SetTargetView(Current, 1);

		InsTitledField(46, 9, 6, 1, '~L~ength: Fabric', New(PInputLength, init(R, 6)));
		FabricLengthLinker^.SetTargetView(Current, 1);
		FabricPriceLinker^.SetSourceView(Current,1 );

		InsTitledField(46,10, 6, 1,         'Lining', New(PInputLength, init(R, 6)));
		LiningLengthLinker^.SetTargetView(Current, 1);
		LiningPriceLinker^.SetSourceView(Current, 2);
		InterLiningPriceLinker^.SetSourceView(Current, 2);

		InsTitledField(46,12, 8, 1, '~P~rice: Fabric', New(PInputMoney, init(R)));
		FabricPriceLinker^.SetTargetView(Current, 1);

		InsTitledField(46,13, 8, 1,          'Lining', New(PInputMoney, init(R)));
		LiningPriceLinker^.SetTargetView(Current, 1);

		InsTitledField(46,14, 8, 1,     'Interlining', New(PInputMoney, init(R)));
		InterLiningPriceLinker^.SetTargetView(Current, 1);

		InsTitledField(46,16, 6, 1, 'Making/w',   		 New(PInputScodePrice, Init(R)));
		MakingPriceLInker^.SetTargetView(Current, 1);

		InsTitledField(46,17, 6, 1, 'Pleat ~G~ap',  New(PInputLength, init(R, 6)));

		{-- Buttons --}
		Insert(New(PJimmyOKButton, 			init(Size.X-12,18, @Self)));
		Insert(New(PJimmyCancelButton, 	init(Size.X-12,20, @Self)));
{		R.assign(34, 19, 44, 21);
		Insert(New(PSetupButton, init(R, 'Setup', cmNone, bfNormal, @MatShopSetup)));{}

		EndInit;
	end;
end;

{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}
function TCurtainQuote.RecSize : word;
begin RecSize := 300; end; {gives record size}

function TCurtainQuote.srType : word;
begin srType := srCurtainQuote; end; {for identifying in hooking, etc}

const
	{--- Required for Stream ----}
	RCurtainQuote : TStreamRec = (
		ObjType : srCurtainQuote;
		VmtLink : Ofs(TypeOf(TCurtainQuote)^);
		Load : @TCurtainQuote.Load;
		Store : @TCurtainQuote.Store
	);

constructor TCurtainQuote.Load(var S : TDataStream);
var Ver : byte;
begin
	S.Read(Ver, 1);

	case Ver of
		5 : begin
			{v4.3, fabric ID}
			inherited Load(S);

			Code := S.ReadFixedStr(3);
			S.Read(Quantity, 1);
			S.Read(NoCurtspW, 1);

			Drop.Load(S);
			RailWidth.Load(S);
			Return.Load(S);
			Overlap.Load(S);
			HeadedWidth.Load(S);

			S.Read(FabricID, 4);

			Lining := S.ReadFixedStr(3);
		  Interlining := S.ReadFixedStr(3);

			MakingType := S.ReadFixedStr(3);
			Heading := S.ReadFixedStr(3);

			TBHem.Load(S);
			SideHem.Load(S);
      LiningTBHem.Load(S);
      LiningSideHem.Load(S);

			S.Read(NumWidths, sizeof(NumWidths));

		  FabricLength.Load(S);
		  LiningLength.Load(S);

			TotalFabricPrice.Load(S);
		  TotalLiningPrice.Load(S);
		  TotalInterliningPrice.Load(S);

			PriceMakingpW.Load(S);

			PleatGap.Load(S);
		end;
	else
		ProgramError('Unrecognised CurtainQuote version:'+N2Str(Ver), hcInternalErrorMsg); {case}
	end;
end;

procedure TCurtainQuote.StoreFields(var S : TDataStream);
var
	Ver : byte;

begin
	Ver := 5; S.Write(Ver, 1);

	inherited StoreFields(S);

	S.WriteFixedStr(@Code, 3);
	S.Write(Quantity, 1);
	S.Write(NoCurtspW, 1);

	Drop.Store(S);
	RailWidth.Store(S);
	Return.Store(S);
	Overlap.Store(S);
	HeadedWidth.Store(S);

	S.Read(FabricID, 4);

	S.WriteFixedStr(@Lining, 3);
	S.WriteFixedStr(@Interlining, 3);

	S.WriteFixedStr(@MakingType, 3);
	S.WriteFixedStr(@Heading, 3);

	TBHem.Store(S);
	SideHem.Store(S);
	LiningTBHem.Store(S);
	LiningSideHem.Store(S);

	S.Write(NumWidths, sizeof(NumWidths));

	FabricLength.Store(S);
	LiningLength.Store(S);

	TotalFabricPrice.Store(S);
	TotalLiningPrice.Store(S);
	TotalInterliningPrice.Store(S);

	PriceMakingpW.Store(S);

	PleatGap.Store(S);
end;

function TCurtainQuote.GetFabric;
var Param : TJimmyInitParam;
begin
	if Fabric=nil then
		Fabric := PFabric(GetJimmy(FabricID));

	{safety check}
	if (Fabric<>nil) and (Fabric^.srType<>srFabric) then begin
		ProgramError('Fabric ID ('+N2Str(FabricID)+') not Fabric object, sr='+N2Str(Fabric^.srType),hcNoContext);
		dispose(Fabric, done);
		Param.ForWho := RecNo;
		FabricID := -1;
		Fabric := nil; {New(PFabric, init(@Param));{}
	end;

	GetFabric := Fabric;{}
end;

{***************************************************
 ***       SET STANDARD FORM CODES               ***
 ***************************************************}
procedure TCurtainQuote.SetFormCodes;
var S : string;
		Price : TMoney;
		HeadingItem : PHeaderSCodeItem;
begin
	CalculateWorkingValues;

	inherited SetFormCodes(FormCodes);

	with FormCodes^ do begin
		SetStr('TYPE',ExpandSCode(scCQType, Code));
		SetStr('QTY', N2Str(Quantity));

		{Measurements}
		SetStr('NOC', N2Str(NoCurtspW));
		SetStr('DROP', Drop.Text(unAuto, dcAuto, 0));
{		SetStr('CUTDROP', CutDrop.Text(unAuto, dcAuto, 0)); not stored so don't put in form}
		SetStr('RAIL', RailWidth.Text(unAuto, dcAuto, 0));

		{style}
		S := ExpandSCode(scMaking, MakingType);
		if ExpandSCode(scHeading, Heading)<>'' then S := S +', '+ExpandSCode(scHeading, Heading);
		if ExpandSCode(scLining,  Lining) <>'' then S := S +', '+ExpandSCode(scLining,  Lining);
		if ExpandSCode(scInterLining, InterLining)<>'' then S := S +', '+ExpandSCode(scInterLining, InterLining);
		SetStr('TEXT', S);

		{making details}
		SetStr('MAKING', ExpandSCode(scMaking, MakingType));
		SetStr('LINING', ExpandSCode(scLining, Lining));
		SetStr('INTERL', ExpandSCode(scInterLining, InterLining));
		SetStr('HEADING', ExpandSCode(scHeading, Heading));
		HeadingItem := PHeaderSCodeItem(GetScode(scHeading, Heading));
		if HeadingItem<>nil then begin
			SetStr('HEADGATHLO',N2Str(HeadingItem^.GathLo));
			SetStr('HEADGATHHI',N2Str(HeadingItem^.GathHi));
		end else begin
			SetStr('HEADGATHLO','');
			SetStr('HEADGATHHI','');
		end;

		SetStr('LINLEN', LiningLength.Text(unAuto, dcAuto +dcBlankZero, 0));
		SetStr('FABLEN', FabricLength.Text(unAuto, dcAuto +dcBlankZero, 0));

		SetStr('WIDTHS', N2Str(NumWidths));
		SetStr('NOWPC', R2Str(NumWidths/NoCurtspW, dcUpto+1,0));

		SetStr('TBHEM', TBHem.Text(unAuto, dcAuto, 0));
		SetStr('SHEM', SideHem.Text(unAuto, dcAuto, 0));
		SetStr('LINTBHEM', LiningTBHem.Text(unAuto, dcAuto, 0));
		SetStr('LINSHEM', LiningSideHem.Text(unAuto, dcAuto, 0));

		SetStr('NUMPLEATS', N2Str(NumPleats));
		SetStr('PLEATWIDTH', PleatWidth.Text(unAuto, dcUpTo+3, 6));
		SetStr('PLEATGAP', PleatGap.Text(unAuto, dcUpTo+3, 6));
		SetStr('PLEATSTART', PleatStart.Text(unAuto, dcUpTo+3, 6));

		Insert(New(PJimmyFormCode, init('FABRIC', FabricID)));
	end;
end;


{*******************************************
 *** PRINT SUMMARY (FOR QUOTE)           ***
 *******************************************}

{function TCurtainQuote.Print;
begin
	Print := cmCancel;
	SetFormCodes(Output, nil);

	if (prType and pmPrintAs)=0 then begin
		{"Print" pressed from nodeviewer - do worksheet with its own header}
{		ThinkingOn('Printing');
		Output^.StartPrint('','CQUOTEWS'); {default to curtainquote header}
{		PrintTree(prWorkSheet + (prType and pmScope) + (prType and pmTarget), Output, @Self); {print self & descendants}
{		Output^.EndPrint;
		ThinkingOff;
	end;

	if (prType and prWorkSheet)>0 then Output^.PrintForm('CQUOTEWS.FRM');
	if (prType and prEstimate)>0 	then Output^.PrintForm('CQUOTEEI.FRM');
	if (prType and prInvoice)>0 	then Output^.PrintForm('CQUOTEII.FRM');
end;



{********************************************************************
 ***                                                              ***
 ***              EDGING QUOTE ITEM DEFINITION                    ***
 ***                                                              ***
 ********************************************************************}
function CreateCQEdging(P : pointer) : pointer; far;
begin	CreateCQEdging := New(PCQEdging, init(P)); end;

{--- Inititalise - set ptrs to SC ---}
constructor TCQEdging.Init;
var Focused : PJimmy;
		CQUote : PCurtainQuote;
begin
	inherited Init(Param);

	Drop.Clear;
	Width.Clear;
	Position := poLeading; {default to leading edge}
	Quantity := 1;

	if Param<>nil then with Param^ do begin
		{check focused - if curtain, read in drop and width}
		if FocusedID<>-1 then Focused := GetJimmy(FocusedID);
		if (Focused <> nil) then begin
			if typeof(Focused^)=typeof(TCurtainQuote) then begin
				CQuote := PCurtainQuote(Focused);
				Width.SetTomm((CQuote^.NumWidths * CQuote^.GetFabric^.Width.inmm div CQuote^.NoCurtspW)
												-CQuote^.SideHem.inmm);
				Width.SetUnits(CQuote^.RailWidth.Units);
				Drop.SetTo(CQuote^.Drop);
				Quantity := CQuote^.Quantity * CQuote^.NoCurtspW;
			end;
			dispose(FOcused, done);
		end;
	end;
end;

{--- Set SCode Collection Pointers ----}
{Has to be separate so it can be used after a Get to tell it where
 the existing code collections are located}
procedure TCQEdging.CommonInit;
begin
  inherited CommonInit;
	SCodeCollection[scEdgings]^.LogOn;
end;

destructor TCQEdging.Done;
begin
	SCodeCollection[scEdgings]^.LogOff;
  inherited Done;
end;


{procedure TCQEdging.CalculateTotals;
begin
	if (Position = poLeading) or (Position = poTrailing) then begin

		Total.SetToPence(round(Quantity * Drop.inMeters * (Pricepm.inPence + MakingPricepm.inPence)));
	end else
		Total.SetToPence(round(Quantity * Width.inMeters * (Pricepm.inPence + MakingPricepm.inPence)));

	inherited CalculateTotals; {calculate VAT, etc}
{end;{}


{*********************************************
 ** DISPLAY LINE FOR LISTS                 ***
 *********************************************}
function TCQEdging.DisplayLine;
var S :string;
begin
	S := ExpandSCode(scEdgings, Code)+', ';

	case Position of
  	poLeading : S := S + 'Leading';
    poTrailing : S := S + 'Trailing';
		poTop : S := S + 'Top';
    poBottom : S := S + 'Bottom';
	end;

	if Quantity>1 then S := S + +' x'+N2Str(Quantity);

  DisplayLine := S;
end;


{*****************************************
 ***        SCREEN INPUT BOX           ***
 *****************************************}
procedure TCQEdging.MakeEditBox;
var
	R: TRect;
	Control : word;
	ResultsControl : word;
	CodeLine : PView; {For link}
	InputDrop : PView;
	INputWidth : PView;
	Radio : PView;
	MakingPriceLinker : PInputLinker;

begin
	R.Assign(0, 0, 61, 15);

	EditBox := New(PJimmyEditBox, Init(R, 'EdgingQuote',Caller,@Self));

	New(MakingPriceLinker, init(nil, EditBox));

	with EditBox^ do begin
		HelpCtx := hcEditBox;

		Options := Options or ofCenterX or ofCenterY;

		Insert(New(PSkipBytes, init(sizeof(TOrderItem))));

		{--- Set up box interior ---}

		InsTitledField(16, 1,17, 1, 'T~y~pe',   New(PInputSCode, init(R, scEdgings))); CodeLine := Current;
		MakingPriceLInker^.SetSourceView(Current, 1);

		InsTitledField(16, 2, 3, 1, '~Q~uantity', New(PinputByte, Init(R, 3)));

		InsTitledField(37, 1, 17, 4, 'Position',
			New(PERadioButtons, init(R, NewSItem('~L~eading',
																	NewSITem('~T~railing',
																	NewSItem('~B~ottom',
																	NewSItem('To~p~',
															nil))))))
		);

		InsTitledField(16, 6, 6, 1, 'Curtain ~D~rop',   New(PInputLength, Init(R, 6))); InputDrop := Current;
		InsTitledField(16, 7, 6, 1, '~W~idth',  New(PInputLength, Init(R, 6))); InputWidth := Current;

		InsTitledBox(37, 6,20, 1, 'Trim ~N~ame', 20);
		InsTitledBox(37, 7,20, 1, 'Colour', 20);
		InsTitledField(37, 8,8, 1, '~P~rice/m', New(PInputMoney, init(R)));

		InsTitledField(37, 10, 8, 1, '~M~aking price/m',   New(PInputScodePrice, Init(R)));{}
		MakingPriceLinker^.SetTargetView(Current, 1);

		{-- Buttons --}
		Insert(New(PJimmyOKButton, init(25,12, @Self)));
		Insert(New(PJimmyCancelButton, init(38,12, @Self)));

		EndInit;
	end;
end;


{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}
function TCQEdging.RecSize : word;
begin RecSize := 250; end; {gives record size}

function TCQEdging.srType : word;
begin srType := srFabric; end; {for identifying in hooking, etc}

const
	{--- Required for Stream ----}
	RCQEdging : TStreamRec = (
		ObjType : srCQEdging;
		VmtLink : Ofs(TypeOf(TCQEdging)^);
		Load : @TCQEdging.Load;
		Store : @TCQEdging.Store
	);

constructor TCQEdging.Load(var S : TDataStream);
var Ver : byte;
begin

	S.Read(Ver, 1);

	case Ver of
		1 : begin
			inherited Load(S);

			S.Read(COde, sizeof(Code));
    	S.Read(Position ,2 );

			Width.Load(S);
			Drop.Load(S);
      S.Read(Quantity, 1);

			S.Read(Name, sizeof(Name));
			S.Read(Colour, sizeof(Colour));
			Pricepm.Load(S);

      MakingPricepm.Load(S);
		end;
	else
		ProgramError('Unrecognised CQEdging version:'+N2Str(Ver), hcInternalErrorMsg); {case}
	end;
end;

procedure TCQEdging.StoreFields(var S : TDataStream);
var	Ver : byte;

begin
	Ver := 1; S.Write(Ver, 1);

	inherited StoreFields(S);

	S.Write(COde, sizeof(Code));
	S.Write(Position ,2 );

	Width.Store(S);
	Drop.Store(S);
	S.Write(Quantity, 1);

	S.Write(Name, sizeof(Name));
	S.Write(Colour, sizeof(Colour));
	Pricepm.Store(S);

	MakingPricepm.Store(S);
end;


{***************************************************
 ***       SET STANDARD FORM CODES               ***
 ***************************************************}
procedure TCQEdging.SetFormCodes;
var S : string;
begin
	inherited SetFormCodes(FormCodes);
	S := '';

	with FormCodes^ do begin
		SetStr('TYPE',ExpandSCode(scEdgings, Code));

		case Position of
			poTop			: begin S :='Top'; SetStr('LEN', Width.Text(unAuto, dcAuto, 0)); end;
			poBottom	: begin S :='Bottom';  SetStr('LEN', Width.Text(unAuto, dcAuto, 0)); end;
			poLeading	: begin S :='Leading';  SetStr('LEN', Drop.Text(unAuto, dcAuto, 0)); end;
			poTrailing : begin S :='Trailing'; SetStr('LEN', Drop.Text(unAuto, dcAuto, 0)); end;
    end;
		SetStr('POS',S);

    {Style}
    if delspace(Name)<>'' then S := S + ', '+Name;
    if delspace(Colour)<>'' then S := S +', '+Colour;
		SetStr('TEXT', S);

		SetStr('QTY', N2Str(Quantity));

		SetStr('NAME', Name);
		SetStr('COL', Colour);
		SetStr('PRICE', Pricepm.Text(mtValue));


		SetStr('MAKPR', MakingPricepm.Text(mtValue));

	end;
end;


{*******************************************
 *** PRINT SUMMARY (FOR QUOTE)           ***
 *******************************************}

{function TCQEdging.Print;
var S :string;

begin
	Print := cmCancel;
	SetFormCodes(Output, nil);

	if ((prType and pmPrintAs)=0) then begin
		{"Print" pressed from nodeviewer - do worksheet with its own header}
{		ThinkingOn('Printing');
		Output^.StartPrint('','EDGEWS');
		if not Output^.FormFound then Output^.PrintForm('CQUOTEWS'); {default to curtainquote header}
{		PrintTree(prWorkSheet + (prType and pmScope) + (prType and pmTarget), Output, @Self); {print self & descendants}
{		Output^.EndPrint;
		ThinkingOff;
	end;

	if (prType and prWorkSheet)>0 then Output^.PrintForm('EDGEWS.FRM'); {worksheet}
{	if (prType and prEstimate)>0 	then Output^.PrintForm('EDGEEI.FRM'); {Edging estimate item}

{	if ((prType and prInvoice)>0) or not Output^.FormFOund then Output^.PrintForm('EDGEII.FRM'); {Edging estimate item}
{end;

{**************************************
 ***       INITIALISER              ***
 **************************************}
const
 RHeaderSCode : TStreamRec = (
	 ObjType : srHeaderSCodeItem;
	 VmtLink : Ofs(TypeOf(THeaderSCodeItem)^);
	 Load : @THeaderSCodeItem.Load;
	 Store : @THeaderSCodeItem.Store
 );

const
 RFQSCode : TStreamRec = (
	 ObjType : srFQSCodeItem;
	 VmtLink : Ofs(TypeOf(TFQSCodeItem)^);
	 Load : @TFQSCodeItem.Load;
	 Store : @TFQSCodeItem.Store
 );

begin
	{----For FabricQuote stuff---}
	New(SCodeCollection[scCQAccessory],Init('CQAcsry.SC', 'CQ Types', CreateFQSCodeItem));
	New(SCodeCollection[scCQPanel],Init('CQPanel.SC', 'CQ Descriptions', StdSCodeCreator));{}

	{registration of straightforward fabricitem}
	RegisterJimmy(RCQAccessory, CreateCQAccessory, lsInvoiceItems,'~A~ccessory');
	RegisterNewWithList(lsEstimateItems, '~A~ccessory', cmNewCQAccessory);

	{registration of calculated fabricitem}
	RegisterJimmy(RCQPanel, CreateCQPanel, lsInvoiceItems, '~P~anelQuote');
	RegisterNewWithList(lsEstimateItems, '~P~anelQuote', cmNewCQPanel);

	{----For curtain item---}
	New(SCodeCollection[scCQType],Init('CQType.SC', 'CurtainQuote Types', StdSCodeCreator));
	New(SCodeCollection[scHeading],Init('Headings.SC', 'Headings', CreateHeaderSCodeItem));
	New(SCodeCollection[scLining],Init('Linings.SC', 'Linings', CostedScodeCreator));
	New(SCodeCollection[scMaking],Init('Makings.SC', 'Makings', CostedScodeCreator));
	New(SCodeCollection[scInterlining],Init('IntrLngs.SC', 'Interlinings', CostedScodeCreator));

	{Register item with invoice}
	RegisterJimmy(RCurtainQuote, CreateCurtainQuote, lsInvoiceItems, 'Curtain~Q~uote');
	RegisterNewWithList(lsEstimateItems, 'Curtain~Q~uote', cmNewCurtainQuote);

	{----For edging item---}
	New(SCodeCollection[scEdgings],Init('EDGINGS.SC', 'Edgings', CostedSCodeCreator));

	{Register item with invoice}
	RegisterJimmy(RCQEdging, CreateCQEdging, lsInvoiceItems, '~E~dging');
	RegisterNewWithList(lsEstimateItems, '~E~dging', cmNewCQEdging);

	{--- Setup ----}
	MatShopSetup.Init('CurtainQuote');

{	AppMenuBar^.Add2SubMenu(mnMaintenance, mnSetup,
		NewItem('Curtain~Q~uote', '', kbNone, cmEditMatShopSetup, hcNoContext,
	nil));
	RegisterTask(DesktopTasks, cmEditMatShopSetup, EditMatShopSetup);

	{--- Initialise Repeat Fabric ----}
	RepeatFabricID :=-1;

	RegisterType(RHeaderSCOde);
	RegisterType(RFQSCOde);
end.
