{************************************************************************* Copyright (c) PilotLogic Software House Package pl_ExAvionics This file is part of CodeTyphon Studio (https://www.pilotlogic.com/) ***** BEGIN LICENSE BLOCK ***** * Version: LGPL-2.1 with link exception (Modified LGPL) * (licence inchangée - voir original) * ***** END LICENSE BLOCK ***** Anti-flash PATCH: - Added BeginUpdate / EndUpdate - Replaced Refresh with Invalidate in all SetXxx (Refresh = Invalidate + Synchronous Update → 1 repaint per property) (Invalidate = deferred repaint, merged by message handler) - Fixed the FUpdateReq bug (useless flag in the original) ***************************************************************************} Unit ExAvionicHSI; {$MODE objfpc}{$H+} Interface Uses LCLIntf, LCLType, SysUtils, Classes, Graphics, Controls, Forms; Const Radian = 180.0 / pi; Type TCourseMode = (cmOff, cmTo, cmFrom, cmNoDir); TExAvionicHSI = Class(TGraphicControl) Private fBearing: Integer; fCompass: Integer; fCourse1: Integer; fCourse2: Integer; fCourseMode1: TCourseMode; fCourseMode2: TCourseMode; fDeviation: Integer; fHeading: Integer; fBorderStyle: TBorderStyle; fFullBearing: Boolean; fBackColor: TColor; fBearingColor: TColor; fCardinalColor: TColor; fCourse1Color: TColor; fCourse2Color: TColor; fHeadingColor: TColor; fLubberColor: TColor; fScaleColor: TColor; FUpdateReq: Boolean; // PATCH : compteur de verrou pour BeginUpdate/EndUpdate FUpdateLock: Integer; // PATCH anti-flash : bitmap hors-écran persistant FOffscreenBitmap: TBitmap; Procedure PaintBackground(AnImage: TBitmap); Procedure PaintHSIimage(AnImage: TBitmap; PaintRect: TRect); Procedure SetBorderStyle(Value: TBorderStyle); Procedure SetBackColor(Colour: TColor); Procedure SetBearingColor(Colour: TColor); Procedure SetCardinalColor(Colour: TColor); Procedure SetCourse1Color(Colour: TColor); Procedure SetCourse2Color(Colour: TColor); Procedure SetHeadingColor(Colour: TColor); Procedure SetLubberColor(Colour: TColor); Procedure SetScaleColor(Colour: TColor); Procedure SetBearing(Value: Integer); Procedure SetFullBearing(Mode: Boolean); Procedure SetCompass(Value: Integer); Procedure SetCourse1(Value: Integer); Procedure SetCourse2(Value: Integer); Procedure SetCourseMode1(Value: TCourseMode); Procedure SetCourseMode2(Value: TCourseMode); Procedure SetDeviation(Value: Integer); Procedure SetHeading(Value: Integer); // PATCH : Invalidate conditionnel (ignoré si verrou actif) Procedure SafeInvalidate; Protected Procedure Paint; Override; Public Constructor Create(AOwner: TComponent); Override; Destructor Destroy; Override; // PATCH : grouper plusieurs affectations en un seul repaint Procedure BeginUpdate; Procedure EndUpdate; Published Property Align; Property Anchors; Property BorderStyle: TBorderStyle read fBorderStyle write SetBorderStyle Default bsNone; Property BackColor: TColor read fBackColor write SetBackColor Default clBlack; Property BearingColor: TColor read fBearingColor write SetBearingColor Default clRed; Property CardinalColor: TColor read fCardinalColor write SetCardinalColor Default clAqua; Property Course1Color: TColor read fCourse1Color write SetCourse1Color Default clAqua; Property Course2Color: TColor read fCourse2Color write SetCourse2Color Default clFuchsia; Property HeadingColor: TColor read fHeadingColor write SetHeadingColor Default clYellow; Property LubberColor: TColor read fLubberColor write SetLubberColor Default clWhite; Property ScaleColor: TColor read fScaleColor write SetScaleColor Default clLime; Property Constraints; Property Enabled; Property Font; Property ParentColor; Property ParentFont; Property ParentShowHint; Property PopupMenu; Property Bearing: Integer read fBearing write SetBearing Default 0; Property Compass: Integer read fCompass write SetCompass Default 0; Property Heading: Integer read fHeading write SetHeading Default 0; Property FullBearing: Boolean read fFullBearing write SetFullBearing Default True; Property Course1: Integer read fCourse1 write SetCourse1 Default 0; Property Course2: Integer read fCourse2 write SetCourse2 Default 0; Property CourseMode1: TCourseMode read fCourseMode1 write SetCourseMode1 Default cmOff; Property CourseMode2: TCourseMode read fCourseMode2 write SetCourseMode2 Default cmOff; Property Deviation: Integer read fDeviation write SetDeviation Default 0; Property ShowHint; Property Visible; Property OnClick; Property OnDblClick; Property OnPaint; Property OnResize; Property OnChangeBounds; Property OnContextPopup; Property OnEndDrag; Property OnMouseDown; Property OnMouseUp; Property OnMouseEnter; Property OnMouseLeave; Property OnMouseMove; Property OnMouseWheel; Property OnMouseWheelDown; Property OnMouseWheelUp; Property OnMouseWheelHorz; Property OnMouseWheelLeft; Property OnMouseWheelRight; Property OnDragDrop; Property OnDragOver; Property OnStartDrag; Property OnStartDock; Property OnEndDock; End; Implementation Const SOutOfRange = 'Out Of Range'; Type TBltBitmap = Class(TBitmap) Procedure MakeLike(ATemplate: TBitmap); End; Procedure TBltBitmap.MakeLike(ATemplate: TBitmap); Begin Width := ATemplate.Width; Height := ATemplate.Height; Canvas.Brush.Color := clWindowFrame; Canvas.Brush.Style := bsSolid; Canvas.FillRect(Rect(0, 0, Width, Height)); End; Constructor TExAvionicHSI.Create(AOwner: TComponent); Begin Inherited Create(AOwner); ControlStyle := ControlStyle + [csFramed, csOpaque]; fBearing := 0; fCompass := 0; fCourse1 := 0; fCourse2 := 0; fDeviation := 0; fHeading := 0; fFullBearing := True; fCourseMode1 := cmNoDir; fCourseMode2 := cmOff; fBorderStyle := bsNone; fBackColor := clBlack; fBearingColor := clRed; fCardinalColor := clAqua; fCourse1Color := clAqua; fCourse2Color := clFuchsia; fHeadingColor := clYellow; fLubberColor := clWhite; fScaleColor := clLime; Font.Color := clWhite; Font.Style := [fsBold]; Font.Size := 12; Width := 301; Height := 301; FUpdateReq := True; FUpdateLock := 0; // PATCH // PATCH : bitmap hors-écran persistant pour éliminer le flash noir FOffscreenBitmap := TBitmap.Create; End; // PATCH : destructeur pour libérer le bitmap hors-écran Destructor TExAvionicHSI.Destroy; Begin FOffscreenBitmap.Free; Inherited Destroy; End; // PATCH : Paint réécrit — un seul Canvas.Draw à la fin, zéro flash noir Procedure TExAvionicHSI.Paint; Var OverlayImage : TBltBitmap; PaintRect : TRect; Begin // Redimensionner le bitmap hors-écran si la taille a changé If (FOffscreenBitmap.Width <> Self.Width) Or (FOffscreenBitmap.Height <> Self.Height) Then Begin FOffscreenBitmap.Width := Self.Width; FOffscreenBitmap.Height := Self.Height; FUpdateReq := True; End; PaintRect := ClientRect; If fBorderStyle = bsSingle Then InflateRect(PaintRect, -1, -1); // Composition entièrement hors-écran PaintBackground(FOffscreenBitmap); OverlayImage := TBltBitmap.Create; OverlayImage.Canvas.Font := Font; Try OverlayImage.MakeLike(FOffscreenBitmap); PaintBackground(OverlayImage); PaintHSIimage(OverlayImage, PaintRect); FOffscreenBitmap.Canvas.CopyMode := cmSrcInvert; FOffscreenBitmap.Canvas.Draw(0, 0, OverlayImage); FOffscreenBitmap.Canvas.CopyMode := cmSrcCopy; Finally OverlayImage.Free; End; // UN SEUL appel à Canvas.Draw → zéro flash, zéro clignotement Canvas.CopyMode := cmSrcCopy; Canvas.Draw(0, 0, FOffscreenBitmap); End; // PATCH : BeginUpdate — suspend les repaints Procedure TExAvionicHSI.BeginUpdate; Begin Inc(FUpdateLock); End; // PATCH : EndUpdate — déclenche un seul repaint si nécessaire Procedure TExAvionicHSI.EndUpdate; Begin If FUpdateLock > 0 Then Dec(FUpdateLock); If FUpdateLock = 0 Then Begin FUpdateReq := True; Invalidate; // un seul repaint asynchrone pour toutes les modifs End; End; // PATCH : remplace les appels directs à Refresh dans les SetXxx // Si un BeginUpdate est actif, on mémorise le besoin sans repeindre Procedure TExAvionicHSI.SafeInvalidate; Begin FUpdateReq := True; If FUpdateLock = 0 Then Invalidate; // asynchrone : fusionné par le gestionnaire de messages // NOTE : on n'appelle plus Refresh (= Invalidate + Update synchrone forcé) // qui causait 1 repaint complet par propriété modifiée End; Procedure TExAvionicHSI.PaintBackground(AnImage: TBitmap); Var ARect: TRect; Begin With AnImage.Canvas Do Begin CopyMode := cmBlackness; ARect := Rect(0, 0, Width, Height); CopyRect(ARect, Animage.Canvas, ARect); CopyMode := cmSrcCopy; End; End; Procedure TExAvionicHSI.PaintHSIimage(AnImage: TBitmap; PaintRect: TRect); Var Radius: Integer; Xmid: Integer; Ymid: Integer; Sector: Boolean; Procedure DrawCompassRose(Compass: Integer); Var Count: Integer; Brg: Integer; Angle: Integer; Cangle: Integer; AngStr: String; Th: Integer; R2, R3, R4: Real; RX, RY: Real; RX2, RY2: Real; Procedure AngleTextOut(CV: TCanvas; Const sText: String; X, Y, ang: Integer); Var LogFont: TLogFont; hOldFont: HFont; hNewFont: HFont; Begin While ang > 360 Do ang := ang - 360; While ang < 0 Do ang := ang + 360; GetObject(CV.Font.Handle, sizeof(LogFont), Addr(LogFont)); With Logfont Do Begin lfEscapement := ang * 10; lfPitchAndFamily := FF_DONTCARE; End; hNewFont := CreateFontIndirect(LogFont); SetBkMode(CV.Handle, TRANSPARENT); hOldFont := SelectObject(CV.Handle, hNewFont); CV.TextOut(X, Y, sText); hNewFont := SelectObject(CV.Handle, hOldFont); DeleteObject(hNewFont); End; Procedure TextXY(Var RX, RY: Real; Angle, W, H: Integer); Var Ang: Real; Begin While angle > 270 Do angle := angle - 360; While angle < -90 Do angle := angle + 360; Ang := (Angle + 90) / Radian; RX := RX + W * Cos(ang) / 2; RY := RY - W * Sin(ang) / 2; End; Begin With AnImage.Canvas Do Begin Pen.Color := fScaleColor; Pen.Width := 2; Ellipse(Xmid - Radius, Ymid - Radius, Xmid + Radius, Ymid + Radius); Pen.Width := 2; Th := Canvas.TextHeight('00'); R2 := Radius - Th; R3 := Radius - Th / 2; R4 := Radius - Th * 2; Ellipse(Xmid - Round(R4), Ymid - Round(R4), Xmid + Round(R4), Ymid + Round(R4)); Pen.Width := 1; For Count := 0 To 71 Do Begin Angle := Count * 5; Cangle := -(Angle + Compass); Brg := 450 - Angle; While Brg >= 360 Do Brg := Brg - 360; RY2 := Ymid + R2 * Sin(Cangle / Radian); If RY2 > AnImage.Height Then continue; RX2 := Xmid + R2 * Cos(Cangle / Radian); RX := Xmid + Radius * Cos(Cangle / Radian); RY := Ymid + Radius * Sin(Cangle / Radian); MoveTo(Trunc(RX), Trunc(RY)); If Brg Mod 90 = 0 Then Begin Font.Size := 12; Font.Color := fCardinalColor; Case Brg Div 90 Of 0: AngStr := 'N'; 1: AngStr := 'E'; 2: AngStr := 'S'; 3: AngStr := 'W'; End; End Else Begin Font.Color := fLubberColor; If Brg Mod 30 = 0 Then Begin If fFullBearing Then AngStr := IntToStr(Brg) Else AngStr := IntToStr(Brg Div 10); End Else Begin AngStr := ' '; If Brg Mod 10 = 0 Then Begin RX2 := RX - Th * Cos(Cangle / Radian); RY2 := RY - Th * Sin(Cangle / Radian); End Else Begin RX2 := RX - Th / 2 * Cos(Cangle / Radian); RY2 := RY - Th / 2 * Sin(Cangle / Radian); End; End; End; LineTo(Trunc(RX2), Trunc(RY2)); RX := Xmid + R3 * Cos(Cangle / Radian); RY := Ymid + R3 * Sin(Cangle / Radian); TextXY(RX, RY, -Cangle, TextWidth(AngStr), TextHeight(AngStr)); AngleTextOut(AnImage.Canvas, AngStr, Round(RX), Round(RY), -(Cangle + 90)); End; End; End; Procedure DrawPlane; Begin With AnImage.Canvas Do Begin Pen.Width := 2; Pen.Color := fLubberColor; MoveTo(Xmid - 20, Ymid); LineTo(Xmid + 20, Ymid); MoveTo(Xmid, Ymid - 10); LineTo(Xmid, Ymid + 25); MoveTo(Xmid - 10, Ymid + 20); LineTo(Xmid + 10, Ymid + 20); End; End; Procedure DrawBearingMarker(Bearing: Integer); Var Pointer: Array[0..2] Of Tpoint; Angle: Integer; RX, RY: Real; RX2, RY2: Real; RX3, RY3: Real; Begin With AnImage.Canvas Do Begin Angle := Bearing - fCompass; Pen.Width := 1; Pen.Color := fBackColor; Brush.Color := fBearingColor; RX := Xmid + (Radius + 1) * Cos((Angle - 90) / Radian); RY := Ymid + (Radius + 1) * Sin((Angle - 90) / Radian); RX2 := 10 * Cos((Angle + 180) / Radian); RY2 := 10 * Sin((Angle + 180) / Radian); RX3 := Xmid + (Radius - 10) * Cos((Angle - 90) / Radian); RY3 := Ymid + (Radius - 10) * Sin((Angle - 90) / Radian); Pointer[0] := Point(Round(RX + RX2), Round(RY + RY2)); Pointer[1] := Point(Round(RX - RX2), Round(RY - RY2)); Pointer[2] := Point(Round(RX3), Round(RY3)); Polygon(Pointer); End; End; Procedure DrawCourseLine1(Course: Integer; Cmode: TCourseMode; Deviation: Integer); Var Count: Integer; Pointer: Array[0..2] Of Tpoint; Angle: Integer; R4: Integer; RX, RY: Real; RX1, RY1: Real; RX2, RY2: Real; RX3, RY3: Real; Begin If Cmode = cmOff Then exit; With AnImage.Canvas Do Begin R4 := Radius - Canvas.TextHeight('00') * 2; Angle := Course - fCompass; Pen.Color := fCourse1Color; Brush.Color := fBackColor; RX := R4 * Cos((Angle - 90) / Radian); RY := R4 * Sin((Angle - 90) / Radian); Pen.Width := 1; Pen.Color := fLubberColor; Brush.Color := fBackColor; For Count := 1 To 3 Do Begin If (Count * 50) + 5 > R4 Then continue; RX2 := Count * 50 * Cos((Angle + 180) / Radian); RY2 := Count * 50 * Sin((Angle + 180) / Radian); Ellipse(Xmid - Round(RX2) - 5, Ymid - Round(RY2) - 5, Xmid - Round(RX2) + 5, Ymid - Round(RY2) + 5); Ellipse(Xmid + Round(RX2) - 5, Ymid + Round(RY2) - 5, Xmid + Round(RX2) + 5, Ymid + Round(RY2) + 5); End; Pen.Color := fCourse1Color; Pen.Width := 2; Brush.Color := fCourse1Color; MoveTo(Xmid - Round(RX), Ymid - Round(RY)); LineTo(Xmid - Round(RX / 2), Ymid - Round(RY / 2)); MoveTo(Xmid + Round(RX / 2), Ymid + Round(RY / 2)); LineTo(Xmid + Round(RX), Ymid + Round(RY)); While Deviation > 180 Do Deviation := Deviation - 360; While Deviation < -180 Do Deviation := Deviation + 360; Pen.Color := fCourse1Color; Pen.Width := 1; RX2 := 14 * Cos((Angle + 120) / Radian); RY2 := 14 * Sin((Angle + 120) / Radian); RX3 := 14 * Cos((Angle + 60) / Radian); RY3 := 14 * Sin((Angle + 60) / Radian); Pointer[0] := Point(Xmid + Round(RX), Ymid + Round(RY)); Pointer[1] := Point(Xmid + Round(RX + RX2), Ymid + Round(RY + RY2)); Pointer[2] := Point(Xmid + Round(RX + RX3), Ymid + Round(RY + RY3)); Polygon(Pointer); Pen.Color := fCourse1Color; Brush.Color := fBackColor; Pen.Width := 1; If Sector Then RX2 := R4 Else RX2 := Radius * 2 / 3; RX1 := RX2 * Cos((Angle - 90) / Radian); RY1 := RX2 * Sin((Angle - 90) / Radian); RX2 := 14 * Cos((Angle + 120) / Radian); RY2 := 14 * Sin((Angle + 120) / Radian); RX3 := 14 * Cos((Angle + 60) / Radian); RY3 := 14 * Sin((Angle + 60) / Radian); If Cmode = cmTo Then Begin Pointer[0] := Point(Xmid + Round(RX1 / 2), Ymid + Round(RY1 / 2)); Pointer[1] := Point(Xmid + Round(RX1 / 2 + RX2), Ymid + Round(RY1 / 2 + RY2)); Pointer[2] := Point(Xmid + Round(RX1 / 2 + RX3), Ymid + Round(RY1 / 2 + RY3)); Polygon(Pointer); End; If Cmode = cmFrom Then Begin Pointer[0] := Point(Xmid - Round(RX1 / 2), Ymid - Round(RY1 / 2)); Pointer[1] := Point(Xmid - Round(RX1 / 2 + RX2), Ymid - Round(RY1 / 2 + RY2)); Pointer[2] := Point(Xmid - Round(RX1 / 2 + RX3), Ymid - Round(RY1 / 2 + RY3)); Polygon(Pointer); End; Pen.Width := 2; Deviation := Deviation * 5; If ABS(Deviation) > 0.86 * R4 Then Begin Deviation := Round(0.86 * R4) * Deviation Div ABS(Deviation); Pen.Color := clRed; End; RX2 := Deviation * Cos((Angle + 180) / Radian); RY2 := Deviation * Sin((Angle + 180) / Radian); MoveTo(Xmid - Round(RX / 2 + RX2), Ymid - Round(RY / 2 + RY2)); LineTo(Xmid + Round(RX / 2 - RX2), Ymid + Round(RY / 2 - RY2)); End; End; Procedure DrawCourseLine2(Course: Integer; Cmode: TCourseMode); Var Pointer: Array[0..2] Of Tpoint; Angle: Integer; R4: Integer; RX, RY: Real; RX2, RY2: Real; RX3, RY3: Real; RX4, RY4: Real; Begin If Cmode = cmOff Then exit; With AnImage.Canvas Do Begin R4 := Radius - Canvas.TextHeight('00') * 2; Angle := Course - fCompass; Pen.Color := fCourse2Color; Brush.Color := fBackColor; RX := R4 * Cos((Angle - 90) / Radian); RY := R4 * Sin((Angle - 90) / Radian); Pen.Color := fCourse2Color; Pen.Width := 2; Brush.Color := fBackColor; RX4 := RX * 3 / 4; RY4 := RY * 3 / 4; MoveTo(Xmid - Round(RX), Ymid - Round(RY)); LineTo(Xmid - Round(RX4), Ymid - Round(RY4)); MoveTo(Xmid + Round(RX4), Ymid + Round(RY4)); LineTo(Xmid + Round(RX), Ymid + Round(RY)); Pen.Color := fCourse2Color; Pen.Width := 1; RX2 := 14 * Cos((Angle + 120) / Radian); RY2 := 14 * Sin((Angle + 120) / Radian); RX3 := 14 * Cos((Angle + 60) / Radian); RY3 := 14 * Sin((Angle + 60) / Radian); Pointer[0] := Point(Xmid + Round(RX), Ymid + Round(RY)); Pointer[1] := Point(Xmid + Round(RX + RX2), Ymid + Round(RY + RY2)); Pointer[2] := Point(Xmid + Round(RX + RX3), Ymid + Round(RY + RY3)); Polygon(Pointer); Pen.Color := fCourse2Color; Brush.Color := fBackColor; Pen.Width := 1; RX2 := 14 * Cos((Angle + 120) / Radian); RY2 := 14 * Sin((Angle + 120) / Radian); RX3 := 14 * Cos((Angle + 60) / Radian); RY3 := 14 * Sin((Angle + 60) / Radian); If Cmode = cmTo Then Begin Pointer[0] := Point(Xmid + Round(RX4), Ymid + Round(RY4)); Pointer[1] := Point(Xmid + Round(RX4 + RX2), Ymid + Round(RY4 + RY2)); Pointer[2] := Point(Xmid + Round(RX4 + RX3), Ymid + Round(RY4 + RY3)); Polygon(Pointer); End; If Cmode = cmFrom Then Begin Pointer[0] := Point(Xmid - Round(RX4), Ymid - Round(RY4)); Pointer[1] := Point(Xmid - Round(RX4 + RX2), Ymid - Round(RY4 + RY2)); Pointer[2] := Point(Xmid - Round(RX4 + RX3), Ymid - Round(RY4 + RY3)); Polygon(Pointer); End; End; End; Procedure DrawHeadingMarker(Heading: Integer); Var HDGpointer: Array[0..4] Of TPoint; Angle: Integer; RX, RY: Real; RX2, RY2: Real; Begin With AnImage.Canvas Do Begin Angle := Heading - fCompass; Pen.Color := fBackColor; Pen.Width := 1; Brush.Color := fHeadingColor; Brush.Style := bsSolid; RX := Xmid + (Radius + 10) * Cos((Angle - 90) / Radian); RY := Ymid + (Radius + 10) * Sin((Angle - 90) / Radian); RX2 := 10 * Cos((Angle + 180) / Radian); RY2 := 10 * Sin((Angle + 180) / Radian); HDGpointer[0] := Point(Round(RX + RX2), Round(RY + RY2)); HDGpointer[2] := Point(Round(RX - RX2), Round(RY - RY2)); RX := Xmid + Radius * Cos((Angle - 90) / Radian); RY := Ymid + Radius * Sin((Angle - 90) / Radian); HDGpointer[1] := Point(Round(RX), Round(RY)); HDGpointer[3] := Point(Round(RX - RX2), Round(RY - RY2)); HDGpointer[4] := Point(Round(RX + RX2), Round(RY + RY2)); Polygon(HDGPointer); End; End; Procedure DrawLubberMarker; Var Pointer: Array[0..2] Of Tpoint; Begin With AnImage.Canvas Do Begin Pen.Width := 1; Pen.Color := fBackColor; Brush.Style := bsSolid; Brush.Color := fLubberColor; Pointer[0] := Point(Xmid - 10, Ymid - Radius - 10); Pointer[1] := Point(Xmid + 10, Ymid - Radius - 10); Pointer[2] := Point(Xmid, Ymid - Radius); Polygon(Pointer); End; End; Begin AnImage.Canvas.Font := Font; // PATCH : la condition FUpdateReq est supprimée — on dessine toujours. // L'ancien mécanisme FUpdateReq bloquait le dessin après le 1er Paint, // rendant le HSI invisible. Le double-buffering via FOffscreenBitmap // dans Paint() remplace avantageusement ce mécanisme. With AnImage Do Begin Canvas.Brush.Color := fBackColor; Canvas.FillRect(PaintRect); Xmid := (Width Div 2); Radius := Xmid - 10; If Width > Height Then Begin Ymid := (Width Div 2); Sector := True; End Else Begin Ymid := (Height Div 2); Sector := False; End; If BorderStyle = bsSingle Then Begin Inc(Xmid); Inc(Ymid); End; End; With AnImage.Canvas Do Begin With Font Do Begin Size := 12; Color := clWhite; End; DrawCompassRose(fCompass); DrawPlane; DrawBearingMarker(fBearing); DrawHeadingMarker(fHeading); DrawCourseLine1(fCourse1, fCourseMode1, fDeviation); DrawCourseLine2(fCourse2, fCourseMode2); DrawLubberMarker; End; End; // --- Setters : Refresh → SafeInvalidate (PATCH) --- Procedure TExAvionicHSI.SetBorderStyle(Value: TBorderStyle); Begin If Value <> fBorderStyle Then Begin fBorderStyle := Value; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetBackColor(Colour: TColor); Begin If Colour <> fBackColor Then Begin fBackColor := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetBearingColor(Colour: TColor); Begin If Colour <> fBearingColor Then Begin fBearingColor := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetCardinalColor(Colour: TColor); Begin If Colour <> fCardinalColor Then Begin fCardinalColor := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetCourse1Color(Colour: TColor); Begin If Colour <> fCourse1Color Then Begin fCourse1Color := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetCourse2Color(Colour: TColor); Begin If Colour <> fCourse2Color Then Begin fCourse2Color := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetHeadingColor(Colour: TColor); Begin If Colour <> fHeadingColor Then Begin fHeadingColor := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetLubberColor(Colour: TColor); Begin If Colour <> fLubberColor Then Begin fLubberColor := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetScaleColor(Colour: TColor); Begin If Colour <> fScaleColor Then Begin fScaleColor := Colour; SafeInvalidate; End; End; Procedure TExAvionicHSI.SetBearing(Value: Integer); Begin If fBearing = Value Then Exit; fBearing := Value; While fBearing > 360 Do fBearing := fBearing - 360; While fBearing < 0 Do fBearing := fBearing + 360; SafeInvalidate; End; Procedure TExAvionicHSI.SetCompass(Value: Integer); Begin If fCompass = Value Then Exit; fCompass := Value; While fCompass > 360 Do fCompass := fCompass - 360; While fCompass < 0 Do fCompass := fCompass + 360; SafeInvalidate; End; Procedure TExAvionicHSI.SetCourse1(Value: Integer); Begin If fCourse1 = Value Then Exit; fCourse1 := Value; While fCourse1 > 360 Do fCourse1 := fCourse1 - 360; While fCourse1 < 0 Do fCourse1 := fCourse1 + 360; SafeInvalidate; End; Procedure TExAvionicHSI.SetCourse2(Value: Integer); Begin If fCourse2 = Value Then Exit; fCourse2 := Value; While fCourse2 > 360 Do fCourse2 := fCourse2 - 360; While fCourse2 < 0 Do fCourse2 := fCourse2 + 360; SafeInvalidate; End; Procedure TExAvionicHSI.SetCourseMode1(Value: TCourseMode); Begin If fCourseMode1 = Value Then Exit; fCourseMode1 := Value; SafeInvalidate; End; Procedure TExAvionicHSI.SetCourseMode2(Value: TCourseMode); Begin If fCourseMode2 = Value Then Exit; fCourseMode2 := Value; SafeInvalidate; End; Procedure TExAvionicHSI.SetDeviation(Value: Integer); Begin If fDeviation = Value Then Exit; fDeviation := Value; While fDeviation > 360 Do fDeviation := fDeviation - 360; While fDeviation < 0 Do fDeviation := fDeviation + 360; SafeInvalidate; End; Procedure TExAvionicHSI.SetHeading(Value: Integer); Begin If fHeading = Value Then Exit; fHeading := Value; While fHeading > 360 Do fHeading := fHeading - 360; While fHeading < 0 Do fHeading := fHeading + 360; SafeInvalidate; End; Procedure TExAvionicHSI.SetFullBearing(Mode: Boolean); Begin If Mode <> fFullBearing Then Begin fFullBearing := Mode; SafeInvalidate; End; End; End.