From 5be8bb9dab1cf9b035dea224d8c988a3a3991c4a Mon Sep 17 00:00:00 2001 From: Robin Breitfeld Date: Tue, 27 Feb 2024 12:41:00 +0100 Subject: [PATCH 01/16] update copy script --- scripts/copy_a318hs.sh | 6 ++---- scripts/copy_a319hs.sh | 4 +--- scripts/copy_a320hs.sh | 4 +--- scripts/copy_a321hs.sh | 4 +--- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/scripts/copy_a318hs.sh b/scripts/copy_a318hs.sh index 0aae56bd..e0c311a4 100755 --- a/scripts/copy_a318hs.sh +++ b/scripts/copy_a318hs.sh @@ -5,9 +5,10 @@ set -ex #remove directory if it exist rm -rvf ./fbw-common -# copy from FBW COMMON source and HDW COMMON into one src +# copy from FBW COMMON source and HS COMMON into one src cp -ra ./flybywire/fbw-common/. ./fbw-common cp -ra ./hsim-a318-common/. ./fbw-common +cp -ra ./hsim-common/. ./fbw-common #remove directory if it exist rm -rvf ./build-a318ceo @@ -32,9 +33,6 @@ cp -ra ./hsim-a318ceo/src/model/. ./build-a318ceo/src/model cp -ra ./hsim-a318ceo/src/systems/. ./build-a318ceo/src/systems cp -ra ./hsim-a318ceo/src/wasm/. ./build-a318ceo/src/wasm -# copy common modules into A318HS build -cp -ra ./hsim-common/src/systems/. ./build-a318ceo/src/systems - mkdir -p ./build-a318ceo/out/lvfr-horizonsim-airbus-a318-ceo mkdir -p ./build-a318ceo/out/lvfr-horizonsim-airbus-a318-ceo-lock-highlight diff --git a/scripts/copy_a319hs.sh b/scripts/copy_a319hs.sh index f786fa93..be7424ed 100755 --- a/scripts/copy_a319hs.sh +++ b/scripts/copy_a319hs.sh @@ -8,6 +8,7 @@ rm -rf ./fbw-common # copy from FBW COMMON source and HDW COMMON into one src cp -ra ./flybywire/fbw-common/. ./fbw-common cp -ra ./hsim-a319-common/. ./fbw-common +cp -ra ./hsim-common/. ./fbw-common #remove directory if it exist rm -rf ./build-a319ceo @@ -40,9 +41,6 @@ cp -ra ./hsim-a319ceo/src/model/. ./build-a319ceo/src/model cp -ra ./hsim-a319ceo/src/systems/. ./build-a319ceo/src/systems cp -ra ./hsim-a319ceo/src/wasm/. ./build-a319ceo/src/wasm -# copy common modules into A319HS build -cp -ra ./hsim-common/src/systems/. ./build-a319ceo/src/systems - mkdir -p ./build-a319ceo/out/lvfr-horizonsim-airbus-a319-ceo mkdir -p ./build-a319ceo/out/lvfr-horizonsim-airbus-a319-ceo-lock-highlight diff --git a/scripts/copy_a320hs.sh b/scripts/copy_a320hs.sh index 15be31b6..ce267bc7 100755 --- a/scripts/copy_a320hs.sh +++ b/scripts/copy_a320hs.sh @@ -8,6 +8,7 @@ rm -rf ./fbw-common # copy from FBW COMMON source and HDW COMMON into one src cp -ra ./flybywire/fbw-common/. ./fbw-common cp -ra ./hsim-a320-common/. ./fbw-common +cp -ra ./hsim-common/. ./fbw-common #remove directory if it exist rm -rf ./build-a320ceo @@ -41,9 +42,6 @@ cp -ra ./hsim-a320ceo/src/model/. ./build-a320ceo/src/model cp -ra ./hsim-a320ceo/src/systems/. ./build-a320ceo/src/systems cp -ra ./hsim-a320ceo/src/wasm/. ./build-a320ceo/src/wasm -# copy common modules into A320HS build -cp -ra ./hsim-common/src/systems/. ./build-a320ceo/src/systems - mkdir -p ./build-a320ceo/out/lvfr-horizonsim-airbus-a320-ceo mkdir -p ./build-a320ceo/out/lvfr-horizonsim-airbus-a320-ceo-lock-highlight diff --git a/scripts/copy_a321hs.sh b/scripts/copy_a321hs.sh index b04fa534..71136a30 100755 --- a/scripts/copy_a321hs.sh +++ b/scripts/copy_a321hs.sh @@ -8,6 +8,7 @@ rm -rf ./fbw-common # copy from FBW COMMON source and HDW COMMON into one src cp -ra ./flybywire/fbw-common/. ./fbw-common cp -ra ./hsim-a21n-common/. ./fbw-common +cp -ra ./hsim-common/. ./fbw-common #remove directory if it exist rm -rf ./build-a321neo @@ -35,9 +36,6 @@ cp -ra ./hsim-a321neo/src/model/. ./build-a321neo/src/model cp -ra ./hsim-a321neo/src/systems/. ./build-a321neo/src/systems cp -ra ./hsim-a321neo/src/wasm/. ./build-a321neo/src/wasm -# copy common modules into A21NHS build -cp -ra ./hsim-common/src/systems/. ./build-a321neo/src/systems - mkdir -p ./build-a321neo/out/lvfr-horizonsim-airbus-a321-neo mkdir -p ./build-a321neo/out/lvfr-horizonsim-airbus-a321-neo-lock-highlight From 03b3d934ba1c3a29dbc95e4668bccbae90def193 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 14:27:33 +0200 Subject: [PATCH 02/16] Updated /Clock/Instrument.tsx Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- hsim-a318ceo/src/systems/instruments/src/Clock/instrument.tsx | 3 +-- hsim-a319ceo/src/systems/instruments/src/Clock/instrument.tsx | 3 +-- hsim-a320ceo/src/systems/instruments/src/Clock/instrument.tsx | 3 +-- hsim-a321neo/src/systems/instruments/src/Clock/instrument.tsx | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hsim-a318ceo/src/systems/instruments/src/Clock/instrument.tsx b/hsim-a318ceo/src/systems/instruments/src/Clock/instrument.tsx index 753b616f..29a424d0 100644 --- a/hsim-a318ceo/src/systems/instruments/src/Clock/instrument.tsx +++ b/hsim-a318ceo/src/systems/instruments/src/Clock/instrument.tsx @@ -1,6 +1,5 @@ +import { ClockRoot, ClockSimvarPublisher } from '@flybywiresim/clock'; import { EventBus, FSComponent, HEventPublisher } from '@microsoft/msfs-sdk'; -import { ClockSimvarPublisher } from './shared/ClockSimvarPublisher'; -import { ClockRoot } from './Clock'; // eslint-disable-next-line camelcase class A32NX_Clock extends BaseInstrument { diff --git a/hsim-a319ceo/src/systems/instruments/src/Clock/instrument.tsx b/hsim-a319ceo/src/systems/instruments/src/Clock/instrument.tsx index df802a80..1b61fbbd 100644 --- a/hsim-a319ceo/src/systems/instruments/src/Clock/instrument.tsx +++ b/hsim-a319ceo/src/systems/instruments/src/Clock/instrument.tsx @@ -1,6 +1,5 @@ +import { ClockRoot, ClockSimvarPublisher } from '@flybywiresim/clock'; import { EventBus, FSComponent, HEventPublisher } from '@microsoft/msfs-sdk'; -import { ClockSimvarPublisher } from './shared/ClockSimvarPublisher'; -import { ClockRoot } from './Clock'; // eslint-disable-next-line camelcase class A32NX_Clock extends BaseInstrument { diff --git a/hsim-a320ceo/src/systems/instruments/src/Clock/instrument.tsx b/hsim-a320ceo/src/systems/instruments/src/Clock/instrument.tsx index e1d1a4c1..e6f85058 100644 --- a/hsim-a320ceo/src/systems/instruments/src/Clock/instrument.tsx +++ b/hsim-a320ceo/src/systems/instruments/src/Clock/instrument.tsx @@ -1,6 +1,5 @@ +import { ClockRoot, ClockSimvarPublisher } from '@flybywiresim/clock'; import { EventBus, FSComponent, HEventPublisher } from '@microsoft/msfs-sdk'; -import { ClockSimvarPublisher } from './shared/ClockSimvarPublisher'; -import { ClockRoot } from './Clock'; // eslint-disable-next-line camelcase class A32NX_Clock extends BaseInstrument { diff --git a/hsim-a321neo/src/systems/instruments/src/Clock/instrument.tsx b/hsim-a321neo/src/systems/instruments/src/Clock/instrument.tsx index 9f0fa13d..f0b41bb1 100644 --- a/hsim-a321neo/src/systems/instruments/src/Clock/instrument.tsx +++ b/hsim-a321neo/src/systems/instruments/src/Clock/instrument.tsx @@ -1,6 +1,5 @@ +import { ClockRoot, ClockSimvarPublisher } from '@flybywiresim/clock'; import { EventBus, FSComponent, HEventPublisher } from '@microsoft/msfs-sdk'; -import { ClockSimvarPublisher } from './shared/ClockSimvarPublisher'; -import { ClockRoot } from './Clock'; // eslint-disable-next-line camelcase class A32NX_Clock extends BaseInstrument { From 8be20012dc5122868dad16acd671899c5dff2f80 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 14:30:42 +0200 Subject: [PATCH 03/16] Moved Clock/style.scss to hsim common folder Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../src/systems/instruments/src/Clock/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {hsim-a318ceo => hsim-common}/src/systems/instruments/src/Clock/style.scss (91%) diff --git a/hsim-a318ceo/src/systems/instruments/src/Clock/style.scss b/hsim-common/src/systems/instruments/src/Clock/style.scss similarity index 91% rename from hsim-a318ceo/src/systems/instruments/src/Clock/style.scss rename to hsim-common/src/systems/instruments/src/Clock/style.scss index 41ee5dba..71634b7a 100644 --- a/hsim-a318ceo/src/systems/instruments/src/Clock/style.scss +++ b/hsim-common/src/systems/instruments/src/Clock/style.scss @@ -1,6 +1,6 @@ @font-face { font-family: "AirbusChronometer"; - src: url("/Fonts/A318HS/AirbusChronometer.ttf") format("truetype"); + src: url("/Fonts/AirbusChronometer.ttf") format("truetype"); font-weight: normal; font-style: normal; } From 66049bb44ffbbffffe094366757239c6a5510d19 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 14:36:41 +0200 Subject: [PATCH 04/16] Created fonts folders in the local base Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../html_ui/Fonts/AirbusChronometer.ttf | Bin 0 -> 3004 bytes .../html_ui/Fonts/AirbusChronometer.ttf | Bin 0 -> 3004 bytes .../html_ui/Fonts/AirbusChronometer.ttf | Bin 0 -> 3004 bytes .../html_ui/Fonts/AirbusChronometer.ttf | Bin 0 -> 3004 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Fonts/AirbusChronometer.ttf create mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Fonts/AirbusChronometer.ttf create mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Fonts/AirbusChronometer.ttf create mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Fonts/AirbusChronometer.ttf diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Fonts/AirbusChronometer.ttf b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Fonts/AirbusChronometer.ttf new file mode 100644 index 0000000000000000000000000000000000000000..93ac4d5672ae494c18847c9c4b01279425db159b GIT binary patch literal 3004 zcmdT`O>9(E6#mY8^X7FrwWZc}D1-P0Xa^cvrUSP8H2g?gQNoW{`Kf4`Dbr5Fv{R=8 zw$TL=V+>+qWMf#MV#3A*Z4-@&J3_>zF)Y-O5Osq;BrYIsWXA8l_hxv777};9$(?)7 zx%b@jopaB*_d)`VC5OZP%u( z-S1xVeeqVYpf%_g`3h)C%8xp_RV<)iOBQc&tV2JsIjfgva7-kFh!V(7 z{(Z*vlJp}f7o8rJT2jeMa#Xu=&Mn@ihO({NVjDBiO-`X$3?Ejo_p=w;B?|5+*vE>+ z;;+T4?tF^GuUvLM<&lljf9&HMldUIz- zr*!IORGLg98mf`#tFm&SP$d^OMzxBU3t!5RXkoKL-WimJ9fd=3XQ=Sq@gaF8oYhA~ z4zBVqE1Vzt9uxv4E#tBje_YnrxO?cJ)jkI*{ekeVV)G8Xu3J*?BzU$OF3AI>^uO)mDh-qJ^e;Ju7GF14^vq-mH|Jztrx}A-CXo>Uwgx zhPU-XJnlv2&8G)%^@E|5cHC1z<(lWMcma9sLq?isPMts6992h6N2npxVEXlY_(P3L zD=QXN8|K1DzzkRU%zJokof=%UEMPWP8~$*lvT*Vq0c%ISS}v9^oF&-g(!%|D!=*J= z_$Mx{qg70o_Muh|y0n1>@~%t!DZiv{K3{5Y!^biS61}!|-tKdpk+LDS5hO2vwuf7D=CxxjTIrZ- zj)UmUj^%r^x#5%*Z;M$Qtou+=*1oni-l}~3uYT>bJ)U4pR22A7;jf*KFx4v`urHOH z7|D)Vu~>UsEEc2W;V#V;!14>H_yt{@>*Kk@%+i<%b*#&J-pL_Wr@CRnJV98c5Wc1~ bH~WAp&QkY+dOeBT911_Zum4TSthegF02l>d literal 0 HcmV?d00001 diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Fonts/AirbusChronometer.ttf b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Fonts/AirbusChronometer.ttf new file mode 100644 index 0000000000000000000000000000000000000000..93ac4d5672ae494c18847c9c4b01279425db159b GIT binary patch literal 3004 zcmdT`O>9(E6#mY8^X7FrwWZc}D1-P0Xa^cvrUSP8H2g?gQNoW{`Kf4`Dbr5Fv{R=8 zw$TL=V+>+qWMf#MV#3A*Z4-@&J3_>zF)Y-O5Osq;BrYIsWXA8l_hxv777};9$(?)7 zx%b@jopaB*_d)`VC5OZP%u( z-S1xVeeqVYpf%_g`3h)C%8xp_RV<)iOBQc&tV2JsIjfgva7-kFh!V(7 z{(Z*vlJp}f7o8rJT2jeMa#Xu=&Mn@ihO({NVjDBiO-`X$3?Ejo_p=w;B?|5+*vE>+ z;;+T4?tF^GuUvLM<&lljf9&HMldUIz- zr*!IORGLg98mf`#tFm&SP$d^OMzxBU3t!5RXkoKL-WimJ9fd=3XQ=Sq@gaF8oYhA~ z4zBVqE1Vzt9uxv4E#tBje_YnrxO?cJ)jkI*{ekeVV)G8Xu3J*?BzU$OF3AI>^uO)mDh-qJ^e;Ju7GF14^vq-mH|Jztrx}A-CXo>Uwgx zhPU-XJnlv2&8G)%^@E|5cHC1z<(lWMcma9sLq?isPMts6992h6N2npxVEXlY_(P3L zD=QXN8|K1DzzkRU%zJokof=%UEMPWP8~$*lvT*Vq0c%ISS}v9^oF&-g(!%|D!=*J= z_$Mx{qg70o_Muh|y0n1>@~%t!DZiv{K3{5Y!^biS61}!|-tKdpk+LDS5hO2vwuf7D=CxxjTIrZ- zj)UmUj^%r^x#5%*Z;M$Qtou+=*1oni-l}~3uYT>bJ)U4pR22A7;jf*KFx4v`urHOH z7|D)Vu~>UsEEc2W;V#V;!14>H_yt{@>*Kk@%+i<%b*#&J-pL_Wr@CRnJV98c5Wc1~ bH~WAp&QkY+dOeBT911_Zum4TSthegF02l>d literal 0 HcmV?d00001 diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Fonts/AirbusChronometer.ttf b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Fonts/AirbusChronometer.ttf new file mode 100644 index 0000000000000000000000000000000000000000..93ac4d5672ae494c18847c9c4b01279425db159b GIT binary patch literal 3004 zcmdT`O>9(E6#mY8^X7FrwWZc}D1-P0Xa^cvrUSP8H2g?gQNoW{`Kf4`Dbr5Fv{R=8 zw$TL=V+>+qWMf#MV#3A*Z4-@&J3_>zF)Y-O5Osq;BrYIsWXA8l_hxv777};9$(?)7 zx%b@jopaB*_d)`VC5OZP%u( z-S1xVeeqVYpf%_g`3h)C%8xp_RV<)iOBQc&tV2JsIjfgva7-kFh!V(7 z{(Z*vlJp}f7o8rJT2jeMa#Xu=&Mn@ihO({NVjDBiO-`X$3?Ejo_p=w;B?|5+*vE>+ z;;+T4?tF^GuUvLM<&lljf9&HMldUIz- zr*!IORGLg98mf`#tFm&SP$d^OMzxBU3t!5RXkoKL-WimJ9fd=3XQ=Sq@gaF8oYhA~ z4zBVqE1Vzt9uxv4E#tBje_YnrxO?cJ)jkI*{ekeVV)G8Xu3J*?BzU$OF3AI>^uO)mDh-qJ^e;Ju7GF14^vq-mH|Jztrx}A-CXo>Uwgx zhPU-XJnlv2&8G)%^@E|5cHC1z<(lWMcma9sLq?isPMts6992h6N2npxVEXlY_(P3L zD=QXN8|K1DzzkRU%zJokof=%UEMPWP8~$*lvT*Vq0c%ISS}v9^oF&-g(!%|D!=*J= z_$Mx{qg70o_Muh|y0n1>@~%t!DZiv{K3{5Y!^biS61}!|-tKdpk+LDS5hO2vwuf7D=CxxjTIrZ- zj)UmUj^%r^x#5%*Z;M$Qtou+=*1oni-l}~3uYT>bJ)U4pR22A7;jf*KFx4v`urHOH z7|D)Vu~>UsEEc2W;V#V;!14>H_yt{@>*Kk@%+i<%b*#&J-pL_Wr@CRnJV98c5Wc1~ bH~WAp&QkY+dOeBT911_Zum4TSthegF02l>d literal 0 HcmV?d00001 diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Fonts/AirbusChronometer.ttf b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Fonts/AirbusChronometer.ttf new file mode 100644 index 0000000000000000000000000000000000000000..93ac4d5672ae494c18847c9c4b01279425db159b GIT binary patch literal 3004 zcmdT`O>9(E6#mY8^X7FrwWZc}D1-P0Xa^cvrUSP8H2g?gQNoW{`Kf4`Dbr5Fv{R=8 zw$TL=V+>+qWMf#MV#3A*Z4-@&J3_>zF)Y-O5Osq;BrYIsWXA8l_hxv777};9$(?)7 zx%b@jopaB*_d)`VC5OZP%u( z-S1xVeeqVYpf%_g`3h)C%8xp_RV<)iOBQc&tV2JsIjfgva7-kFh!V(7 z{(Z*vlJp}f7o8rJT2jeMa#Xu=&Mn@ihO({NVjDBiO-`X$3?Ejo_p=w;B?|5+*vE>+ z;;+T4?tF^GuUvLM<&lljf9&HMldUIz- zr*!IORGLg98mf`#tFm&SP$d^OMzxBU3t!5RXkoKL-WimJ9fd=3XQ=Sq@gaF8oYhA~ z4zBVqE1Vzt9uxv4E#tBje_YnrxO?cJ)jkI*{ekeVV)G8Xu3J*?BzU$OF3AI>^uO)mDh-qJ^e;Ju7GF14^vq-mH|Jztrx}A-CXo>Uwgx zhPU-XJnlv2&8G)%^@E|5cHC1z<(lWMcma9sLq?isPMts6992h6N2npxVEXlY_(P3L zD=QXN8|K1DzzkRU%zJokof=%UEMPWP8~$*lvT*Vq0c%ISS}v9^oF&-g(!%|D!=*J= z_$Mx{qg70o_Muh|y0n1>@~%t!DZiv{K3{5Y!^biS61}!|-tKdpk+LDS5hO2vwuf7D=CxxjTIrZ- zj)UmUj^%r^x#5%*Z;M$Qtou+=*1oni-l}~3uYT>bJ)U4pR22A7;jf*KFx4v`urHOH z7|D)Vu~>UsEEc2W;V#V;!14>H_yt{@>*Kk@%+i<%b*#&J-pL_Wr@CRnJV98c5Wc1~ bH~WAp&QkY+dOeBT911_Zum4TSthegF02l>d literal 0 HcmV?d00001 From 332d1ab0cfa1bc72294f99e0af4af799f6c9b921 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 14:41:17 +0200 Subject: [PATCH 05/16] Updated apron.flt (part of fix nd bugs and pahts (#8453) Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../SimObjects/Airplanes/A318ceoCFM/apron.FLT | 2 +- .../SimObjects/Airplanes/A318cjCFM/apron.FLT | 2 +- .../SimObjects/Airplanes/A319ceoCFM/apron.FLT | 2 +- .../SimObjects/Airplanes/A319ceoCFMSL/apron.FLT | 2 +- .../SimObjects/Airplanes/A319ceoCFM_acj/apron.FLT | 2 +- .../SimObjects/Airplanes/A319ceoIAE/apron.flt | 2 +- .../SimObjects/Airplanes/A319ceoIAE_acj/apron.FLT | 2 +- .../SimObjects/Airplanes/A320ceoCFM/apron.FLT | 2 +- .../SimObjects/Airplanes/A320ceoCFMsl/apron.FLT | 2 +- .../SimObjects/Airplanes/A320ceoIAE/apron.FLT | 2 +- .../SimObjects/Airplanes/A320ceoIAEsl/apron.FLT | 2 +- .../SimObjects/Airplanes/A321neoLEAP/apron.FLT | 2 +- .../SimObjects/Airplanes/aircrafta321neolrLEAP/apron.FLT | 2 +- .../SimObjects/Airplanes/aircrafta321neolrPW/apron.FLT | 2 +- .../SimObjects/Airplanes/aircrafta321neopw/apron.FLT | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318ceoCFM/apron.FLT b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318ceoCFM/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318ceoCFM/apron.FLT +++ b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318ceoCFM/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318cjCFM/apron.FLT b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318cjCFM/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318cjCFM/apron.FLT +++ b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/SimObjects/Airplanes/A318cjCFM/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM/apron.FLT b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM/apron.FLT +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFMSL/apron.FLT b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFMSL/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFMSL/apron.FLT +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFMSL/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM_acj/apron.FLT b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM_acj/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM_acj/apron.FLT +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoCFM_acj/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE/apron.flt b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE/apron.flt index 1dd267e3..1c8d55f8 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE/apron.flt +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE/apron.flt @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE_acj/apron.FLT b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE_acj/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE_acj/apron.FLT +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/SimObjects/Airplanes/A319ceoIAE_acj/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFM/apron.FLT b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFM/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFM/apron.FLT +++ b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFM/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFMsl/apron.FLT b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFMsl/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFMsl/apron.FLT +++ b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoCFMsl/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAE/apron.FLT b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAE/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAE/apron.FLT +++ b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAE/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAEsl/apron.FLT b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAEsl/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAEsl/apron.FLT +++ b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/SimObjects/Airplanes/A320ceoIAEsl/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/A321neoLEAP/apron.FLT b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/A321neoLEAP/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/A321neoLEAP/apron.FLT +++ b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/A321neoLEAP/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrLEAP/apron.FLT b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrLEAP/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrLEAP/apron.FLT +++ b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrLEAP/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrPW/apron.FLT b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrPW/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrPW/apron.FLT +++ b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neolrPW/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neopw/apron.FLT b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neopw/apron.FLT index 1dd267e3..1c8d55f8 100644 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neopw/apron.FLT +++ b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/SimObjects/Airplanes/aircrafta321neopw/apron.FLT @@ -41,7 +41,7 @@ AudioMarkerListen=True AudioDmeListen=False AudioAdfListen=False AudioAdf2Listen=False -AvionicsSwitch=False +AvionicsSwitch=True [Engine Parameters.1.0] ThrottleLeverPct=0 From 07126285d5fa029de7c0cff3f225a70d5c803fc9 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:31:56 +0200 Subject: [PATCH 06/16] Update NoseOutline.tsx Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../src/systems/instruments/src/EFB/Assets/NoseOutline.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsim-common/src/systems/instruments/src/EFB/Assets/NoseOutline.tsx b/hsim-common/src/systems/instruments/src/EFB/Assets/NoseOutline.tsx index 99ff399a..bce70105 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Assets/NoseOutline.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Assets/NoseOutline.tsx @@ -1,7 +1,7 @@ /* eslint-disable max-len */ import React from 'react'; -export const NoseOutline = ({ className }: {className: string}) => ( +export const A320NoseOutline = ({ className }: {className: string}) => ( From 574082afa4cd1f669676e723836f72e24d1148c8 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:32:10 +0200 Subject: [PATCH 07/16] Update FlightWidget.tsx Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../EFB/Dashboard/Widgets/FlightWidget.tsx | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hsim-common/src/systems/instruments/src/EFB/Dashboard/Widgets/FlightWidget.tsx b/hsim-common/src/systems/instruments/src/EFB/Dashboard/Widgets/FlightWidget.tsx index 457a473d..c67fd9c7 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dashboard/Widgets/FlightWidget.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dashboard/Widgets/FlightWidget.tsx @@ -1,5 +1,4 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 /* eslint-disable max-len */ @@ -12,7 +11,7 @@ import { fetchSimbriefDataAction, isSimbriefDataLoaded } from '../../Store/featu import { useAppSelector, useAppDispatch } from '../../Store/store'; import { ScrollableContainer } from '../../UtilComponents/ScrollableContainer'; -import { t } from '../../translation'; +import { t } from '../../Localization/translation'; import { getAirframeType } from '../../Efb'; import { AC_TYPE } from '../../Enum/Airframe'; @@ -22,8 +21,8 @@ interface InformationEntryProps { } const InformationEntry = ({ title, info }: InformationEntryProps) => ( -
-

{title}

+
+

{title}

{info}

); @@ -130,7 +129,7 @@ export const FlightWidget = () => { return (
-
+

{t('Dashboard.YourFlight.Title')}

{simbriefDataLoaded && (

@@ -138,7 +137,7 @@ export const FlightWidget = () => { {' '} | {' '} - {(airframe !== null ? AC_TYPE[airframe] : 'A320-214')} + {(airframe !== null ? AC_TYPE[airframe] : 'A320-214')} //DO NOT TOUCH

)}
@@ -151,19 +150,19 @@ export const FlightWidget = () => {

{departingName}

-

{arrivingAirport}

-

{arrivingName}

+

{arrivingAirport}

+

{arrivingName}

-
+

1 ? 'text-theme-highlight' : 'text-theme-text'}`}> {schedOutParsed}

-
+
{!!flightPlanProgress && ( { )}
-

= 98 ? 'text-theme-highlight' : 'text-theme-text'}`}> +

= 98 ? 'text-theme-highlight' : 'text-theme-text'}`}> {schedInParsed}

-
+
@@ -199,7 +198,7 @@ export const FlightWidget = () => {
{t('Dashboard.YourFlight.Route')}

- + {departingAirport} / {departingRunway} @@ -207,7 +206,7 @@ export const FlightWidget = () => { {' '} {route} {' '} - + {arrivingAirport} / {arrivingRunway} From a4e36261aae636379c5415ead27f9905916c7cb8 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:32:36 +0200 Subject: [PATCH 08/16] A21NOverview.tsx Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../Pages/Overview/A21N_251N/A21NLEAPOverview.tsx | 14 ++++++-------- .../Overview/A21N_251NX/A21NLEAPFLEXOverview.tsx | 14 ++++++-------- .../Overview/A21N_251N_LR/A21NLEAPLROverview.tsx | 14 ++++++-------- .../Pages/Overview/A21N_271N/A21NPWOverview.tsx | 14 ++++++-------- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N/A21NLEAPOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N/A21NLEAPOverview.tsx index 1db13c9d..8f7ec46e 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N/A21NLEAPOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N/A21NLEAPOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A21NLEAPOverviewPage = () => { }; return ( -

+

Airbus A321neo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251NX/A21NLEAPFLEXOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251NX/A21NLEAPFLEXOverview.tsx index 1db13c9d..8f7ec46e 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251NX/A21NLEAPFLEXOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251NX/A21NLEAPFLEXOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A21NLEAPOverviewPage = () => { }; return ( -
+

Airbus A321neo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N_LR/A21NLEAPLROverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N_LR/A21NLEAPLROverview.tsx index 0320705b..4c18a8cf 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N_LR/A21NLEAPLROverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_251N_LR/A21NLEAPLROverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A21NLEAPLROverviewPage = () => { }; return ( -
+

Airbus A321neo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N/A21NPWOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N/A21NPWOverview.tsx index 5d00e401..c7ff9cb1 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N/A21NPWOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N/A21NPWOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A21NPWOverviewPage = () => { }; return ( -
+

Airbus A321neo

{airline}

-
- +
+
-
+
From 145b508710f3f15b0f5eef8670263db0cbc31f60 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:32:52 +0200 Subject: [PATCH 09/16] A21N Overview.tsx Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../Overview/A21N_271NX/A21NPWFLEXOverview.tsx | 14 ++++++-------- .../Overview/A21N_271N_LR/A21NPWLROverview.tsx | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271NX/A21NPWFLEXOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271NX/A21NPWFLEXOverview.tsx index 5d00e401..c7ff9cb1 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271NX/A21NPWFLEXOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271NX/A21NPWFLEXOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A21NPWOverviewPage = () => { }; return ( -
+

Airbus A321neo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N_LR/A21NPWLROverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N_LR/A21NPWLROverview.tsx index 6b66ad2f..41d20e71 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N_LR/A21NPWLROverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A21N_271N_LR/A21NPWLROverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A21NPWLROverviewPage = () => { }; return ( -
+

Airbus A321neo

{airline}

-
- +
+
-
+
From 66b7f51850f807c165e3b502ebedefd5a6fbc01d Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:33:21 +0200 Subject: [PATCH 10/16] A3XXceo Overview.tsx Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../Overview/A318CJ_115/A318ACJOverview.tsx | 14 ++++++-------- .../Pages/Overview/A318_115/A318Overview.tsx | 14 ++++++-------- .../Overview/A319CJ_115/A319CFMACJOverview.tsx | 14 ++++++-------- .../Overview/A319CJ_133/A319IAEACJOverview.tsx | 14 ++++++-------- .../Pages/Overview/A319_115/A319CFMOverview.tsx | 14 ++++++-------- .../Pages/Overview/A319_133/A319IAEOverview.tsx | 14 ++++++-------- .../Pages/Overview/A320_214/A320CFMOverview.tsx | 16 +++++++--------- .../Pages/Overview/A320_232/A320IAEOverview.tsx | 14 ++++++-------- 8 files changed, 49 insertions(+), 65 deletions(-) diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318CJ_115/A318ACJOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318CJ_115/A318ACJOverview.tsx index 554bbbab..f101c0f4 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318CJ_115/A318ACJOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318CJ_115/A318ACJOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A318ACJOverviewPage = () => { }; return ( -
+

Airbus ACJ318ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318_115/A318Overview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318_115/A318Overview.tsx index 9be4f3ac..1a91b9cf 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318_115/A318Overview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A318_115/A318Overview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A318OverviewPage = () => { }; return ( -
+

Airbus A318ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_115/A319CFMACJOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_115/A319CFMACJOverview.tsx index 86e07662..8fdd9617 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_115/A319CFMACJOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_115/A319CFMACJOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A319CFMACJOverviewPage = () => { }; return ( -
+

Airbus ACJ319ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_133/A319IAEACJOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_133/A319IAEACJOverview.tsx index 5759a769..44f44b00 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_133/A319IAEACJOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319CJ_133/A319IAEACJOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A319IAEACJOverviewPage = () => { }; return ( -
+

Airbus ACJ319ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_115/A319CFMOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_115/A319CFMOverview.tsx index 8eb3795a..286a7ddb 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_115/A319CFMOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_115/A319CFMOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A319CFMOverviewPage = () => { }; return ( -
+

Airbus A319ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_133/A319IAEOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_133/A319IAEOverview.tsx index 2491e75e..8d560044 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_133/A319IAEOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A319_133/A319IAEOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A319IAEOverviewPage = () => { }; return ( -
+

Airbus A319ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_214/A320CFMOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_214/A320CFMOverview.tsx index 471a59f1..a79caa78 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_214/A320CFMOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_214/A320CFMOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -27,7 +25,7 @@ const InformationEntry: FC = ({ children, title, info }) export const A320CFMOverviewPage = () => { let [airline] = useSimVar('ATC AIRLINE', 'String', 1_000); - airline ||= 'Horizon Simulations'; + airline ||= 'Horizon Simulations'; //DO NOT TOUCH const [actualGrossWeight] = useSimVar('TOTAL WEIGHT', 'kilograms', 5_000); const getConvertedInfo = (metricValue: number, unitType: 'weight' |'volume' |'distance') => { @@ -45,15 +43,15 @@ export const A320CFMOverviewPage = () => { }; return ( -
+

Airbus A320ceo

{airline}

-
- +
+
-
+
diff --git a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_232/A320IAEOverview.tsx b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_232/A320IAEOverview.tsx index 858e4a8f..97bfa79c 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_232/A320IAEOverview.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Dispatch/Pages/Overview/A320_232/A320IAEOverview.tsx @@ -1,13 +1,11 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { FC } from 'react'; import { IconPlane } from '@tabler/icons'; import { Box, LightningFill, PeopleFill, Rulers, Speedometer2 } from 'react-bootstrap-icons'; import { useSimVar, Units } from '@flybywiresim/fbw-sdk'; -import { t } from '../../../../translation'; -import { NoseOutline } from '../../../../Assets/NoseOutline'; +import { t, A320NoseOutline } from '@flybywiresim/flypad'; interface InformationEntryProps { title: string; @@ -45,15 +43,15 @@ export const A320IAEOverviewPage = () => { }; return ( -
+

Airbus A320ceo

{airline}

-
- +
+
-
+
From 0cdaf62524279b4c97ccefe6bf14df7e9d7899e2 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:33:42 +0200 Subject: [PATCH 11/16] Fuelpage & Sync.ts Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../EFB/Ground/Pages/{ => Fuel}/FuelPage.tsx | 24 ++++++++----------- .../instruments/src/EFB/Settings/sync.ts | 1 + 2 files changed, 11 insertions(+), 14 deletions(-) rename hsim-common/src/systems/instruments/src/EFB/Ground/Pages/{ => Fuel}/FuelPage.tsx (96%) diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/FuelPage.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Fuel/FuelPage.tsx similarity index 96% rename from hsim-common/src/systems/instruments/src/EFB/Ground/Pages/FuelPage.tsx rename to hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Fuel/FuelPage.tsx index 020bac8c..e5d703dd 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/FuelPage.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Fuel/FuelPage.tsx @@ -1,23 +1,19 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - /* eslint-disable max-len */ import React, { useState } from 'react'; -import { getAirframeType } from '../../Efb'; //DO NOT REMOVE UNDER ANY CIRCUMSTANCES -import { Fuel } from './Fuel/Constants' //DO NOT REMOVE UNDER ANY CIRCUMSTANCES +import { getAirframeType } from '../../../Efb'; //DO NOT REMOVE UNDER ANY CIRCUMSTANCES +import { Fuel } from './Constants' //DO NOT REMOVE UNDER ANY CIRCUMSTANCES import { round } from 'lodash'; import { CloudArrowDown, PlayFill, StopCircleFill } from 'react-bootstrap-icons'; import { useSimVar, Units, usePersistentNumberProperty, usePersistentProperty } from '@flybywiresim/fbw-sdk'; import Slider from 'rc-slider'; -import { t } from '../../translation'; -import { TooltipWrapper } from '../../UtilComponents/TooltipWrapper'; -import { isSimbriefDataLoaded } from '../../Store/features/simBrief'; -import { useAppSelector } from '../../Store/store'; -import { SelectGroup, SelectItem } from '../../UtilComponents/Form/Select'; -import { ProgressBar } from '../../UtilComponents/Progress/Progress'; -import { SimpleInput } from '../../UtilComponents/Form/SimpleInput/SimpleInput'; -import { OverWingOutline } from '../../Assets/OverWingOutline'; +import { t } from '../../../translation'; +import { TooltipWrapper } from '../../../UtilComponents/TooltipWrapper'; +import { isSimbriefDataLoaded } from '../../../Store/features/simBrief'; +import { useAppSelector } from '../../../Store/store'; +import { SelectGroup, SelectItem } from '../../../UtilComponents/Form/Select'; +import { ProgressBar } from '../../../UtilComponents/Progress/Progress'; +import { SimpleInput } from '../../../UtilComponents/Form/SimpleInput/SimpleInput'; +import { OverWingOutline } from '../../../Assets/OverWingOutline'; interface TankReadoutProps { title: string; diff --git a/hsim-common/src/systems/instruments/src/EFB/Settings/sync.ts b/hsim-common/src/systems/instruments/src/EFB/Settings/sync.ts index 7bdfb259..b09a75f0 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Settings/sync.ts +++ b/hsim-common/src/systems/instruments/src/EFB/Settings/sync.ts @@ -47,6 +47,7 @@ const settingsToSync: Map = new Map([ ['CONFIG_USING_METRIC_UNIT', ['L:A32NX_EFB_USING_METRIC_UNIT', 'bool', '1']], ['CONFIG_A32NX_FWC_RADIO_AUTO_CALL_OUT_PINS', ['L:A32NX_FWC_RADIO_AUTO_CALL_OUT_PINS', 'number', DEFAULT_RADIO_AUTO_CALL_OUTS.toString()]], ['CONFIG_USING_PORTABLE_DEVICES', ['L:A32NX_CONFIG_USING_PORTABLE_DEVICES', 'bool', '1']], + ['REFUEL_RATE_SETTING', ['L:A32NX_EFB_REFUEL_RATE_SETTING', 'number', '0']], ]); const settingEnumToSync: Map = new Map([ From fee0f430848bbd1e0e46ba96dcfb11af30ab7311 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 15:34:00 +0200 Subject: [PATCH 12/16] Systems/fuel/mod.rs Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../src/wasm/systems/a320_systems/src/fuel/mod.rs | 8 +++++++- .../src/wasm/systems/a320_systems/src/fuel/mod.rs | 8 +++++++- .../src/wasm/systems/a320_systems/src/fuel/mod.rs | 7 ++++++- .../src/wasm/systems/a320_systems/src/fuel/mod.rs | 7 ++++++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hsim-a318ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs b/hsim-a318ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs index 4cc4ff1c..44476190 100644 --- a/hsim-a318ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs +++ b/hsim-a318ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs @@ -52,22 +52,27 @@ impl A320Fuel { FuelInfo { fuel_tank_id: "FUEL TANK CENTER QUANTITY", position: (2., 0., 1.), + total_capacity_gallons: 2215., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT MAIN QUANTITY", position: (-0.89, -16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT AUX QUANTITY", position: (-6.8, -35., 3.), + total_capacity_gallons: 228., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT MAIN QUANTITY", position: (-0.89, 16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT AUX QUANTITY", position: (-6.8, 35., 3.), + total_capacity_gallons: 228., }, ]; @@ -77,6 +82,7 @@ impl A320Fuel { context, f.fuel_tank_id, Vector3::new(f.position.0, f.position.1, f.position.2), + false, ) }); A320Fuel { @@ -161,4 +167,4 @@ impl SimulationElement for A320Fuel { self.fuel_system.accept(visitor); visitor.visit(self); } -} \ No newline at end of file +} diff --git a/hsim-a319ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs b/hsim-a319ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs index db907622..50f6ec54 100644 --- a/hsim-a319ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs +++ b/hsim-a319ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs @@ -52,22 +52,27 @@ impl A320Fuel { FuelInfo { fuel_tank_id: "FUEL TANK CENTER QUANTITY", position: (2.55, 0., 1.), + total_capacity_gallons: 2215., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT MAIN QUANTITY", position: (-4.89, -16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT AUX QUANTITY", position: (-9.9, -35., 3.), + total_capacity_gallons: 228., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT MAIN QUANTITY", position: (-4.89, 16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT AUX QUANTITY", position: (-9.9, 35., 3.), + total_capacity_gallons: 228., }, ]; @@ -77,6 +82,7 @@ impl A320Fuel { context, f.fuel_tank_id, Vector3::new(f.position.0, f.position.1, f.position.2), + false, ) }); A320Fuel { @@ -161,4 +167,4 @@ impl SimulationElement for A320Fuel { self.fuel_system.accept(visitor); visitor.visit(self); } -} \ No newline at end of file +} diff --git a/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs b/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs index 4bf73bdb..d07a22ad 100644 --- a/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs +++ b/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs @@ -52,22 +52,27 @@ impl A320Fuel { FuelInfo { fuel_tank_id: "FUEL TANK CENTER QUANTITY", position: (-4.5, 0., 1.), + total_capacity_gallons: 2215., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT MAIN QUANTITY", position: (-8., -16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT AUX QUANTITY", position: (-16.9, -35., 3.), + total_capacity_gallons: 228., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT MAIN QUANTITY", position: (-8., 16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT AUX QUANTITY", position: (-16.9, 35., 3.), + total_capacity_gallons: 228., }, ]; @@ -161,4 +166,4 @@ impl SimulationElement for A320Fuel { self.fuel_system.accept(visitor); visitor.visit(self); } -} \ No newline at end of file +} diff --git a/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs b/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs index 0c4fc63c..264e2dea 100644 --- a/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs +++ b/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs @@ -52,22 +52,27 @@ impl A320Fuel { FuelInfo { fuel_tank_id: "FUEL TANK CENTER QUANTITY", position: (-20.53, 0., 1.), + total_capacity_gallons: 2117., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT MAIN QUANTITY", position: (-21.73, -16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK LEFT AUX QUANTITY", position: (-29.63, -35., 3.), + total_capacity_gallons: 228., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT MAIN QUANTITY", position: (-21.73, 16., 2.), + total_capacity_gallons: 1816., }, FuelInfo { fuel_tank_id: "FUEL TANK RIGHT AUX QUANTITY", position: (-29.63, 35., 3.), + total_capacity_gallons: 228., }, ]; @@ -161,4 +166,4 @@ impl SimulationElement for A320Fuel { self.fuel_system.accept(visitor); visitor.visit(self); } -} \ No newline at end of file +} From b53abd5979aa1cc6032b6b489eb0f42cf77b06c7 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 16:09:54 +0200 Subject: [PATCH 13/16] fix(mcdu): make dest efob amber if below min fuel (#8300) Co-Authored-By: Robin Breitfeld <30130534+masterrob94@users.noreply.github.com> --- .../CDU/A320_Neo_CDU_FuelPredPage.js | 18 ++--- .../FMC/A318HS_FMCMainDisplay.js | 64 ++++++++++------ .../CDU/A320_Neo_CDU_FuelPredPage.js | 18 ++--- .../FMC/A319HS_FMCMainDisplay.js | 64 ++++++++++------ .../CDU/A320_Neo_CDU_FuelPredPage.js | 18 ++--- .../FMC/A320HS_FMCMainDisplay.js | 73 ++++++++++++------- .../CDU/A320_Neo_CDU_FuelPredPage.js | 18 ++--- .../FMC/A21NHS_FMCMainDisplay.js | 73 ++++++++++++------- 8 files changed, 209 insertions(+), 137 deletions(-) diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/CDU/A320_Neo_CDU_FuelPredPage.js b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/CDU/A320_Neo_CDU_FuelPredPage.js index 5a1cf7af..1068f786 100644 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/CDU/A320_Neo_CDU_FuelPredPage.js +++ b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/CDU/A320_Neo_CDU_FuelPredPage.js @@ -160,7 +160,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { altIdentCell = mcdu.altDestination.ident; altEFOBCell = (NXUnits.kgToUser(mcdu.getAltEFOB(true))).toFixed(1); - altEFOBCellColor = mcdu.getAltEFOB(true) < mcdu._minDestFob ? "[color]amber" : "[color]green"; + altEFOBCellColor = "[color]green"; } mcdu.tryUpdateRouteTrip(isFlying); @@ -168,7 +168,8 @@ class CDUFuelPredPage { if (dest) { destIdentCell = dest.ident; } - destEFOBCell = (NXUnits.kgToUser(mcdu.getDestEFOB(true))).toFixed(1); + const efob = mcdu.getDestEFOB(true); + destEFOBCell = (NXUnits.kgToUser(efob)).toFixed(1); // Should we use predicted values or liveETATo and liveUTCto? destTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime)) : destTimeCell = FMCMainDisplay.minutesTohhmm(mcdu._routeTripTime); @@ -176,7 +177,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { if (mcdu.getRouteAltFuelTime()) { altTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime) + FMCMainDisplay.minuteToSeconds(mcdu.getRouteAltFuelTime())) - : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); + : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); altTimeCellColor = "[color]green"; } else { altTimeCell = "----"; @@ -184,10 +185,8 @@ class CDUFuelPredPage { } } - destEFOBCellColor = "[color]green"; destTimeCellColor = "[color]green"; - rteRsvWeightCell = "{sp}{sp}" + (NXUnits.kgToUser(mcdu.getRouteReservedWeight())).toFixed(1); if (!mcdu._rteReservedWeightEntered) { rteRsvWeightCell = "{small}" + rteRsvWeightCell + "{end}"; @@ -199,14 +198,13 @@ class CDUFuelPredPage { rteRsvPctColor = "{white}"; } else { rteRsvPercentCell = mcdu.getRouteReservedPercent().toFixed(1); - if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered()) ) { + if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered())) { rteRsvPercentCell = "{small}" + rteRsvPercentCell + "{end}"; } - rteRsvPctColor = isFlying? "{green}" : "{cyan}"; - rteRSvCellColor = isFlying? "[color]green" : "[color]cyan"; + rteRsvPctColor = isFlying ? "{green}" : "{cyan}"; + rteRSvCellColor = isFlying ? "[color]green" : "[color]cyan"; } - mcdu.onLeftInput[2] = async (value, scratchpadCallback) => { if (await mcdu.trySetRouteReservedFuel(value)) { CDUFuelPredPage.ShowPage(mcdu); @@ -250,6 +248,8 @@ class CDUFuelPredPage { if (isFinite(mcdu.zeroFuelWeightMassCenter)) { zfwCgCell = mcdu.zeroFuelWeightMassCenter.toFixed(1); } + + destEFOBCellColor = mcdu._isBelowMinDestFob ? "[color]amber" : "[color]green"; } } diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/FMC/A318HS_FMCMainDisplay.js b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/FMC/A318HS_FMCMainDisplay.js index 9dc94a89..499ad1b5 100644 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/FMC/A318HS_FMCMainDisplay.js +++ b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/FMC/A318HS_FMCMainDisplay.js @@ -70,6 +70,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = undefined; this._minDestFob = undefined; this._minDestFobEntered = undefined; + this._isBelowMinDestFob = undefined; this._defaultRouteFinalTime = undefined; this._fuelPredDone = undefined; this._fuelPlanningPhase = undefined; @@ -414,6 +415,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = false; this._minDestFob = 0; this._minDestFobEntered = false; + this._isBelowMinDestFob = false; this._defaultRouteFinalTime = 45; this._fuelPredDone = false; this._fuelPlanningPhase = this._fuelPlanningPhases.PLANNING; @@ -643,6 +645,7 @@ class FMCMainDisplay extends BaseAirliners { this.updateMinimums(); this.updateIlsCourse(); this.updatePerfPageAltPredictions(); + this.checkEFOBBelowMin(); } this.A32NXCore.update(); @@ -665,7 +668,6 @@ class FMCMainDisplay extends BaseAirliners { if (this.efisSymbols) { this.efisSymbols.update(_deltaTime); } - this.arincBusOutputs.forEach((word) => word.writeToSimVarIfDirty()); } @@ -2191,7 +2193,7 @@ class FMCMainDisplay extends BaseAirliners { if (isFinite(value)) { if (this.isMinDestFobInRange(value)) { this._minDestFobEntered = true; - if (value < this._minDestFob) { + if (value < this._routeAltFuelWeight + this.getRouteFinalFuelWeight()) { this.addMessageToQueue(NXSystemMessages.checkMinDestFob); } this._minDestFob = value; @@ -4277,26 +4279,44 @@ class FMCMainDisplay extends BaseAirliners { } checkEFOBBelowMin() { - if (!this._minDestFobEntered) { - this.tryUpdateMinDestFob(); - } - const EFOBBelMin = this.isAnEngineOn() ? this.getDestEFOB(true) : this.getDestEFOB(false); - - if (EFOBBelMin < this._minDestFob) { - if (this.isAnEngineOn()) { - setTimeout(() => { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); - }, 180000); - } else { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); + if (this._fuelPredDone) { + if (!this._minDestFobEntered) { + this.tryUpdateMinDestFob(); + } + + if (this._minDestFob) { + // round & only use 100kgs precision since thats how it is displayed in fuel pred + const destEfob = Math.round(this.getDestEFOB(this.isAnEngineOn()) * 10) / 10; + const roundedMinDestFob = Math.round(this._minDestFob * 10) / 10; + if (!this._isBelowMinDestFob) { + if (destEfob < roundedMinDestFob) { + this._isBelowMinDestFob = true; + // TODO should be in flight only and if fuel is below min dest efob for 2 minutes + if (this.isAnEngineOn()) { + setTimeout(() => { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + }, 120000); + } else { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + } + } + } else { + // check if we are at least 300kgs above min dest efob to show green again & the ability to trigger the message + if (roundedMinDestFob) { + if (destEfob - roundedMinDestFob >= 0.3) { + this._isBelowMinDestFob = false; + this.removeMessageFromQueue(NXSystemMessages.destEfobBelowMin); + } + } + } } } } diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/CDU/A320_Neo_CDU_FuelPredPage.js b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/CDU/A320_Neo_CDU_FuelPredPage.js index 5a1cf7af..0fa6ba33 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/CDU/A320_Neo_CDU_FuelPredPage.js +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/CDU/A320_Neo_CDU_FuelPredPage.js @@ -9,7 +9,7 @@ class CDUFuelPredPage { let destTimeCell = "----"; let destTimeCellColor = "[color]white"; let destEFOBCell = "---.-"; - let destEFOBCellColor = "[color]white"; + const destEFOBCellColor = "[color]white"; let altIdentCell = "NONE"; let altTimeCell = "----"; @@ -160,7 +160,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { altIdentCell = mcdu.altDestination.ident; altEFOBCell = (NXUnits.kgToUser(mcdu.getAltEFOB(true))).toFixed(1); - altEFOBCellColor = mcdu.getAltEFOB(true) < mcdu._minDestFob ? "[color]amber" : "[color]green"; + altEFOBCellColor = "[color]green"; } mcdu.tryUpdateRouteTrip(isFlying); @@ -168,7 +168,8 @@ class CDUFuelPredPage { if (dest) { destIdentCell = dest.ident; } - destEFOBCell = (NXUnits.kgToUser(mcdu.getDestEFOB(true))).toFixed(1); + const efob = mcdu.getDestEFOB(true); + destEFOBCell = (NXUnits.kgToUser(efob)).toFixed(1); // Should we use predicted values or liveETATo and liveUTCto? destTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime)) : destTimeCell = FMCMainDisplay.minutesTohhmm(mcdu._routeTripTime); @@ -176,7 +177,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { if (mcdu.getRouteAltFuelTime()) { altTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime) + FMCMainDisplay.minuteToSeconds(mcdu.getRouteAltFuelTime())) - : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); + : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); altTimeCellColor = "[color]green"; } else { altTimeCell = "----"; @@ -184,10 +185,8 @@ class CDUFuelPredPage { } } - destEFOBCellColor = "[color]green"; destTimeCellColor = "[color]green"; - rteRsvWeightCell = "{sp}{sp}" + (NXUnits.kgToUser(mcdu.getRouteReservedWeight())).toFixed(1); if (!mcdu._rteReservedWeightEntered) { rteRsvWeightCell = "{small}" + rteRsvWeightCell + "{end}"; @@ -199,14 +198,13 @@ class CDUFuelPredPage { rteRsvPctColor = "{white}"; } else { rteRsvPercentCell = mcdu.getRouteReservedPercent().toFixed(1); - if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered()) ) { + if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered())) { rteRsvPercentCell = "{small}" + rteRsvPercentCell + "{end}"; } - rteRsvPctColor = isFlying? "{green}" : "{cyan}"; - rteRSvCellColor = isFlying? "[color]green" : "[color]cyan"; + rteRsvPctColor = isFlying ? "{green}" : "{cyan}"; + rteRSvCellColor = isFlying ? "[color]green" : "[color]cyan"; } - mcdu.onLeftInput[2] = async (value, scratchpadCallback) => { if (await mcdu.trySetRouteReservedFuel(value)) { CDUFuelPredPage.ShowPage(mcdu); diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/FMC/A319HS_FMCMainDisplay.js b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/FMC/A319HS_FMCMainDisplay.js index 9dc94a89..499ad1b5 100644 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/FMC/A319HS_FMCMainDisplay.js +++ b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/FMC/A319HS_FMCMainDisplay.js @@ -70,6 +70,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = undefined; this._minDestFob = undefined; this._minDestFobEntered = undefined; + this._isBelowMinDestFob = undefined; this._defaultRouteFinalTime = undefined; this._fuelPredDone = undefined; this._fuelPlanningPhase = undefined; @@ -414,6 +415,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = false; this._minDestFob = 0; this._minDestFobEntered = false; + this._isBelowMinDestFob = false; this._defaultRouteFinalTime = 45; this._fuelPredDone = false; this._fuelPlanningPhase = this._fuelPlanningPhases.PLANNING; @@ -643,6 +645,7 @@ class FMCMainDisplay extends BaseAirliners { this.updateMinimums(); this.updateIlsCourse(); this.updatePerfPageAltPredictions(); + this.checkEFOBBelowMin(); } this.A32NXCore.update(); @@ -665,7 +668,6 @@ class FMCMainDisplay extends BaseAirliners { if (this.efisSymbols) { this.efisSymbols.update(_deltaTime); } - this.arincBusOutputs.forEach((word) => word.writeToSimVarIfDirty()); } @@ -2191,7 +2193,7 @@ class FMCMainDisplay extends BaseAirliners { if (isFinite(value)) { if (this.isMinDestFobInRange(value)) { this._minDestFobEntered = true; - if (value < this._minDestFob) { + if (value < this._routeAltFuelWeight + this.getRouteFinalFuelWeight()) { this.addMessageToQueue(NXSystemMessages.checkMinDestFob); } this._minDestFob = value; @@ -4277,26 +4279,44 @@ class FMCMainDisplay extends BaseAirliners { } checkEFOBBelowMin() { - if (!this._minDestFobEntered) { - this.tryUpdateMinDestFob(); - } - const EFOBBelMin = this.isAnEngineOn() ? this.getDestEFOB(true) : this.getDestEFOB(false); - - if (EFOBBelMin < this._minDestFob) { - if (this.isAnEngineOn()) { - setTimeout(() => { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); - }, 180000); - } else { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); + if (this._fuelPredDone) { + if (!this._minDestFobEntered) { + this.tryUpdateMinDestFob(); + } + + if (this._minDestFob) { + // round & only use 100kgs precision since thats how it is displayed in fuel pred + const destEfob = Math.round(this.getDestEFOB(this.isAnEngineOn()) * 10) / 10; + const roundedMinDestFob = Math.round(this._minDestFob * 10) / 10; + if (!this._isBelowMinDestFob) { + if (destEfob < roundedMinDestFob) { + this._isBelowMinDestFob = true; + // TODO should be in flight only and if fuel is below min dest efob for 2 minutes + if (this.isAnEngineOn()) { + setTimeout(() => { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + }, 120000); + } else { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + } + } + } else { + // check if we are at least 300kgs above min dest efob to show green again & the ability to trigger the message + if (roundedMinDestFob) { + if (destEfob - roundedMinDestFob >= 0.3) { + this._isBelowMinDestFob = false; + this.removeMessageFromQueue(NXSystemMessages.destEfobBelowMin); + } + } + } } } } diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/CDU/A320_Neo_CDU_FuelPredPage.js b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/CDU/A320_Neo_CDU_FuelPredPage.js index 5a1cf7af..0fa6ba33 100644 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/CDU/A320_Neo_CDU_FuelPredPage.js +++ b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/CDU/A320_Neo_CDU_FuelPredPage.js @@ -9,7 +9,7 @@ class CDUFuelPredPage { let destTimeCell = "----"; let destTimeCellColor = "[color]white"; let destEFOBCell = "---.-"; - let destEFOBCellColor = "[color]white"; + const destEFOBCellColor = "[color]white"; let altIdentCell = "NONE"; let altTimeCell = "----"; @@ -160,7 +160,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { altIdentCell = mcdu.altDestination.ident; altEFOBCell = (NXUnits.kgToUser(mcdu.getAltEFOB(true))).toFixed(1); - altEFOBCellColor = mcdu.getAltEFOB(true) < mcdu._minDestFob ? "[color]amber" : "[color]green"; + altEFOBCellColor = "[color]green"; } mcdu.tryUpdateRouteTrip(isFlying); @@ -168,7 +168,8 @@ class CDUFuelPredPage { if (dest) { destIdentCell = dest.ident; } - destEFOBCell = (NXUnits.kgToUser(mcdu.getDestEFOB(true))).toFixed(1); + const efob = mcdu.getDestEFOB(true); + destEFOBCell = (NXUnits.kgToUser(efob)).toFixed(1); // Should we use predicted values or liveETATo and liveUTCto? destTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime)) : destTimeCell = FMCMainDisplay.minutesTohhmm(mcdu._routeTripTime); @@ -176,7 +177,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { if (mcdu.getRouteAltFuelTime()) { altTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime) + FMCMainDisplay.minuteToSeconds(mcdu.getRouteAltFuelTime())) - : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); + : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); altTimeCellColor = "[color]green"; } else { altTimeCell = "----"; @@ -184,10 +185,8 @@ class CDUFuelPredPage { } } - destEFOBCellColor = "[color]green"; destTimeCellColor = "[color]green"; - rteRsvWeightCell = "{sp}{sp}" + (NXUnits.kgToUser(mcdu.getRouteReservedWeight())).toFixed(1); if (!mcdu._rteReservedWeightEntered) { rteRsvWeightCell = "{small}" + rteRsvWeightCell + "{end}"; @@ -199,14 +198,13 @@ class CDUFuelPredPage { rteRsvPctColor = "{white}"; } else { rteRsvPercentCell = mcdu.getRouteReservedPercent().toFixed(1); - if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered()) ) { + if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered())) { rteRsvPercentCell = "{small}" + rteRsvPercentCell + "{end}"; } - rteRsvPctColor = isFlying? "{green}" : "{cyan}"; - rteRSvCellColor = isFlying? "[color]green" : "[color]cyan"; + rteRsvPctColor = isFlying ? "{green}" : "{cyan}"; + rteRSvCellColor = isFlying ? "[color]green" : "[color]cyan"; } - mcdu.onLeftInput[2] = async (value, scratchpadCallback) => { if (await mcdu.trySetRouteReservedFuel(value)) { CDUFuelPredPage.ShowPage(mcdu); diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/FMC/A320HS_FMCMainDisplay.js b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/FMC/A320HS_FMCMainDisplay.js index 9dc94a89..5cd34883 100644 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/FMC/A320HS_FMCMainDisplay.js +++ b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/FMC/A320HS_FMCMainDisplay.js @@ -70,6 +70,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = undefined; this._minDestFob = undefined; this._minDestFobEntered = undefined; + this._isBelowMinDestFob = undefined; this._defaultRouteFinalTime = undefined; this._fuelPredDone = undefined; this._fuelPlanningPhase = undefined; @@ -414,6 +415,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = false; this._minDestFob = 0; this._minDestFobEntered = false; + this._isBelowMinDestFob = false; this._defaultRouteFinalTime = 45; this._fuelPredDone = false; this._fuelPlanningPhase = this._fuelPlanningPhases.PLANNING; @@ -643,6 +645,7 @@ class FMCMainDisplay extends BaseAirliners { this.updateMinimums(); this.updateIlsCourse(); this.updatePerfPageAltPredictions(); + this.checkEFOBBelowMin(); } this.A32NXCore.update(); @@ -665,7 +668,6 @@ class FMCMainDisplay extends BaseAirliners { if (this.efisSymbols) { this.efisSymbols.update(_deltaTime); } - this.arincBusOutputs.forEach((word) => word.writeToSimVarIfDirty()); } @@ -1686,7 +1688,7 @@ class FMCMainDisplay extends BaseAirliners { const dhValid = !mdaValid && inRange && typeof this.perfApprDH === 'number'; const mdaSsm = mdaValid ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData; - const dhSsm = dhValid ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData; + const dhSsm = dhValid ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData this.arincMDA.setBnrValue(mdaValid ? this.perfApprMDA : 0, mdaSsm, 17, 131072, 0); this.arincDH.setBnrValue(dhValid ? this.perfApprDH : 0, dhSsm, 16, 8192, 0); @@ -2191,7 +2193,7 @@ class FMCMainDisplay extends BaseAirliners { if (isFinite(value)) { if (this.isMinDestFobInRange(value)) { this._minDestFobEntered = true; - if (value < this._minDestFob) { + if (value < this._routeAltFuelWeight + this.getRouteFinalFuelWeight()) { this.addMessageToQueue(NXSystemMessages.checkMinDestFob); } this._minDestFob = value; @@ -3086,7 +3088,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = match[4] !== undefined ? FMCMainDisplay.round(parseInt(match[4]), 10) : undefined; const origin = this.flightPlanManager.getPersistentOrigin(); - const elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; + let elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; const minimumAltitude = elevation + 400; const newThrRed = thrRed !== undefined ? thrRed : plan.thrustReductionAltitude; @@ -3141,7 +3143,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = parseInt(match[1]); const origin = this.flightPlanManager.getPersistentOrigin(); - const elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; + let elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; const minimumAltitude = elevation + 400; if (accAlt < minimumAltitude || accAlt > 45000) { @@ -3185,7 +3187,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = match[4] !== undefined ? FMCMainDisplay.round(parseInt(match[4]), 10) : undefined; const destination = this.flightPlanManager.getDestination(); - const elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; + let elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; const minimumAltitude = elevation + 400; const newThrRed = thrRed !== undefined ? thrRed : plan.missedThrustReductionAltitude; @@ -3240,7 +3242,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = parseInt(match[1]); const destination = this.flightPlanManager.getDestination(); - const elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; + let elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; const minimumAltitude = elevation + 400; if (accAlt < minimumAltitude || accAlt > 45000) { @@ -3305,14 +3307,14 @@ class FMCMainDisplay extends BaseAirliners { originTransitionAltitude !== undefined ? originTransitionAltitude : 0, originTransitionAltitude !== undefined ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData, 17, 131072, 0, - ); + ) const destinationTansitionLevel = this.flightPlanManager.destinationTransitionLevel; this.arincTransitionLevel.setBnrValue( destinationTansitionLevel !== undefined ? destinationTansitionLevel : 0, destinationTansitionLevel !== undefined ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData, 9, 512, 0, - ); + ) } //Needs PR Merge #3082 @@ -3791,7 +3793,7 @@ class FMCMainDisplay extends BaseAirliners { const spd = parseInt(s); if (!Number.isFinite(spd)) { this.setScratchpadMessage(NXSystemMessages.formatError); - return false; + return false } if (spd < 100 || spd > 350) { @@ -4280,26 +4282,43 @@ class FMCMainDisplay extends BaseAirliners { if (!this._minDestFobEntered) { this.tryUpdateMinDestFob(); } - const EFOBBelMin = this.isAnEngineOn() ? this.getDestEFOB(true) : this.getDestEFOB(false); - if (EFOBBelMin < this._minDestFob) { - if (this.isAnEngineOn()) { - setTimeout(() => { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); - }, 180000); + if (this._minDestFob) { + // round & only use 100kgs precision since thats how it is displayed in fuel pred + const destEfob = Math.round(this.getDestEFOB(this.isAnEngineOn()) * 10) / 10; + const roundedMinDestFob = Math.round(this._minDestFob * 10) / 10; + if (!this._isBelowMinDestFob) { + if (destEfob < roundedMinDestFob) { + this._isBelowMinDestFob = true; + // TODO should be in flight only and if fuel is below min dest efob for 2 minutes + if (this.isAnEngineOn()) { + setTimeout(() => { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + }, 120000); + } else { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + } + } } else { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); + // check if we are at least 300kgs above min dest efob to show green again & the ability to trigger the message + if (roundedMinDestFob) { + if (destEfob - roundedMinDestFob >= 0.3) { + this._isBelowMinDestFob = false; + this.removeMessageFromQueue(NXSystemMessages.destEfobBelowMin) + } + } } } } +} updateTowerHeadwind() { if (isFinite(this.perfApprWindSpeed) && isFinite(this.perfApprWindHeading)) { @@ -5190,7 +5209,7 @@ class FMCMainDisplay extends BaseAirliners { if (Number.isFinite(mach)) { if (mach < 0.15 || mach > 0.82) { this.setScratchpadMessage(NXSystemMessages.entryOutOfRange); - return false; + return false } this.managedSpeedDescendMachPilot = mach; @@ -5203,7 +5222,7 @@ class FMCMainDisplay extends BaseAirliners { if (Number.isFinite(mach)) { if (mach < 0.15 || mach > 0.82) { this.setScratchpadMessage(NXSystemMessages.entryOutOfRange); - return false; + return false } this.managedSpeedDescendMachPilot = mach; diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/CDU/A320_Neo_CDU_FuelPredPage.js b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/CDU/A320_Neo_CDU_FuelPredPage.js index 5a1cf7af..0fa6ba33 100644 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/CDU/A320_Neo_CDU_FuelPredPage.js +++ b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/CDU/A320_Neo_CDU_FuelPredPage.js @@ -9,7 +9,7 @@ class CDUFuelPredPage { let destTimeCell = "----"; let destTimeCellColor = "[color]white"; let destEFOBCell = "---.-"; - let destEFOBCellColor = "[color]white"; + const destEFOBCellColor = "[color]white"; let altIdentCell = "NONE"; let altTimeCell = "----"; @@ -160,7 +160,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { altIdentCell = mcdu.altDestination.ident; altEFOBCell = (NXUnits.kgToUser(mcdu.getAltEFOB(true))).toFixed(1); - altEFOBCellColor = mcdu.getAltEFOB(true) < mcdu._minDestFob ? "[color]amber" : "[color]green"; + altEFOBCellColor = "[color]green"; } mcdu.tryUpdateRouteTrip(isFlying); @@ -168,7 +168,8 @@ class CDUFuelPredPage { if (dest) { destIdentCell = dest.ident; } - destEFOBCell = (NXUnits.kgToUser(mcdu.getDestEFOB(true))).toFixed(1); + const efob = mcdu.getDestEFOB(true); + destEFOBCell = (NXUnits.kgToUser(efob)).toFixed(1); // Should we use predicted values or liveETATo and liveUTCto? destTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime)) : destTimeCell = FMCMainDisplay.minutesTohhmm(mcdu._routeTripTime); @@ -176,7 +177,7 @@ class CDUFuelPredPage { if (mcdu.altDestination) { if (mcdu.getRouteAltFuelTime()) { altTimeCell = isFlying ? FMCMainDisplay.secondsToUTC(utcTime + FMCMainDisplay.minuteToSeconds(mcdu._routeTripTime) + FMCMainDisplay.minuteToSeconds(mcdu.getRouteAltFuelTime())) - : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); + : FMCMainDisplay.minutesTohhmm(mcdu.getRouteAltFuelTime()); altTimeCellColor = "[color]green"; } else { altTimeCell = "----"; @@ -184,10 +185,8 @@ class CDUFuelPredPage { } } - destEFOBCellColor = "[color]green"; destTimeCellColor = "[color]green"; - rteRsvWeightCell = "{sp}{sp}" + (NXUnits.kgToUser(mcdu.getRouteReservedWeight())).toFixed(1); if (!mcdu._rteReservedWeightEntered) { rteRsvWeightCell = "{small}" + rteRsvWeightCell + "{end}"; @@ -199,14 +198,13 @@ class CDUFuelPredPage { rteRsvPctColor = "{white}"; } else { rteRsvPercentCell = mcdu.getRouteReservedPercent().toFixed(1); - if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered()) ) { + if (isFlying || (!mcdu._rteReservedPctEntered && mcdu.routeReservedEntered())) { rteRsvPercentCell = "{small}" + rteRsvPercentCell + "{end}"; } - rteRsvPctColor = isFlying? "{green}" : "{cyan}"; - rteRSvCellColor = isFlying? "[color]green" : "[color]cyan"; + rteRsvPctColor = isFlying ? "{green}" : "{cyan}"; + rteRSvCellColor = isFlying ? "[color]green" : "[color]cyan"; } - mcdu.onLeftInput[2] = async (value, scratchpadCallback) => { if (await mcdu.trySetRouteReservedFuel(value)) { CDUFuelPredPage.ShowPage(mcdu); diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/FMC/A21NHS_FMCMainDisplay.js b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/FMC/A21NHS_FMCMainDisplay.js index 9dc94a89..5cd34883 100644 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/FMC/A21NHS_FMCMainDisplay.js +++ b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/FMC/A21NHS_FMCMainDisplay.js @@ -70,6 +70,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = undefined; this._minDestFob = undefined; this._minDestFobEntered = undefined; + this._isBelowMinDestFob = undefined; this._defaultRouteFinalTime = undefined; this._fuelPredDone = undefined; this._fuelPlanningPhase = undefined; @@ -414,6 +415,7 @@ class FMCMainDisplay extends BaseAirliners { this._routeAltFuelEntered = false; this._minDestFob = 0; this._minDestFobEntered = false; + this._isBelowMinDestFob = false; this._defaultRouteFinalTime = 45; this._fuelPredDone = false; this._fuelPlanningPhase = this._fuelPlanningPhases.PLANNING; @@ -643,6 +645,7 @@ class FMCMainDisplay extends BaseAirliners { this.updateMinimums(); this.updateIlsCourse(); this.updatePerfPageAltPredictions(); + this.checkEFOBBelowMin(); } this.A32NXCore.update(); @@ -665,7 +668,6 @@ class FMCMainDisplay extends BaseAirliners { if (this.efisSymbols) { this.efisSymbols.update(_deltaTime); } - this.arincBusOutputs.forEach((word) => word.writeToSimVarIfDirty()); } @@ -1686,7 +1688,7 @@ class FMCMainDisplay extends BaseAirliners { const dhValid = !mdaValid && inRange && typeof this.perfApprDH === 'number'; const mdaSsm = mdaValid ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData; - const dhSsm = dhValid ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData; + const dhSsm = dhValid ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData this.arincMDA.setBnrValue(mdaValid ? this.perfApprMDA : 0, mdaSsm, 17, 131072, 0); this.arincDH.setBnrValue(dhValid ? this.perfApprDH : 0, dhSsm, 16, 8192, 0); @@ -2191,7 +2193,7 @@ class FMCMainDisplay extends BaseAirliners { if (isFinite(value)) { if (this.isMinDestFobInRange(value)) { this._minDestFobEntered = true; - if (value < this._minDestFob) { + if (value < this._routeAltFuelWeight + this.getRouteFinalFuelWeight()) { this.addMessageToQueue(NXSystemMessages.checkMinDestFob); } this._minDestFob = value; @@ -3086,7 +3088,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = match[4] !== undefined ? FMCMainDisplay.round(parseInt(match[4]), 10) : undefined; const origin = this.flightPlanManager.getPersistentOrigin(); - const elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; + let elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; const minimumAltitude = elevation + 400; const newThrRed = thrRed !== undefined ? thrRed : plan.thrustReductionAltitude; @@ -3141,7 +3143,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = parseInt(match[1]); const origin = this.flightPlanManager.getPersistentOrigin(); - const elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; + let elevation = origin.infos.elevation !== undefined ? origin.infos.elevation : 0; const minimumAltitude = elevation + 400; if (accAlt < minimumAltitude || accAlt > 45000) { @@ -3185,7 +3187,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = match[4] !== undefined ? FMCMainDisplay.round(parseInt(match[4]), 10) : undefined; const destination = this.flightPlanManager.getDestination(); - const elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; + let elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; const minimumAltitude = elevation + 400; const newThrRed = thrRed !== undefined ? thrRed : plan.missedThrustReductionAltitude; @@ -3240,7 +3242,7 @@ class FMCMainDisplay extends BaseAirliners { const accAlt = parseInt(match[1]); const destination = this.flightPlanManager.getDestination(); - const elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; + let elevation = destination.infos.elevation !== undefined ? destination.infos.elevation : 0; const minimumAltitude = elevation + 400; if (accAlt < minimumAltitude || accAlt > 45000) { @@ -3305,14 +3307,14 @@ class FMCMainDisplay extends BaseAirliners { originTransitionAltitude !== undefined ? originTransitionAltitude : 0, originTransitionAltitude !== undefined ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData, 17, 131072, 0, - ); + ) const destinationTansitionLevel = this.flightPlanManager.destinationTransitionLevel; this.arincTransitionLevel.setBnrValue( destinationTansitionLevel !== undefined ? destinationTansitionLevel : 0, destinationTansitionLevel !== undefined ? Arinc429Word.SignStatusMatrix.NormalOperation : Arinc429Word.SignStatusMatrix.NoComputedData, 9, 512, 0, - ); + ) } //Needs PR Merge #3082 @@ -3791,7 +3793,7 @@ class FMCMainDisplay extends BaseAirliners { const spd = parseInt(s); if (!Number.isFinite(spd)) { this.setScratchpadMessage(NXSystemMessages.formatError); - return false; + return false } if (spd < 100 || spd > 350) { @@ -4280,26 +4282,43 @@ class FMCMainDisplay extends BaseAirliners { if (!this._minDestFobEntered) { this.tryUpdateMinDestFob(); } - const EFOBBelMin = this.isAnEngineOn() ? this.getDestEFOB(true) : this.getDestEFOB(false); - if (EFOBBelMin < this._minDestFob) { - if (this.isAnEngineOn()) { - setTimeout(() => { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); - }, 180000); + if (this._minDestFob) { + // round & only use 100kgs precision since thats how it is displayed in fuel pred + const destEfob = Math.round(this.getDestEFOB(this.isAnEngineOn()) * 10) / 10; + const roundedMinDestFob = Math.round(this._minDestFob * 10) / 10; + if (!this._isBelowMinDestFob) { + if (destEfob < roundedMinDestFob) { + this._isBelowMinDestFob = true; + // TODO should be in flight only and if fuel is below min dest efob for 2 minutes + if (this.isAnEngineOn()) { + setTimeout(() => { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + }, 120000); + } else { + this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { + return this._EfobBelowMinClr === true; + }, () => { + this._EfobBelowMinClr = true; + }); + } + } } else { - this.addMessageToQueue(NXSystemMessages.destEfobBelowMin, () => { - return this._EfobBelowMinClr === true; - }, () => { - this._EfobBelowMinClr = true; - }); + // check if we are at least 300kgs above min dest efob to show green again & the ability to trigger the message + if (roundedMinDestFob) { + if (destEfob - roundedMinDestFob >= 0.3) { + this._isBelowMinDestFob = false; + this.removeMessageFromQueue(NXSystemMessages.destEfobBelowMin) + } + } } } } +} updateTowerHeadwind() { if (isFinite(this.perfApprWindSpeed) && isFinite(this.perfApprWindHeading)) { @@ -5190,7 +5209,7 @@ class FMCMainDisplay extends BaseAirliners { if (Number.isFinite(mach)) { if (mach < 0.15 || mach > 0.82) { this.setScratchpadMessage(NXSystemMessages.entryOutOfRange); - return false; + return false } this.managedSpeedDescendMachPilot = mach; @@ -5203,7 +5222,7 @@ class FMCMainDisplay extends BaseAirliners { if (Number.isFinite(mach)) { if (mach < 0.15 || mach > 0.82) { this.setScratchpadMessage(NXSystemMessages.entryOutOfRange); - return false; + return false } this.managedSpeedDescendMachPilot = mach; From b1086e9e5e9fd3742c09ce6bbe8fa851944edfe3 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 19:51:18 +0200 Subject: [PATCH 14/16] fix: remove old EICAS files #8485 --- .../EICAS/A320_Neo_EICAS.css | 256 -------- .../EICAS/A320_Neo_EICAS.html | 98 ---- .../EICAS/A320_Neo_EICAS.js | 315 ---------- .../EICAS/DoorVideoResources/empty.png | Bin 48821 -> 0 bytes .../EICAS/ECAM/A320_Neo_ECAMGauge.css | 172 ------ .../EICAS/ECAM/A320_Neo_ECAMGauge.js | 549 ------------------ .../EICAS/EICAS_Common.css | 68 --- .../EICAS/EICAS_Common.html | 51 -- .../EICAS/EICAS_Common.js | 191 ------ .../EICAS/A320_Neo_EICAS.css | 256 -------- .../EICAS/A320_Neo_EICAS.html | 98 ---- .../EICAS/A320_Neo_EICAS.js | 315 ---------- .../EICAS/A320_Neo_EICAS_IAE.html | 98 ---- .../EICAS/A320_Neo_EICAS_SL.html | 98 ---- .../EICAS/DoorVideoResources/empty.png | Bin 48821 -> 0 bytes .../EICAS/ECAM/A320_Neo_ECAMGauge.css | 172 ------ .../EICAS/ECAM/A320_Neo_ECAMGauge.js | 549 ------------------ .../EICAS/EICAS_Common.css | 68 --- .../EICAS/EICAS_Common.html | 51 -- .../EICAS/EICAS_Common.js | 191 ------ .../EICAS/A320_Neo_EICAS.css | 256 -------- .../EICAS/A320_Neo_EICAS.html | 98 ---- .../EICAS/A320_Neo_EICAS.js | 315 ---------- .../EICAS/A320_Neo_EICAS_CFM_SL.html | 98 ---- .../EICAS/A320_Neo_EICAS_IAE.html | 98 ---- .../EICAS/A320_Neo_EICAS_IAE_SL.html | 98 ---- .../EICAS/DoorVideoResources/empty.png | Bin 48821 -> 0 bytes .../EICAS/ECAM/A320_Neo_ECAMGauge.css | 172 ------ .../EICAS/ECAM/A320_Neo_ECAMGauge.js | 549 ------------------ .../EICAS/EICAS_Common.css | 68 --- .../EICAS/EICAS_Common.html | 51 -- .../EICAS/EICAS_Common.js | 191 ------ .../EICAS/A320_Neo_EICAS.css | 256 -------- .../EICAS/A320_Neo_EICAS.html | 98 ---- .../EICAS/A320_Neo_EICAS.js | 315 ---------- .../EICAS/A320_Neo_EICAS_PW.html | 98 ---- .../EICAS/ECAM/A320_Neo_ECAMGauge.css | 172 ------ .../EICAS/ECAM/A320_Neo_ECAMGauge.js | 549 ------------------ .../EICAS/EICAS_Common.css | 68 --- .../EICAS/EICAS_Common.html | 51 -- .../EICAS/EICAS_Common.js | 191 ------ 41 files changed, 7388 deletions(-) delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.css delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.html delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.js delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/DoorVideoResources/empty.png delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.css delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.html delete mode 100644 hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.js delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.css delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.html delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.js delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_IAE.html delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_SL.html delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/DoorVideoResources/empty.png delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.css delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.html delete mode 100644 hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.js delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.css delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.html delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.js delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_CFM_SL.html delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE.html delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE_SL.html delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/DoorVideoResources/empty.png delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.css delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.html delete mode 100644 hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.js delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.css delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.html delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.js delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS_PW.html delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.css delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.js delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.css delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.html delete mode 100644 hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.js diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.css b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.css deleted file mode 100644 index cd1977ca..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.css +++ /dev/null @@ -1,256 +0,0 @@ -@import url("/CSS/A318HS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); -} -#Electricity[state="off"] { - display: none; -} - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); - height: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #RedArc { - fill: none; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 3; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder { - fill: none; - stroke: var(--displayGrey); - stroke-width: 3px; -} - -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: black; - stroke: var(--displayGrey); - stroke-width: 3px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none; -} - -a320-neo-eicas-element { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; -} -a320-neo-eicas-element #highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -a320-neo-eicas-element #Mainframe { - top: 0; - left: 0; - width: 100%; - height: 100%; - display: block; - position: relative; -} -a320-neo-eicas-element #Mainframe #TopScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); - transform: rotateX(0); - top: 0%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} -a320-neo-eicas-element #Mainframe #BottomScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); - transform: rotateX(0); - top: 5%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} - -a320-neo-eicas-element[index="1"] #Mainframe #TopScreen { - display: block; -} -a320-neo-eicas-element[index="2"] #Mainframe #BottomScreen { - display: block; -} -.blue-text { - color: var(--displayCyan); -} -.SelfTestWrapper { - position: absolute; - left: 0%; - top: 0%; - width: 100%; - height: 100%; - border: none; - visibility: hidden; -} -#BottomScreen #door-video-wrapper { - position: absolute; - top: -5%; - width: 100%; - height: 82%; - z-index: 100; - visibility: hidden; - background-image: url(DoorVideoResources/empty.png); - background-size: cover; -} diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.html b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.html deleted file mode 100644 index 0ba9b1a9..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.js b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.js deleted file mode 100644 index 7555c287..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/A320_Neo_EICAS.js +++ /dev/null @@ -1,315 +0,0 @@ -class A320_Neo_EICAS extends Airliners.BaseEICAS { - get templateID() { - return "A320_Neo_EICAS"; - } - - // This js file has 2 intances at runtime, 1 upper screen and 1 lower - get isTopScreen() { - return this.urlConfig.index === 1; - } - - get isBottomScreen() { - return this.urlConfig.index === 2; - } - - // The following two functions can be called from anywhere on the EICAS - static isOnTopScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isTopScreen; - } - - static isOnBottomScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isBottomScreen; - } - - changePage(_pageName) { - let pageName = _pageName.toUpperCase(); - const isOnGround = SimVar.GetSimVarValue("GEAR IS ON GROUND","Bool"); - for (let i = 0; i < this.lowerScreenPages.length; i++) { - //skip CRZ and go back to ENG Page - if (this.lowerScreenPages[i].name == "CRZ" && isOnGround) { - pageName = "ENG"; - //The index of the ENG page is 0 so loop counter will point to correct index without triggering a new iteration. - i = 0; - } - if (this.lowerScreenPages[i].name == pageName) { - let pageIndex = i; - if (pageIndex == this.currentPage) { - pageName = this.pageNameWhenUnselected; - pageIndex = -1; - } - - this.currentPage = pageIndex; - break; - } - } - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, pageName); - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", this.currentPage); - } - - createLowerScreenPages() { - this.addIndependentElementContainer(new Airliners.EICASScreen("BottomScreenCommon", "BottomScreen", "eicas-common-display")); - this.createLowerScreenPage("ENG", "BottomScreen", "a32nx-eng-page-element"); - this.createLowerScreenPage("BLEED", "BottomScreen", "a32nx-bleed-page-element"); - this.createLowerScreenPage("PRESS", "BottomScreen", "a32nx-press-page-element"); - this.createLowerScreenPage("ELEC", "BottomScreen", "a32nx-elec-page-element"); - this.createLowerScreenPage("HYD", "BottomScreen", "a32nx-hyd-page-element"); - this.createLowerScreenPage("FUEL", "BottomScreen", "a32nx-fuel-page-element"); - this.createLowerScreenPage("APU", "BottomScreen", "a32nx-apu-page-element"); - this.createLowerScreenPage("COND", "BottomScreen", "a32nx-cond-page-element"); - this.createLowerScreenPage("DOOR", "BottomScreen", "a32nx-door-page-element"); - this.createLowerScreenPage("WHEEL", "BottomScreen", "a32nx-wheel-page-element"); - this.createLowerScreenPage("FTCL", "BottomScreen", "a32nx-fctl-page-element"); - this.createLowerScreenPage("STS", "BottomScreen", "a32nx-status-page-element"); - this.createLowerScreenPage("CRZ", "BottomScreen", "a32nx-crz-page-element"); - } - - getLowerScreenChangeEventNamePrefix() { - return "ECAM_CHANGE_PAGE_"; - } - - Init() { - super.Init(); - this.getDeltaTime = A32NX_Util.createDeltaTimeCalculator(this._lastTime); - this.currentPage = -1; - this.ecamAllButtonTimer = 1000; - this.ecamAllButtonTimerStarted = false; - - this.pageNameWhenUnselected = "DOOR"; - - this.ecamFCTLTimer = -1; - - this.changePage("FUEL"); // MODIFIED - - this.lastAPUMasterState = 0; // MODIFIED - this.ApuAboveThresholdTimer = -1; // MODIFIED - this.MainEngineStarterOffTimer = -1; - this.CrzCondTimer = 60; - this.PrevFailPage = -1; - - this.doorVideoWrapper = this.querySelector("#door-video-wrapper"); - - this.lowerEngTestDiv = this.querySelector("#Eicas2EngTest"); - this.lowerEngMaintDiv = this.querySelector("#Eicas2MaintMode"); - - this.doorVideoPressed = false; - this.doorVideoEnabled = false; - - // Using ternary in case the LVar is undefined - this.poweredDuringPreviousUpdate = SimVar.GetSimVarValue("L:A32NX_COLD_AND_DARK_SPAWN", "Bool") ? 0 : 1; - - this.changePage("DOOR"); // MODIFIED - this.changePage("DOOR"); // This should get the ECAM into the "unselected" state - - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:7", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:84", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:85", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:86", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:87", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:88", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:89", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:90", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:91", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:92", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:93", "number", 0.1); - - this.ecamAllButtonPrevState = false; - this.updateThrottler = new UpdateThrottler(500); - - this.displayUnit = new DisplayUnit( - this.querySelector("#Electricity"), - () => { - return SimVar.GetSimVarValue("L:A32NX_ELEC_AC_2_BUS_IS_POWERED", "Bool"); - }, - () => parseInt(NXDataStore.get("CONFIG_SELF_TEST_TIME", "15")), - 93, - this.querySelector("#BottomSelfTest") - ); - } - - onUpdate() { - let deltaTime = this.getDeltaTime(); - super.onUpdate(deltaTime); - - const ecamAllButtonBeingPushed = SimVar.GetSimVarValue("L:A32NX_ECAM_ALL_Push_IsDown", "Bool"); - - deltaTime = this.updateThrottler.canUpdate(deltaTime, this.displayUnit.isJustNowTurnedOn() || ecamAllButtonBeingPushed); - if (deltaTime === -1) { - return; - } - - this.displayUnit.update(deltaTime); - - this.updateDoorVideoState(); - - // Engineering self-tests - updateDisplayDMC("EICAS2", this.lowerEngTestDiv, this.lowerEngMaintDiv); - - //Determine displayed page when no button is selected - const prevPage = this.pageNameWhenUnselected; - - const fwcFlightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - - switch (fwcFlightPhase) { - case 10: - case 1: - this.CrzCondTimer = 60; - this.pageNameWhenUnselected = "DOOR"; - //TODO: Emergency Generator Test displays ELEC - //Needs system implementation (see A320_NEO_INTERIOR Component ID EMER_ELEC_PWR [LVar: L:A32NX_EMERELECPWR_GEN_TEST]) - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 2: - const sidestickPosX = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_X", "Number"); - const sidestickPosY = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_Y", "Number"); - const rudderPos = SimVar.GetSimVarValue("RUDDER PEDAL POSITION", "Position"); - const controlsMoved = Math.abs(sidestickPosX) > 0.05 || Math.abs(sidestickPosY) > 0.05 || Math.abs(rudderPos) > 0.2; - - this.pageNameWhenUnselected = "WHEEL"; - // When controls are moved > threshold, show FCTL page for 20s - if (controlsMoved) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer = 20; - } else if (this.ecamFCTLTimer >= 0) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer -= deltaTime / 1000; - } - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 3: - case 4: - case 5: - this.pageNameWhenUnselected = "ENG"; - break; - case 6: - case 7: - case 8: - case 9: - const isGearExtended = SimVar.GetSimVarValue("GEAR TOTAL PCT EXTENDED", "percent") > 0.95; - const ToPowerSet = Math.max(SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:1", "number"), SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:2", "number")) >= 35 && SimVar.GetSimVarValue("ENG N1 RPM:1", "Percent") > 15 && SimVar.GetSimVarValue("ENG N1 RPM:2", "Percent") > 15; - const spoilerOrFlapsDeployed = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "number") !== 0 || SimVar.GetSimVarValue("L:A32NX_SPOILERS_HANDLE_POSITION", "percent") !== 0; - - if (isGearExtended && (Simplane.getAltitude() < 16000)) { - this.pageNameWhenUnselected = "WHEEL"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - // Else check for CRZ - } - - if ((spoilerOrFlapsDeployed || ToPowerSet)) { - if (this.CrzCondTimer <= 0) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } else { - this.CrzCondTimer -= deltaTime / 1000; - } - } else if (!spoilerOrFlapsDeployed && !ToPowerSet) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } - break; - default: - // Sometimes happens when loading in, in which case we have to initialise pageNameWhenUnselected here. - this.pageNameWhenUnselected = "DOOR"; - break; - } - - const sFailPage = SimVar.GetSimVarValue("L:A32NX_ECAM_SFAIL", "Enum"); - - if (sFailPage != -1) { - this.pageNameWhenUnselected = this.lowerScreenPages[sFailPage].name; - - // Disable user selected page when new failure detected - if (this.PrevFailPage !== sFailPage) { - this.currentPage = -1; - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", -1); - } - } - - // switch page when desired page was changed, or new Failure detected - if ((this.pageNameWhenUnselected != prevPage && this.currentPage == -1) || (this.PrevFailPage !== sFailPage)) { - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, this.pageNameWhenUnselected); - } - - if (ecamAllButtonBeingPushed && !this.ecamAllButtonPrevState) { // button press - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - this.ecamCycleInterval = setInterval(() => { - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - }, 1000); - } else if (!ecamAllButtonBeingPushed && this.ecamAllButtonPrevState) { // button release - clearInterval(this.ecamCycleInterval); - } - - this.ecamAllButtonPrevState = ecamAllButtonBeingPushed; - this.PrevFailPage = sFailPage; - } - - checkEnginePage(deltaTime) { - const engModeSel = SimVar.GetSimVarValue("L:XMLVAR_ENG_MODE_SEL", "number"); - const eng1State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:1", "number"); - const eng2State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:2", "number"); - const oneEngOff = eng1State !== 1 || eng2State !== 1; - - if (engModeSel === 0 || (oneEngOff && engModeSel === 2) || this.MainEngineStarterOffTimer >= 0) { - // Show ENG until >10 seconds after both engines are fully started - if (engModeSel === 0 || (oneEngOff && engModeSel === 2)) { - this.MainEngineStarterOffTimer = 10; - } else if (this.MainEngineStarterOffTimer >= 0) { - this.MainEngineStarterOffTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "ENG"; - } - } - - checkApuPage(deltaTime) { - const currentAPUMasterState = SimVar.GetSimVarValue("L:A32NX_OVHD_APU_MASTER_SW_PB_IS_ON", "Bool"); - const apuRpm = Arinc429Word.fromSimVarValue("L:A32NX_APU_N"); - if (currentAPUMasterState && apuRpm.isNormalOperation() && (apuRpm.value <= 95 || this.ApuAboveThresholdTimer >= 0)) { - // Show APU on Lower ECAM until 15s after RPM > 95% - if (this.ApuAboveThresholdTimer <= 0 && apuRpm.value <= 95) { - this.ApuAboveThresholdTimer = 15; - } else if (apuRpm.value > 95) { - this.ApuAboveThresholdTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "APU"; - } - } - - updateDoorVideoState() { - const doorVideoEnabledNow = SimVar.GetSimVarValue("L:A32NX_OVHD_COCKPITDOORVIDEO_TOGGLE", "Bool") === 1; - const doorVideoPressedNow = SimVar.GetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool") === 1; - - if (this.doorVideoEnabled !== doorVideoEnabledNow || this.doorVideoPressed !== doorVideoPressedNow) { - this.doorVideoEnabled = doorVideoEnabledNow; - this.doorVideoPressed = doorVideoPressedNow; - - this.setDoorVideo(); - } - } - - setDoorVideo() { - this.doorVideoWrapper.style.visibility = this.doorVideoEnabled && this.doorVideoPressed ? "visible" : "hidden"; - } - - SwitchToPageName(_menu, _page) { - if (this.doorVideoPressed) { - SimVar.SetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool", 0); - } - - super.SwitchToPageName(_menu, _page); - } -} - -registerInstrument("a320-neo-eicas-element", A320_Neo_EICAS); diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/DoorVideoResources/empty.png b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/DoorVideoResources/empty.png deleted file mode 100644 index f35008acb166bc2754c26028bd43a83cb0e95e0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48821 zcmXuKWmuHo_dPr`!T{1ZGz!u%q~s6+igb=BFf`IJq;$hjg3{g1&?#NgjR;70moz-{ z`Tl>;i@D~y?>94NpL6zJd#$y@)l?J+@IZI~0D$2AySEwu06G)^Ks&(2K)n&cfB78s zh32fGAOolvrP)P2U|L8kO9KE^G5GgJSg7YcH6<;%rlzKrmX@DCf3~-`cXoDmb#?Xh z^z`-hef#z;CML$m$H&#x)z{ZIBqSsvBI3u7AJNg#si~>S$;oA9Wep7tb#--4PEHOE z4h01TRaI4qiHS8eHGY16o}Qle_V!_6VOd#OB_$;l6%~VngQKIPlarHEQ&TfDGxPKF zOG`_cnVETcdE?{bNF=hTs3<)>Jt!#X%aeRKu@2)qCLp!M4qnF0Vmwcfv#)^ayEd?D}d&$~-J)d0AX z?k6j$_H>e77dxlxuT?XIZvQP*Rh`O{lE%lAMxi29Xkp&hXHFdzH6plnaBxr~e||oe zA>sSDh6R4!Ka_}%k3f9*z+*^K+ScHb2+3~02`Rl6_q*c5`)gOH9as7#gsMXZt?h^wU4PIv;C^3X8fP-$#Y<(U z^fWYdPW`zrk8ba8{{2Hx4h``b(9n+!$F3#v&`WyV#61Wvx4KV|?O|wKu5{K|@bf!6 zzkXd)!ym=MLWr2P+c?!vX`MJa%2lALtjx@)DF5kwH^kHa=;KJsrVfA4UyY-7j`}5xSKLiH1Kt=W*wT67znfaq`3)N`8O7 zFp`5nTpja7%u;i4OMd;ghNWBDLq&RSOFZ+gUoh z0(j1f6zTCGo{ldUD-Dm2&}aYB>Dt?&lS7r2U86L@jOE>-_q(Vfpd#jtJtn0(m^0QdLlBX|ewc7~Y?w zs0nUuX{o`WDJ|XKFD?E0HH#Tawi<{7Fxf+k_}=a*ceyGX{4KDlDLnk76o z603~m^^$yOsI#-KZhSlr&h~bEyzl+#er5Z8b+ahHvjeY4Q+s=(yQ8D$Z9hHQ{+uBZ z;p}WhB@vOT>hezv#N}lbxJ@PRLt0OSKpalH{Kl73VneVZdKn9gq}Lk=PH7Fl;?qWu zwOpz3TMyzI3x{m9GPJTvtOR+rB2-wfmfN3vEVi%ReKHPWAHu_Dv?sdA3=E9*05+}( zgG)>KMei8^;_k>QN6+SlZQFOA^cfX+vQbJ|@0q@tdw>1v=H`>pf;M`-ozgio1H0TJ zfcD}({-c&ZDU^p@E=N6{#ys6*`aYhw9490y-~5+BQiUrG<0lnj1X57}9`hwRD$J~} z7ZOfP5D4jzla3b#GRj-{`dV2T8F_+`2?>qD^5>WPRbb`po9vu-Ke?Y{iFf>2$OVGe zgVQOvmh|g5mnOAyiRk?{*82^8AFds3Y-|rNF1m4me{XI=iRd9ZNEOx2m5Yn1LbqcT z)v+;=l+<;OULt^$`qt$KKOX2elXj(zyB$lP3^5uS00mTEUwuqlW>9AUoyN+Tz5~>8 z%MNp?LN7UPf4bRT_ASJ{d13fD4x&(q^^rmxSv zyUoE_+{Mumwj6;4aJBvMa!Pe*C^eNz5f3Win^7QE{6=K{_ZyL>X4DF-U-?lDpPnYa zh!izso0K(s2J$d8C~$=E^9u&EwYIf2>wRu*o1I=NPskOkZMY(l+{EgSuQmSx&KL^L>Ue$(zsnW-rF;vKWANJcH_X{(xzrwPu z$awMnPLBLdgB6mkM@60a6&>xj<_M9#KgkFrHYX7XR+#Q&XhW6rQk*kCy!tJC!nYTzzaWa&{eZ_O}XMSIZE0DKBskxjexta53IAS;5#y0h7SzxTsX~^Jklndt)u8llp4$ zKqS<|Jaky?1~;o{xUMcL>h$!%8_3X``;4NLo6diayX+Bl2yVvcecW%qSKv2;3|gsd z8%a?I@-DjaTb~+Qi}ICUFXi4me@N5T_Irr-+Xk>9ixYvti}E(1@)?CQAw3& z28L6~H>=%U=v!)7g_QopXk72)yLA)6${+OOvWQBB|!|vzQR1=15 zo-Ti;dD0TAYpN|tyC9F%O1|E)1b_UL!xa9=mH5~1osrGd>=#q2kf-|{;;RFqO?RxD zSJOn0R|+}IIzmgkm_OV8F1NRuj(gh^Fh8!Joofp5Pc`)U2!-lPNMO~+lQyGM8P`xd8?7$bTUhj}`p@2r zFAaU^sw_V|(j$F*V4#QJ#2N0H*vEAGo>Yc7*hcXXvnvUn;W}=NML=F2upR!d^kB?x zv9K^JuOyLQ+#SDuotT)_yAo}wtgPMvl+h#xhi1tc2U2ubYHC_oh>2a|P=0&i<9gE_ zoh%_)u&Fd{*HH3&&lVdg(<{<*bKG9o1(p*e!! z)05Rpm+_P|aZ#qrX`o#3liXHa)j16YWhv!2sx>SGRc`UVhw6!nebV2I5oxGO(b2Iy zs3<35f*8xyL`B6e|lW7 z|Nd{iA99aujjWPOTFSzLx=!)shxcJO^5zX=qWh3_0M^Gs7yTi{8>NKz0%uJ)=p1d5 z08=h!Znf|qS%fIu>rIQ?Ir*gTeX%2?vopiNa-}}qkqsX96Oe7ucm6GhpytE;@G_II zp$eRpoKfH|w|jDOE6NM5J(LBRnDqCny!O#^2@bn4l52&Mp}5=GB>#RYXobQZP7gE?nU2*LyCHr;O;-?(Uiz zRXK7_7H&O|FL#U7mpI>hclWUOy@|gzV(6b9@47=P4Sml?+?KU#ErXPl#;51pCB1JS zuEYmVZv~eKv#|I~OyJMN9KS&{U6ExKaeR~SSm`ox1z@=^%Ai%0+%Y{7?P&jZ074Y} zw{|s^veZHs5sf7D_v&knwh5dpv0f&Oog=Eva>y1 znc3UB6ogGc`(J5v-2ci#dm0fwKiAbws=Dz=Jvs)>v~$u+Dyg=6-MEcc$D_ad+m^r3 zQ4t|*?{h~Gf4A{#y&pa?X>@>0^E++$2&1pjjmY9+p65Gm-$gLj-5qcyEe&}^tWh#nQfpnk_MU~x&qzZx#NM4Z z%J}}q0(mQ@_VB}r`R=$Khk3P&S?7MWqfG6_+8R#9Zx&lS**hT6^XnI!GJv8NVPyLJ zc5`Umq>zZe$a?B$Kyc?r!|j-7F<;1h+8A0mlE2>%@hrx~{8{q8Px`f@nlavadhJMA z-rE}$_3+RTB^6z{IR=?huC5alba7mj)u*JSrk;JihTl5}5P7>n=8T4?H3MLOaGZDS zOpK1sM=NuM__>V1jK*hY-2vWqM|a1^GWg<2lHIVrMVhGoEG)W)5k_JR1WRnD-c#FD z@;l9?3QWf`-Dj`l$xP6tgns+uy}Vv>gMGOC>GQDUCh+Hpzo?msA|(4^-;Z~UytGa* za%h#2z)xWL0W^UnYZT8tX*(en6>_9m@T;t{vW$lAkBFjMAk3ef=67#8@qBD(XxUqrVBVLz^Uu=d7-kN}D<~~pMyBs=5AR^l+k(4O1=@HN z|ASPc8?#9{WOFTKnUWTj7!gSR^$ZO794VWxCRpAL?d85p>4 zy%*wHWBpyg$=sM}C8?&-I#=Jrv^%{SyR@kZtxO&TdeJzWAGWrW+40$HYJguO_eN5G z{w(LBt6TxkK0F}sL)Zfn(y@fxIdmSwdx4Xz{ZxErv26BZ8AkG6H2#?QWbeQOX?@M_ zMBLBEd>{WU9HH9Or#TefH>Bz)RBfmicZQIZ9UczJ!vg^1%7(}_^>I`$d7sSo8Xm_N z99r2oL2QUiv5C}UGcLeijsBQdbGp-;qNC z|86{KdBD#_Po|$hV8nD?L+G_DE|uc~?-4Mh`;djGlJtxDCB=EawN7lRpGQNr{rGg< z@3vf(M&0{whd8^VjMvc~RV1;$yeN~qyHk?-jLMiV${w%R*A+mu@HiD!6ZUl1>N+fF z3L_pUOMDGc-RkA7ER1HT&$5R`0X@AL7uZ;C^L~1~PTCBCriF(d9LZQ4`R~>5Mz8J( zE#;=ujyqKgxJ!7*kUnk%t)g&7ad83L0|4oB-5KZo=;fVG1K`><`m_3*suFXwsbo?S1 zjY;obLP0W7^u|o`J<91JU2pV3r%AONNPHuK2u3smG5@I5Z&N?;>?Vslkyng)!$seYC4pF`e##;2d z{CC)k^&x75xFR7wV}~kh_i?|{_uilJKzJ#4WW>I$lZtOQwpQF{7+4iq>+Apjf|XC= z3fBxa5u`~BVE)1Uvit8QVK6C$Ex6xBPzk!GR+q#N|9`ReT4v~mc8n(S8Rxq2ltMY8>a>qen0fDFjV`~(Rw?r~V z?YkW(Rrk|}O-;27Goy12GaBlIp{qM1FPK!h0j){+h|F=88UL9lrdCcIv8NZmA-;5PtKch3Jb2Oj|9D;+B)Q3YPKVgi0K zUS=^?fpCYHE*!2%DPs-2uk4badm-DhzAo_hrP zG6Jt=P<_L3O^x)!_4?KF*oeMiWhDxN#(R@-ba-A7%Jy6&pE|a^4UqF>{o5phNFD6( zv$0K2_b2?2x&SY{eH&JQ8D&lB+}hTsy4=Paf4tn1#l}Fxhy#qTfdgU; z{3!4-#67?B@GgWBRaRVcA5^!^y9PNL*YaBWCXJ0Xn5 ztTMi?R_Nj9kD-gokt<|KC%m8kyOclW&++khA>@=OObXFE1we!w2K=BO`uUTRC+Tr* z%*i((JI1*ebJl2!-WOHk-z~R#oNX*yH#k4R{%}2qB|$3mSPjy{!W=h(Jqx4Z)7wTebtK&tDt2-LbEWEf|7{H12eK8EG+anA>-E%MXhQ-j$`dXDc*=5g3Uu*?)JLuYe&n>dFJ@6tL-0RD1qOUMU+||bJerC$Ejc2B z)GCpKsR&p;54@xhxc;~is1U^)vV<+p3f?g~mw?T0`hmSJBNRBFZpM5CNs4wVvvS_( zZ7+ZCE!zKpjv~!lLXa|>&w-z=lr#%8LlToQIk8)%tbP8r@A4R;q@Q0M_$x_AbHYJ1 zxl@`H>KHFd{vDJNQ7l2|B~O?{QjdJ?Uwo?qH;YQ`O}rewI6Fh}Q$FI7D*dlxqG@R* zeA2}EFSw`o4kG)-dKBj2G3=(WU`9+1mbYK9%e_Muv5|TNuK|Z6G);b310Y#)3+=8Pu%yuukub z{i8SgQNLqQ&XA0jp6uzygxmS@8NY= z7U&|aH0QV8EX7|(xw8D82SDwY(YK1S@8hKQXG%wuSy)aRj6H6)Gc(0s&|46{WRZn@ zl}{w_c)YQoGs1@!7Ot;LX@;@01DE2=V_UZ-!vBB=WAI!ce%bqxd_zo|| zadVZR1=Re(6;2)*+wYzCNP~2mr+mB0ZlHX5vAfC`Z`y1gi(WW+uCDale3CxK1x)j> zf=24w_CP_ps@1Mr$;|`K2n|IQE7fLmJng8k!W4Rz2HaW8t0IhXze~5&qlr^+_li=c z`K}nn)3!Cg5Jjy`*V9S&q{d`m66aL4<_gG#Ef$>%nIoi7l{4E=|G%wT;)hyWXF~WV zB9)A=ccoSolIS1L&v(C|FGLl;qa)BZK+1rorMEpZ=VAjILnHAtXG+(bW z@V%Ioh$R}raLMQ6Wl06z2inu5PPb(V4?Zz!S?CC?VS)g#cb}F`%buwK_2@`vbV(qa zq_VSDRW-pYEZExm`!jdm+vP`6kU-UhH@lU$<~HD>#Z4vhu|?UfC%{hJxU-rwNhSe2 z{|DWh@<(kTx{AHgZOe&7gZiX36~*KUw0hMyaa`NvaETzxPXS zZ&AHl{r23z=41se%B;2-59+o0_vh3ASSt6eBISs4eQv=hn|mh2_x|0~!;t3vQJf`M z`cHK~jh!7IftPtmyLHlAx{VKb;}^BN6|CeXpw-F#XHl@t?hAP2q=%N6JX$i&HykAB zziWj(WY%uk%mWVsZ;&IBWD|J){4G!{VmDZkkW|TaumLLhg%M&W*l#k|xr&}ly(`4v z{RUQMoTT~VcUAQYM{Yrs+wK)bgSIzD>`}>e^I_@F_rx*Dj9KU$1u5f#45-@@_m#u& zTzyp|D;N@k6oNbu8MI4^qV&`LnDpTxlXJgblBi6{y2~Z1Q9PD8=U33<{O^a7Uh)JIe@ zpsW954H87Om0)txLpU)5BwI%_9Iv!Bn{VoPphmcf zi8#mzY~&FwCteigeJxy&geOiOlN7F-h$?-= zC5eX?j*t7rfPs2RGN2Qstj?k{Xz+M*xm9vwe#c9wccb`}HuXn^;QX9rM9<#lhqhOR zg=qWd79e!vd|tYh;0_svG#LyfPPz__8m-==itd}58aRJ#-BOrJ(4R0>8ZBFTPVB5* zo2(X!>syN_)UQmSdkj8wVz6kQ$9LqGEPg5)pZ>n16=wIL=oYHYzhfv^l@ks@@fV)o1rNqlA@%8=ZIw`16b6lIGu@ ziz#}Xauc{u>J7B6?HNdi*VYO0(+Q2+Lo#PdacyD(#Q;t$ofnqge!s)TLwv3 zca-L&>a@Zxo==h6N6{0BaLchn))Wm<1m_w3_QhAfNGt5kgOHJ_|a&**&EYRfB za`{^X$B!Qia@%`&H6QRSn@#*aDxDp7X%|_&f+7&8-a*b3fGt~J?c^oS-|daH|8Q3Y z_K!H~!Yk@1X@`D;x{PGy^Zv(A)pb;_l(5PaOdzjclAdw%d=$;pwLGzWSfoLyc-?XF zoNO5(b8{aa)=i{Vd9EgiD}{);L}_uyYU>fOf~@qi*s6SEnSFhcM6p)zokj zH8l=knza?>8WRgf(yY;ugJK;t_=tSK#qWRmKILOMC}?NP`1N)zDrI4p&Q+#Ib3$=& z6cos_B%ures>qyNM$K=wjpy6L^idTrI1%K|f&VEgSsMlq3b0d?0Y87l$kf2s(*QIr z14Fh3QU%b{Bp^e13$=Fe8G**PF?Hd$ujY)I~B&jLl!f1 z>@#4f07+2_snu>D>0_L3#%|C|22R5#?rg?(_S6G?w}= z0}GLJWokau)M8?lhEoJ6Tp1NA2gm+zz$OWZY_6mlOx+(KZV* zp${vsR8>B;qzrWE!_qlkHZ%y3og?FOAT9eHNUpZD1XdhzBE0zA6`rU~@E;?tjBG@M zY$@%2GBD4UHcWZb6I24Bx|pyEzriQ2_?e|WhwGY+5+T2)>b|>K!!VG*ViHI^w9HcKP((^0 zN~ER82h_%mpC^B|zR#3cSl(_%>5c>id9{LnNz=2wx1L^gGRY?}6f0l7v-#s^IIa)< zwiX_~v~*~Tjd;h?+&suspR-}GicOjKVq@&1ei`KsB8X zv)En*Y$m2(IvU6XZrwVY3AAZ#D&)sm?#`T)7}UgIHJ zD4ZG>T^>=~f1lll1T!c5(_nu#Y%fSv$_-E6=!3H%ZG@8@{$y@-u39QFI^t1;^-+oX z7nC4$K8#VqsY}#Je+NhK;6WXA>6pX87_TUFb6-ilr{~CE5x_WS_4}yJYI*aHDxK5B zBsBE%P&Zs${>h9?${HR=pH6_%IKy@jaL1)YHMs)P%PN`hVDYLjt~c6Qu~P;%wJ)o3 zCJd{ZzcPdp8WXH`hyD*b;B)#sF1JZQEbxHRnESo>34%G<%6U}f@uYO8UC4=n?enwE zsX_si;1XIM6Wv%v`vj}2>WsTz!s!aa>m~c&pWn=$S(Ys&(7=rDv?4<(Oa6FhGNY+{viL*YU@q-AG2K?w3qb)LuC8UHl9nupcy|0$_B z6l$kAq}boUK?3b>PIri7#!MQY6W8SZX8^<=YMvb4J_y9&F+3w7qbmhKQs8h2haN*a zF~vjpiQp1BS4T-->|1-gE#{huOyQMdK7TjaUNz@A%+cW!RvkY8HE8d9us#7TQSw<-oGsM>=INt zX$RQKr`+>p7xK;&nU(zLCoko3iJUcWnLY``6p5ifKRE*E6c?eDm3&1SLwVs>xMh?}g0PHI zJzDvn%??@f_J`R+c;gV2PTDPW2D>H3*(Dp@Ia^e+t@ZP#(k+CH{6mOXpdg%8jalDW zYb2{go5JKBl>t^D`0gT{a8iZAvUlOJp zj`58us*736%d!!N10-FS>;G(2;M@dz*Yr83!HYMj!m0hwrt}DnGoZ3;oGh0uk>NfG z{1C|EId07OJfRbo!bc!7v4%GA;LT2uB!w`gdKs@^rSQc&tS$#j2e_}ciE7Z4C}u5p zS@%G)GyQC!UiLs?PQ~(P@HHlc*xwL#bG0(dAbg6Mxb~fhL76n8R7H%ej$WtEN8;bV zS5&1wjYT~Y>T!0PPtgWmnpItVcl?)sY+D93PHgp`>BZ7tg$YKG75S0p{N3M2Yc_vg zX4y#kM`Z$!!piHv8rh6uNl0Qtpy*gAB4GD|^K+f3q&cpuc?cvetM|KUN^fW=%8Ml0 zVaz^!#I64vE{cpbZO_%JB`X+TCHJx6;VCSPiN2K;bITSi!6Sdi7`2kCFqTOztQHk> zu6Qh|#qeWpz^M6T-=sGVL%$Yk`Au;>t@@8;2emMHLmPL|>(@%*@8{Ta_P}~va&EYQ zjzJvl_Ofy=Q9%-mJk{Qk0A?Nbcr(3}h_`r&&@b4<-K}(f(dzWk@4J`Gz@3UnJZ%CU z0`mW^_FhIOI$@xT@AR989bybIxa)h0U2TURZLp^m^A|(-A-AS5ikl z^DyhLwNt#phneC*K)z-3ryDAEgN(bi-a~A0E4IC7PeN*yft}&tzF|~?eZ%v*X$aG} zI*5UmKs;rpHzML(RIX4~ZV0;#585M}cD!stf@V#|HSHvj6O8rxm>2M1hJ5!rX5j44 zvRxWow%?Cw4}!VbUwpxZpV+ko(M#?6S(RD#qCXVhpf^! zGRU|w3BlKUunQ`ruZuN*v{=s1OMxsIj*h3&!GHV|-25+5pv8E$9kWMF$knO3@!CRd zVg%MLVUEP7z-^{J$y>qoQ(cG%9}v@}f46e6Y)Jv>mIfJ+bH!ccI@W1hrq zVZlVvd<|atj=s2bmuZaZOWT{TU&%`&C<~AfZSz`_i+TRNL+&zxAlPNrjaXxQdlmS< zrU11)&28rIZ-jcyo&ov#RfW5AIhmT8MTPs<$y$TL1`-n7-{T<4Px+te`E?CxBozS- zvINCi>Uup$`fG((oct2x8FYD1nUvkoI>^q@e=O-IL?5Me8{>;vI!=DQ18g=rUNqfZ(DNb{VKkNlx#wrwnX-htsTtt}V#Q`sX*t zoP!QEZN5verTdsk>AeH%CJAO}=A~ z97d}@?Q}{D1_qc3W2hY-tE&Fz#wGX0LJ|^r8oxX2tZnL#oJu{!$iE|;`%aB z)HO6@F?KHt5xKcJ??j^|5LkMFn<2GEuraK>PQ_mb9o7QToHVr8l3-_(1FGO+;n~cg&1aWxJV+O zz3uNe?&XX3>op8PdFI5?xG?p+JJ88lVhKZVh!PUe$!W_QUiaaW|DgDSS?rnG1L~R> zv{)74NMEn`G6+x7%C&r!c(pa^dymHCDta%X7v@hne6f^H!0AI~GC&{I)Ktti-rQC{ zrBf7J%%)XG;6{)gZ$=jKJTD-@VcwyTtvi61N(MO?mzf;#xhmqtMsFs6RMG#CLQW+* zMX#%iO9L1V5bTScldJ~(gfgZcYq6#qb7H;~WMWK21&IlstGYSZ%n@c1%M<)qKXBTiXHv1PQ^zQEe@jhh_-VulQ zi%f-p-%NNJ3PXoZD|Kyv0x;+2pBt-VS-oemVq&DEz)PQNUP(!b5fX(~fq2S1Ubfia zKkjP2wudLN*Y5W}`WT1Q<5-b7vgpX7x7eH+k|^Z^v>jZYaX@IsmV-BwNhEmJOU${W54YL>n3O?QRP;Ja%g@4ca6u>@L`|($P1@$gdZ;CAFw^otvA3sW-QUMlLHb!#T@Dffu#GynYu z3O+#Kf+b^zD1?$z%rmL>EuQ+aj{>rLLc8MDFOe_x>eLerJ{0lq*De!;1KERF1HsBNt+Dh zhlcj|lb0p(G&Ic3N^xL_k7a-lx29gRFinXU{u*7@GKeuQWQ%g^QuFT_tY%#4GyWZR zBz<{A8`BdPz0&((!Jrl9@dz}ua3sP{FfOF>FIlGD+b~Hv&=PWrdp@Hir#7SI3X{o0 z(rMqw#1*-!fD|H)92)VtN_@%6gRx}1@84Mj4t?NjTom-zrs|y09t}e_6&9#+|{3!e6^$tDgNZme)0Yukd|sYybp2?-|Y4mKQHV6EjRev)!E-71IW;Gx%C=Z zsq6Fj2er(Oht`jh_>8Np!V?E6q%?z*Uve#es%^FCnIo1(t&Hc+#nXtgjLOJqaDUa& zBBx;JqbmX9l^o}RdB6FzLWyzRN0j2Z=c<4K{pm?w2J5v`Cty^JH#atRa{9k3H?BBG zh1#_JU-7%URI;EYaaLdVfqhtM24q|MRh*Rb?X|l_XrkyT>ti4GhyFhW^_nD*a)T$;h{d-aV;y7?0- zi~2t&{oH8XL#bL@rpJ+Zr&TMJiqcv&3ef1Yh#AI32A_|2`nz2QCy{fBQNi=k>`gM- znHI%Dpt4lC?G3NhQe3m_sy&rM1Y-}d%@a#Y;7>ZItOCXesLgMG|NkXQ z&Xmte&iUgyy7qyWXUx9}s1BxETk}4_tV?;dH#jH+)u?2Bl%7e5{EEty$o*jClhI@0 zfV0S|^Jst=w=If=@k(IErcu4K*tx!b^l3ozrqm)-WW!I2g;8PrF8{58D4&r19>PLQ z`Dnw&=QVMt5{gGrV(F1VW;_TuJL;q@=(#`buWaYLw!g`q*bUZJq8-~$V8vJ~4T+VT zy=PC)IAeDlhNc_=u%P~UGsWJ%A>=3@q`6v=Wi>{U+Ns%_H&h+$>@IKoT-sq(*Cv7? zxiAUu!MJn6152QX^uVTB!;n9VU>`fdbvi95f$X6NGd%}IH7JoxUHAviS)6I)ou4P< zW(46G(fJ3_dn>c2;{%gF!N>~L!nFnc(X|N}swW~9M;f3mQHC8koDSP*{jB=W(})j~ z*yxxxZRCa&u}!5z%*SM^|96AHreR=H7>yOiHgiwD^qj;*b3YXv-n0zt=LS!eM*)guWC|c* z$6|E0EJYmI$gEY)e^gQ>8u3QK|0X7)_S8ithzSB32c*lLDANvewfC;E@dsnMu^d;F zf zX~|(r!JtY5@PSPrZJ7$lpFI8rZ(!0cN-2{W1k8E|Zjvle%uZ^ckS5i;uFKy@720#t6o?UTnbtur!S9s5dgou9634X zD}mMI5+$~Z%5w+WVkWX;qX0yF+_9%4%k~}7aGY2(ZU1EJ94$77MiTsgtf>TYr=y3;cx6CljtXyfs<6MG%z&=!jfl~k-c1K4 zgW=lRw}}{ivCOYLt^=egeKZ;xwzpWhMsFd%zCiPZGSEwc~K^Cvq-BlruB5pfIC92#ZTi^i5W&|2=pVtNjp~@2 z(^W`Qo;rlWZ#?%i>xiA&NBwsA~gjK z`xIIA#;6TvJcY2!T?DLD1xZ-z4~ugi8Nj+awXt6Wh_oauzv(8HVR1f3oYKjas%iK5 z2^fl{;7dv|>Jwm?rnXCxf+!QsI4%_K#TT^qK&G9;`eszS$oMg6&$TY;H3X1-Vz&Q6 zTVK0Lly~;c?c6_Q!7r>qwX{S5s<#*vx9dbHtpZECHV$kJtR66WkG@XQ7I_ZnVHC9) z@q!gLmu>GPy$i$Z%B?(S&x`P1A-}!85 z%gId0^0Ec7(75M6pvgd{29SVF{Oa3#+#e2y#nEa1C{NvcQS(?E5sL3gGb)Lje6FHf|H^+@ zwUa=c<@1eJFkYO7`;nJvK#VtYNrB>;JT46V(GyA1bRV$Tqq1lTIBytrWSDg}!fsDq zTe!FYN;iHSqBMI9>uIVp&7y!g)Fg)kU)6G_r2$E3a%vLn^e_yo+p>dS`vubLCnwS1 z@c}1KWf_#Mu&}h${73O%O-*PhA&N1x{QszW>!_&Sxa*tlhM^m&AxBC=xZ_kPr|gL?omX@jbu$xu5l}XD$Ao1H-w_xvuZt`?II8ki&YB zId5KGdu3$M$n%sfd7zmI$!=&8z}|VUH(Np-o|t^x5o0Vpu1_^IT#$;ZenmD83A}#c zLudX&Ndu|8i&noqqp(ND1xrLFIQ=vL)8s*rX1`7^kPQzdgWSeskeyOyq*g*}^}pC2Dz zTifT>pV!=2!~D=DVaHSEQ){?URV60o#6*7pWE%TXuSkAylA7|L9V;s@kD^d^m=s|? z0%_e;Z(mXyvRTHA2kr;n*c|hLqUpW*sqj$o11#8OrBe|ma)X<`-X66kE2;f&ETB?N@grq%b~&%-p?3a(F^g)VJd=Q3vXrlD^$Q4YTcC%7kNz z4}&mUdz_odi-loG6N!!>&sRD;eL&HkQuMu+dx$%t@#C&DqOL@9hBw+D|P8UA4et z_I=c{R2&o2y{X++XA?CP5_f;=N@7<2c0b3p7n?yvI)NmDMt?rJ=v`lTer|3N0JT_K z+j256Z!9kRxhD1&=_4&DXxzx>@@NE>2+VOs5r#i%?9vEviI|CF0`}#CK@q<+y1zrZ zyHV%Ho!u)tyTnGm*0fI+nBQP~V^QpBVkFx#&B-a zEFpD@+JXo|Sjf36>Q?l9T;nS|NF*dSSE*9WuW6!O{#dp7sF__FEqXntI0bD4raDRUhfOB{rs>K5Of( z&3$LkJdHz_NAoO}mToa+ZSmDn=5STuA=5y@u`Vt?QwJZtL&Gc50fzQ4nuBA5n6xJP z=XMgUJ8NlvS#PW}Fyh??QIH{KyNB_cqB2mmo8S+3#;yc+I)UV3Qv(I~@QeF?lwb0K zFHt%i*VGQzxXp;>5+G@~#iG9OPl$t8y&jX^lESn90&5%-orWBtu#XKO#qhphHFD^W zid!GR3>Qs&Q>0yapW(@~c8L$mpllqZH@x@JKKaSU_R8J%CI2Z}fP~$w%&Y6eEDmG; zaj9c;JFNtpk%>WLsnK-J%Nfs@p6~d`O$v|AFUaYDnco~d4cDDu|B2`u13IBbQH6-u zDB5tV-0PcD7Et9mn_AL$T=d}D*50o@oLbRXJ6ywRyWukHr5_uX$Y`HpUQ++Ypz|nO zXU0=S=yY*7<&bu@Xtdws{uC8oIPNjFDR+#;O$T7fVT;&@QF2duSQJDJKj$SJVDAf( zfGF+Bn^FQhlBPv~ULb757#lI>Wu^Xh*u$(i*!xYiS}!eEu(D05<=P)M08f@H75; zReRbaqkY$6Sj|Tzgi5${9ZZ6;Y(QrBK8JR-0uGeYY>+JD(6L`jp@KeK&6z4rR7Kjt zB6on~>7|`X)(Tf-fNZT#r00kOc0V`ose;dE5}v5}7a4Kc>Mp zAFIe$O3HDk=o(3nP02kQ{c3Z0DgF>}Z{2$0;W$ z6XXyP#vyLSNh)DUGHdCFmT9ujBed(JE;P$tXol)5(E2ca{uKC{9GceKa5Ey(v~|kY zhWSe4$mQ~_cG-m@ap$oPUKA~uZj1dW8Xi*L5Q(yL{P;d;`5cm_dfQEK95sq?4U-EO zHii$UDfgGIk%?ZF5H6VHx~YOs9N+};bn3tGgYg=Jnu>v!4F=K_c#Kia?b^DI5#>zx zP3tjvIXfHUM9YD9U*=iNj~s6}vU;4!O-*^kpdkY8#fyQRs5M-3!ZpCjr#{Ik42 zth@N?In50+%V2y_LtFY_JGghUF|QIdIEm^Tuq|OYQ8uz33doDPCf26K zi(-GK`4NLHrifty|DigjEQLp3}0JLAANs8<<)4X)rLgb;a#SicyeSvB<@yWRJ(k> z)ZiU4yr0APlz`W`^fY34skWZTB&B;KJykCri<9;A!f8X@UNf_h=gHzVV2Nn-3Jra! z+j<*3In+EkdHLE}vZGfHqGbP69RapoQ?*g;w|7!>JpZhfuQAc%Vivd@Yk^Vi7fOt& z7IXQ`fUWG*>;0RuppKKL{!DfKqtYtCeZ~D35*Ml3si@XCCZ=bbOwJJn8%8k>j%$@1 z+k?b3rLc|Oy0}~(@84s7q>wR-i~Dol#8RqVdm>LDyiD@x8J@SL3PWl^meL_$^1u}I zC5O+0!llf`w?#zW)4v{_<@4mQyu2hi`IW*!Dvj*C5;DRlCA>qd5Sotk!Y&9}4+ zMH23m1ovoBZkGSts%yA>vVVQOnoF*hXfjn2{`yr}tYHPgKl9<2lR^m3*AhhrjdB7s zUG>&XIbKvmM_-%jV+`a9)~WPWKQFEw^`|xtwYqMM@u$5xui|!LU^Ez(IQdoyKhJ*F z!cx5;)cxV7{V?WarEHvNrekVa;X;n>!MdrJ##C`(si>WaYWK4v8oeh#f|qk9>Lc*R zkMNZ;x3bqX;iJAfQ@Za=O`(J)b7b<;Pf1I2B+V9O)+G`mb}y)2Yvy35ZHUoNqxF%< zT;|SJAMZhyPW;XCBKanL?uOEyzIMzs;JjJI;bI_BJm3rKgSxbR5(2kbpgw>#uLiUO zZf+B_r31NAN$sbqe_o&duq}JA;}EtXhV9{8Wel(zMv51>4w-NbeEkVk(6f7tpf5ZWeO{QkWD##81t?{PH5AxMx|$&QRa;cqBj#T_A@ zhzzHxW=zhs`>R(T$lq>5ItD-%Y6FR+#~?CYrUwXI5^Tb?`O3R{BESH6tf11LtNzA=*B z+WN=)u?_N?IJH1JXt}YOQ~zb)MwUsgaqWW3sQ90R#~js;O`N*hI$%ss476Hh909HL zqAyo!@});$U)I8> zRILTJMQ8iQnF6X~5vEvl3<7_898K*Q3Q;76+p$C1nS3%awq5QIpG5>krF&qFBh9M7 z8(ZG!4~n5RIR2SI+(ZCFqxwrXl;jpRt<@S)=ZP|gKxCp9moKAHH^UfR%C*m9pG9>| z##_KY$bE?MX$2ebnBe<~$BFaQEDWnLdHNlR(Wod5(=Xi0$`urb{{2iQ8|UKW#K*%U zxESIb005P|GJ@URSy-=owCHFH_$1|1IUHT8xY3IdHw~SYa})KV?6%dy_Oo}ut`Rg< zkYu6XJ=&c$`VviG%T*ETO2IBcbK0h5c+Ep+BuR6?5^q2AXiEO>j>@8FCMMLG&{G0`jszU z0DsTBBn!>|_gb6(_Tj$sSnq&)aJ@KI=@GM3-rJT;;gLCff%=BKysMAIp@dgEfYUm8 zr^R_A%+Ag~XEdX|BP~s5P0DT}chkM4#lm9t-MO{}6nL-%fU!k8(YH8>h&a%9)-NZ2 zRXcUIsbu6kU+`H*R5SU0O+}-RO`b`u+{m)fzvEQj;Z(2!_HoAaM!1Vwg639D3GN+h zsg&g^@%)ePm3F^j4;870_PD&#A2v9i4Zf^KZna(lMj34R6(DgPMFRzp^ zIc?Dhe`4*Y>dOrx_9s!9?#6$A?JGU&!x5sa0~^1@MKh`lV`=QM7;G8`P%trJ3m|z9 znUq-nRG=#zQJ~F*`z|{Oed_kdK7R{y?oOip|s_lq8?5Q^XEp{n|D549glD=x*jT`OB19XZsshgUJG z5G}@cL?#Il`(&1*1-doI85z3z-W9Sil@WILSRB{R58+IH=?nkR+1UgEFdDdO zml>W0W)Y6uZe%QP4iW@rXBnzH)*ejM(*@?&J9MAz`i{pW(~lepo9S5L(e-`PSA2%? ze90bXnC<>vE0RIBq`m>aQC*o+c?n1;2jde*!jd_hBFD_@5iT1)ew-7XoRW&h#m5U) z_f}z(CMPp$;tEcY*0O1G|1Q2D}(LQcy0s_d-=tS#YJc5`vBS6NJ#Bwx#V^o4QdK3 z5jSWg5UO9Z24ijc5hV&PCNkY{6xU7Nq>jJQ-FSBtxBHd-wJK{A4O@SyvHP}B21sxt z>(?L_H=4mAXlfIH>0MOdFtSFH>Wgm-6S>&!)>_3mozT4R$t*Dr8JO_4>iY7! zo&)DEp}XEiEr}qnsW2bUc;@0_$DHU}sL|MDN*)$AdvGvG_Fd4EZhCcmPvc>Pg6xnw zemtC`5tFg<`#E%)N-fu!m+{FS$swpWrUrXv2M6aa7%K)ikrtfZ0y?@4sJ0jvOyl_= zdiil;nm#7*-0pQ|xsm9Gph$s*6|SJ(&OD`AUZG=P+mS14+lSurwTHXQ!NFDfG!xOp zIilPG03BvlQX*h3zR%Ao!(vC$CAHbiuGQwr4Mo+CVCaL26#G9tm-4Y3(s5RKk4`iFew<21SyFS2SD#>(@Fu4K|k-mE&6Zaf~V+W8}Z~_O@85ulW-;t*iz50NY}`biv!Q zvZ!I0S;X)Af;fH`vom81>`L89+c#73Jc9i~9$9_JHg>u0VtLqqhF%1aBtzaMnIlfK zT;??&eRsIsh6m*z*$J-Wn(F9m$c?148CBjx{?flrP{OHeg7CbBaJ#=u)}5>C|M-hW zlTL^zJShK>m?yD$QW8y$DaX9Gi$-ls^aMJ6BPDi+uNxVm-c@P6ZnAqG;`_Q|DBYfh zZU4Quggku;nC{5}&GmrxVxb)Nr*nvnt~IVA9k$K5K{bU5949gQHc<5yjleWaBARSh ze-RGS7j&Gx9G@#>DUJKVsPyY-5ts{j>%DJp82WmLS^EJ4oi)a&;3#C3VvY>jzB%Jx;h;sQ9te3Sc!PjRl5CSdneyj-DMop{U(=L}KK*`*vMrNNC3BoKabiWRcUgb#}@D13y{ty|OV^F-l#Zy1kFJ)}?)M zjuz)*gr1BV#GS!g7}v6Kk)YC#r5_VK#!(xN>GqxkE^+b1LS^F<#;1Q+wLMFQpZG>q zzhSTH`eCB>o5$GW&b-PFW?lRK7>!R$#0k<&t7OL<>@0OjBM(Lr7T!Di+QWtN5wy$w z@990R`0ClxQHXy(ACV>1jQ6#C+EcKVo^wk?}F_fiFTJQCT2^KhPWw1e{xBnw!;KDjgJyVDp<#^5Q&Q2Kgo02c3zR11A zF@657aofGliOt4wckBB~FEeecq*PTU{ZwAjL5Am?H$;u<=30oD0n=!^n8IZyim&qP z4MQ##mT=y6U};4O|0 zM?D?1(zWdn^-6KWARf;Ce?ItMI2o;ivs0!!Xziyqn}^5B-_MLXr3)|d1@cdyzmp5? z?$td%%XFol9W@~*k4(UmOKSx35~De4TzS_6It90jQ#kFjMTJkso|`O(^No1talvS34+^3tL90yNvwm!WC4T(whB-L(4@-p) z5u6C3hM80;3%xp8{4JB>_pm^NP%l2V%YL)-+N*>?RW6Hhky|oC#ROl1m>AS84_o5n zm)gilX7|V!{%?{iB|Yr;B+bhoYL9Re#5VPhaD1JjtL|W)y}*Bw5MTBD8Q<3M@U&hd zmLTvm_xVdzfE`I-V^jsZh=}XSrRV!kdmFh2zIML_hUNGX1HYD((l$Z=O=%=Q(gAN3JKHS&o z9~3vhg~VlMYG}wAM)Etssk4{ z>qYR#IHtbcmK{;^e4Klg-EK3P&o>ASAcKzYD0T?GetL53#m2lZ{nP62Q@mm@Bb94E zG1BG{4``Y06f+yX4_v|`$?u{2ek>4%-8Pz1;okN^BT(*SVD z>dejk_@<1-|ydF(>()ZW(TV#7<&<&(BL-=^I+8{D|qH2_%S6uGPON zUFW*&@3Ux1Xpv5vsPWcQ(^0AJK@YiW+Mkhi%4M#4!*CrhS3owxQyh-{qMt_7biw8p zlL9FQQ*aIxCASiPmW+p`$I+PqJX>o_e3EjX7#89Pac5MT!9)2ZF5o<7u90{oL6x;; z^l<;{OsuU@G-CPxUTYVw5OMV?a=$ziSy}0_YN)hnS5D7|Ghp|bcv>o%!SreX2#Cj% z)6s%yfI$j2tNrc$-8m%B%4&Z(M|>wOH6VafBw{a~t#wMK2}j7fr>oJ^Q&H(noZXv=Q-eg4wcc{>GkdtGB zZmCw{$$`~mD~B+jg>5$PY+!t{iBhAv{{_xKF~*`_kerXS=OsNawS`W&XA4SZ?-2}{OAW2LRmQ-%7y;d7a<# zg6e{C4N+Gv4T^OdT~SY{o|iX-{SKyKQ29_s(_(kYVt**w>XzrW6eRAb_F#myOn=dg zKcrGKLXH)M4a-~5Fxp5Z%~&K@__5<7UxoYTSqhvEJW*7H5$13rjw?Gu4hNC`$DCBv zs*>kvLJK=oY<$+Z&@Tz!Mr zWVN<9uC4Ysd5nr3&xL;GLgN}-n=h;T^fM|kYpwQxy6J z!PVw~lekiO_cnU^_^i_a^y$f0m-a+d_XTg1!h#@CJ_t_Q24`0yRyw*m=UJG^o$J50 z`J6dBvrt1-d*r1PZg^4~nT^TNDwowu^rZHcip2L6gOc ztoP!tOo$e&8Z;>ht+&XINbz7A{A5sH8xUrenCIT5XAs=%(z+Na(q2fGUtI4(uxdPu zq$=({(!8D|hv_P}>-0Ox+8D|(h`wUTr4&#tO9*k}b8meiC^3@NGD3S6nHF$}!6@+t z+Z30i1JF1KU{nq;%|{k*`pH{H`=Mw7?DBl=cS`Uq&qClK`0Mh~;WvvV|huLcN;@)K1NL z0#oMdN5bG5_t4I^oB(M~CGlDllb=|CnJGV3a+}}OMtg+wh3>ln<^_WZE!Hrrd2mYK{$! zv+I54Ai2uMabK6202TDp1d+2u&a;=BtHtzEQvUu{atru_rl_|jV;r=OZwt9WKer%9 zX@Z_@DN_hq6Ql*&irw193gzPy6 zl}E5!^%&*7HWX5UGY77iLm_J1NfLYBy5O2`)ej-FQ0$*diYilQZJFrQYyJd znE0}pTAfP^KPLKBR%*>FUtj+ z_v5Czr)(NmYru;7qPX$8e`m9>LB`Egb}y1ghq#5uS|qmw%nhV;vu)z$D_)J0ORFFe z*iS=S<(_jzs8JR?QXw_qv>TqwcYfJQ&7|)*7@=5-cn4wE?jVyiy4Y+<_-tlVbu=3a zkZ|}`kDaSEi~f5o)!rwxt8Qv42oU*0w>iyau-n@`{4?Z3iA)9Ywbc2o6&umMwzgrc zG4!eJn6r}bt|9Sh-yQ+Q3Ad|PA}(goA=QKEnmy+(JvbLrx+Msw_F{K_%x&Z(o3Ssl zwBY5ep8>nBW!x2C)7R+amaR$gN5h?)D-@ez20!>Jeq{%GC-6ou0?~#7-hbk=i8m)x zZleLV?*hta_#ZP2VhYq(CTmq-&nT*7GXLt`YK-w~>{=g~d*^mqONav|;g9piKx>+M zZ?$Y5^ZcKy0RI-Oq?k}bA+8y-cCb-G;_t(;n(?-~huib(>lSB0dly_$NP|!stfeI| zG!sC!3g8Rjl^qO8Z)*j3)}~&H~2>{m^{X3ZaG$gvfRWbJ~xtv zoZm~68@Uj%$!~nN11GCJdgjz8Lfg8zhAA*C&Y0tbEtI@7Gjrc-q}Hhr+aJN(^hO8~ zTQ8@JHH9@0Ge>6ylERajJ@LTGL;8l7BhD?+_%5Pl z%Zln`RG1(R#gzf6K@xb|>3<$k!rFVE8pT*5qm<7^9S&Ih7{jy85r%aYs@l{L%_a=` zyd7?D!B@nleoy9N=mZ?F!(OHBD?EE{RvH{yXv?0TO7K+!3a6u9!j%SG#1!kb`e8a zizg$*^?&isuDXm8R0c-~ABaEYlhvju#?FpjyIbHaE)^iG?&g{M{`@(9<7c9}hlE^T z=!Z_c#yOj)eZ4~}vCjykh7BIEeJ-1A<-|39RSIjPX+BbTUL%b@7f-}mYZKuM|?1Z{m-0*VpFyo#hwu`^%)C`mS@72}OyCrggy zk&?)wnkR^2W+_!1Fj=IMU=5{5p@9#4!%?ZlqQB6T8bg7D3DSg%Lp&gT1)2T%R zY|~SMWFg*trzBRu-^jXwn9%AbBa?Tk_fK0@5+9c+o`{z`rl@wg2JR-tekxMCZr;Y;^m^ePgtWmx~UVC(7c=+LAYbzR`Ogkz2_bE_{)Y7uNeD1aV*|oKGh`lu}+?DElZOgBQBFtfB zC69AVC&J&)4I*~PWnM8t`=nG+kZ92X#y@slYAB(Yt^K^sJcV1c%vb<7{*^M9W!Ub4 z{ODR{WoII8hvqh~=^779WyE{_?I|lFSlf9$X3ITg*Qfq9&5|&FVz*rN;BNXu_Cpo5 zuN?ZmOtcB#kHQ)U$c^(NK1zqb10;qEhJK*n=Dx(Zz{&8bLgORj#wcU9+Tsd`>WG(D zQ`>N(k3Z3Lhg#ItFMdKswxYL8Ou^SLU(I^pGo9wDCUbpD7f#sRY=R(m&pbUm+*35p z&2UWaCZvIxyu$)&=tE^T4eX;vMR~Kvv~93HxC8urV!2>sO$SmFR01U%Ac+%IbrHARl&u}7yT__%O(_|v_&Hd(Fp7!^17kWs47e zf7|nirl(t45)-?+^76iZEh}qknpXEiem=)A&sQCS4-H~9$aVEy?_<*l*b${tX5($j8S>TL=^8JInQ-6M3vggr-eWsNoRQcn@#=HTdA$fa zrrlrV+NA*47A_et+#)R3&5q~DiKvk znc-K}Ux4WI7ySB*FGt#{H?*;)KBoT%!{2`mc!1Da*2<40=+(ML2pBxh7Wg}`xzsbT|s7XjiS8wCv-L#M3@ z;MVnsDl$H58I}`p#nGuJ#Kn^?|0>kSMHs%vya$}SWM}4Vzj8T>uklOkwfX`<_9c9G`M8gxFrb3 z`D9-}%M4h*>hP~6zP!^nmt1?{&-akUzK>MU9F@CmZcX5k25p#nc+pfw5s?XFVD<|HBaY z>bJYg{r#1OA0fq<&llf~-0bWCvwII@&ds%(+L?^Zf-2@kW@ykc7fyM3Wi}Vnt&??| z0Zqkcx8bWB7O1w4-5KjdKE301QD`xd;W#;CKe(C5w~MX+H~9dk62w7$vadmW zk-!X1460|OoCM%6+Y#LEf2MB%wsnUY>q~p=*PT7G^74|BvXge|anJYu3=lkmu-VNSOxoVY!VQB zlz>ymnVpMH<}Rj4v;8d7i7DV;7Pb4;%=nqFAwhA3+9H>WLFOlToPR(<_Mf#Ar`6F0 z)~ji8y~ds4Q0AOLx1qH0UCu=()o0bJ^~9iktABVIFxH>Eu_h+}8_QA4+V#z`qj7&^ zn9WTpWbRJW@yL=yTSVk$M@Cv&);>>jifP2t4|x=>t2I*wr&pDE#*oT`EeHt>?CSn~ zynO0`$cchT^iB}G4)9cT`wPw;jL6oIk2cXKAgJj^n4?-e7stN;24lWbwM-;8SUnl$ z>f{SG7S+yWtY^YoehrDG=K|jew+8HBIUX!wg%qTYe-V6pQnp#L)J#5^WC?^65TF|I z6+L2pvFt3u$u^){3=Bx&tN&Se)NbSm4JFL{6WR9gepd5B7Mjm;-gR)yrLkv?$TvoG$rr9mE z(h6@{XZa+}(vuvX;2&hrGX4EYEi>A8jKy{sLTUNRhN>$96%W@xFknflb)uL@D$1Rh zg1;~}hLHt3S)rmb8jKk}mf$lajoPv3H^<7=M|AK$}*nd5F86NJD${$Xz(x0EV zV+&!NBkAcSQ#R$m=6GsU}>ys;;%%SIp_m8stiuuR|?jTy^d zOi<~6s@k`gLh1X;s?=zdEMR=Lg^nS znVTq57K=k%SO}n~LlU%rf;xpk-GsciA8{7a*_dSIt<7w`JaEiIa@(gKbLej7zI_YG zh(~1VnM%`arME7XZ#Yj=i*RFJ_Wx1wIL9FZqb-giC+dXvvJ>>XO5;FaA||gs-*!0g zbUMEBwZSyJng|l|_^D|fGl{4otCK!XeIEKK`Pj*jdgTDu6NHiz{PL>ND5`B>D;8{; z@x~3KD;`+Qu~|fmDR_;){@Fxd{iBJbD|A&wxM3 zjFo+E7D|j^PL5~gnBsW;%v-klpG#Ph*%X#@a!8K0P1x|>=8k=Br%|u$NRiy8Bn?27 zI+jJML>M;Jc+#AKBRYF$LV;bZr~V0_hB2nIS2n!vx0g@D_Yr#{Y7Gal=rpL#M>gH! zSfDb|@O+rq$Nw|Pwo9KU&rpmA%H%kTgA$eb(IfMc3=QYyyEV*gLf=!F#daV2T1RW*!q<{J)|FbPgd`j){%F!qHk+N- z^ytc*DyyYjR}Fcxooaw}^;oB#Ys5YFhy%X)e6Zf~H~OPgk#$T#qgQSZRJAr?cULRO zTF$dlbDZ*hRD#78o{m}Uqe*Q+xlMvbV;!gfI8Ny}MV&-_{VKw?ps)fnZGc*s)fK3) z{Bof2wq`0ba~sBnCo5MzCfbZfXJ+PpOk-P&sQOcqge1MCfyUzPkFqXPKtj4#k1ZM| zp)?_?xa^x@B+!AwLBs5cO9Yjf7gKjQsVjyMO>4JNc3o4)tH{`zbx9ifRolVGEaW6i zvVUhAc&^l<3p-;bHu6wmE6S5bTp3j0)Bn&>KqtsW4C{{qRk|a zNpy@f%UQRD=E`$^iFE-Y7cFsJ7?!5xNd`yH4(NbNyGU87%n)B~aGrIeUoE#&{l-oe zgrG)EKNKvkh(y?}O%ltnPb5HzzRQ*5hb6b&-ToTY!>O;;{O!I#O^p3wiJz56`knHc@ zUz#DNe-TjED0PnG#`2hBmNB*=NHru>*@~I>weO8~+=XbMmgZ?ZF{1?>e)fB-jms5s z;CGI%1X+0{jkN1=Ch>YD9Ie)3@C6%pXQ@q=)gILelpG`V-WL(qZZ5a!XDkc>`*F8O zhW=7NAkJvr_sai%G%e`iTw@Zdv8$GyyQC1WQ>IBzEvWgZH!3zsz0$?D;QHp^;O6>J zyYX!np?F|LLuQsVPm7PVT(Dn2XPd8&F|e@ncVm5Y>un>lhn3zKEVy+8(SY}tDk97^ z+ceIJ%?0Q`%>1eP!KSGG<9dq3DBI6QDROp`f2(&r1PLR1tu3!+pHis|zQLbEK$w5< z4F_Q2Of$X3@(~W;X;XbVghSqe6(um1UmbOWpZ*Fto5GH zPW$HcI)2_hhfpt9RvjU?9aEf`i*=3Ek_NdCIt-ffU&NX@Ue$so?+|5u5ZxN@tgnnS zp;vWH+xE=XW}GfDrv}ugYAOpW%Oil@32r;20>krR_0=R_C^#(5YaXzWr_) z`&*IYRQ0{JRZ1E;ybY9E4M&e@r?TxFo1v&l;S4W8{-xH$raozTau4<2ke1KpI$l{+ z$~51t;GWEGBMg2as~u~Gr|kPV?FF&kcWe9CjLhvgmvfX)Mmi1vrA&Qt60woBd2im(V5x!%n3nyn8-#*z@4IF?+`=i$l)z^fjYtSjTAD;{y1SKIivk5ToPR z`o+s&&oaR48M1Js2sB${VQ4O=8h+<1ERo@Mx@oWJ5Gv?bT~QB(C%6Lp_bEfXnGQ}fml8*f# zK0a#9_+XkZowe5O#yH2nyQN-AeGAFv`YMpq!5NeL_v!K~%XT89_FHR8GQSN#t3It@CaJMm>dFVVOsBcIx8@c1#G|9> zmY28cctiC1%pNhs)~a`RyKoRWy1R#mhlGS#*FKKK>-F=0{w!Di@?=fwi>392sA~4&bLK~_oqJYB<`1l z6oK?}AC<;^UFlwxzf0-gP9wzkpLvXTDbSYM)#!`p(jP3BR_5kAYx_$vM@6pd&wI5r zHT3|HwrG6L{Un3`t)LX-nT74(HPDZo7IS5M_^+r|$V?3+;_+I_9C4g%Q0tj;Dqt== zGa`Ujpa@h1m2uHZ%E-w{2i~UR-Ctjy3IjAHeJh)vKcDNK=?fhBXK)$mQ+Z?4ru7-% z=70RH)rQEnxPjRjd#q|Qe~zZaAz2|`m$BF{;7M>-NIqR(Nntg~Fl0K<;^aR4!h0cX zuB>tpotZMmwvxiwPXy)fgdy27ac*v;q-^?V_;FypBVD$W!p!;zt z)xR(WmoU*uMjIXyX%C{KqJHPcjOyp!ZY&+{MxHu6p<#S+b@ltV)R(j0l|TatDRH*j z>K7Y}kGCmlMoqo_{J1_$Lh+D=n4ijyS926(`cNx}TAy|UIAodSO; zZ2@ui{Ak3{ZJcf-y}7*Lk4q#uxoK9Z$BapN1jp+1J_KRiPAr43>2 z2N($#p+6Na_A<}5P5`bjRZNeb71v)01j-RLHdTtOONxzcg3Q^OGTM)!4G-URc6Rmx z->*}ghoPa<3%U9+L^LQ6pBpcH)zs9>+s79M%S4YMj_ ziQafq$pCoR07W)=X4Ynkpbr)t7BY0Vs>+i8QT`4EBHF^sK48JW9PRxs+iJF+3cdCaK?_9>a!5Mc0sHI@)(` zXYuHK6{aIlErMn@8D0^?!<&|7^MTATiaJNLh8aCV({3yQ?Bju(c2mj}MQ+l;q+HFp zbL^+O8mYb87n7r(VcFiXgHktWC4#aTC}KowIl$w!LRVI*ssK0OLe_)bOZEdBlKh9x z%f*@ZZUZF%c74dJ4i4=lQh93TzEuUQgHAwpNp@6+UlV3e+&sA*>WFh%SNGS6X%Nmp zLD>8MtKZqr8`tk&eB*;}I)G5nU0?s}5!=5MuQ~jD1sJMf)*iABrWLeuz0I2(+x`L&!RB1{EInbQg6R zzu)?WpmoH9?J+@HyMfeY$lriAmBQ9|I}C|P$+@qoQ91RPwcfKpo+k}{t|*I&AVj)# zfxC&T4KkF@P%M=9tqYX%&C8m-)%xgm5dj(XjG~{&8YWOPqn_UM?DOY~`b9udW`2<~ zq+RNjpy5!`f?@$~b>x3*>SGkW_eJe5*`sB)G|d)HMB*|t3&CU`vJy|~vS97L(auIuf@9Vx zUcOjvS>`?HmhYt2{vwR$5uLR2U82MBiE8H%Dvgs2O7*1}RGaQ{HDLE7$ah&Q_)9DJ zgocpZqJ+r&w`wd({rS5y27nUe_6yW+SIV4(w}}Vnvc_${W#RniyGo_Hl)X$MU`exj z&x%0_L^$5c@83&HpBd9)^>oj$rp+5kPAH^E1DKjHR9CS2jrxDo#!zL2+bSVQ5Rs*_H{>F>A=b~(g1tuf73-lB$9>A#*6`%q_Z!^L}%uU;Ri0| z7R_rn4V+2djHhBOUOse|RzvjF6vBwJ{mGh|uCD$4yFdd)IL1RE;TNhQ`RAe5NBsy?I8(GYd9UU**TI{cq|PmT@5*`pQ0=+C_~1ePe_MrEU|2 z4Q=p5+KNdNgyA;GThRVMXUpdOAV6lOjq`Y<4z53r*J*P&zXcW(Kfqr3gPZi$$W-pJ zgglw`=;#1(*{Vd6kO^RtP-UH;wWdRPBt_!AXQ9k55tK1xTYdhi$K@`X)Y?ZO0!Al- zW9M_+G(^eM1mo|LRp6EEq3&OIglG=9V6#Ru}T*R<~{l9}Fz-?X$KTUW>s->uQ}cscZ;3dioA~s|h;xqa78A?fHN`(@zjT&m<0S z>S_?p|FC;l8Z|Mrp6{H`Elo{%aUn0#3~CE0{`^rwlbh_++(BThZB;>>i;{-|){rE6 zHCAFBOjR0{Se+I=xK-C`{%wL{j0m|*NOnA5M++dN z;M`6=D41!5=vXRA9Iv#i@y%`c1^ zFiFsTo`&@)UZ?kTL_2g`(3`g#61v6!)s2ryf|}C644(RunvWYNY4G%Q zk;D=Ez1FaovX1j3VCuyg3-~2ONlWsiNVZ&AfPi&4=e=-w&u@Bc`H?BB$wVrP`zNQ? zRcsmt^^WLVGKxmN+0&%myCl`bh)+vPEzU}lsSEPv7)JkJQEwgA zUn3vZzEPArusF0BZZs~dZf(^FB+!%T0G|oEbX9uo&Uq>l6~8^Zs&NGeMsoWU`uS=X z=<5fI(deje#L>v`laDut*%`+(|MN04w*^n}qzsbaD~>^?iV*#^R0ruZqMLCr_WfbO zf-^7$Qgk6B$cc~xe+EUsO3eN`9~mboSXkBzJ;M>C@c^Wr-@8)3{U+tulJHU|aD0*O z^9SDIuE%UXvAC!t$dM}qDEF(|PYGoUp6Cht1XFTW*<(4*YA;YU(!cee9T&U(dZhC{ zAtbbb;KhgJoUf^AX*I+-&NB*_^9hqP*^t#iYUTvDwJF`_#`q$oqOm;!0zy~u-%Z^L zTURH+VD&C#Yr!D^r7h>49Z;z#^#g0_v^6916pw5qF^zBjfq?Ogz+s)sykz&uP5v`k zThDKB$`KQYP_B`mH1g9R2Z!#|JEt|J;xw@wSB7mr#=2`{VJ)S;v{<$+bDbto7N2`u zvq??IK{HVkwYC}0#l&{ zmw+ZVqXi*864ed7+@;E=X;^S=f|wFeAB1UnF<#!VS)|mnZI(aSQ!T59e!Q9-%J_g?a4((nmeU#P0i9~`hzU-Lw?*}=FkA1j@QvA)@m@<@8H@+s* z^GQMnUz$oBVNc>mFkEoYah&!e+N#&6Kta;qLYUhhS*)HYXAsizHIX^f6skAdS15Di zKWw7QX}~NF>TvCiR;Z1#J{}^J4ry0I-#$gJ_&z*%C_tf+6QW=g>s;(-xiTW)(hBNa z#o|1F72VS`DJ9DYnxG8-wb&Q-=l#@l;4FjWD-<_sbXOUpXT-Gf@7!!FG$*Tt1#%q3 zhnw+^%o@hbC|NRkj@+%uGTEAa)n|7C)-mCcvcc;aG`}pHU9nTA9gg-wnEtFjJbJIT&bPmF&1A8T znF<$dhI21xIlM0#l`n9&%HekvOCNmMtD*6f#Np?XYx4r#;d`+-p2=7Xz6Yl9bpXKj zKvj+jLROo8=ViBJZS|2!Vq6;P{i)7iim$NO$L1lc7zxzD{a=QrgtyMBFI`N?lRQ4P zjuot&FSAvr~;nxtAIwc_7&*^-VIaPgfajyYbdqi>qN%w&j|iU=JMV)qXMpHi1P`JB^~DV?R~rOaO!%nADuX%c`sztEf!-s z|DOS|XBT@|rfE{8h0I-Gt&EGLR`nhFCeQtn+W|SWvHUn{N|Zc`K8^kPK-`Z#!80Vd zHy962Vv9u>%s#~wNnOcYrHK4q{QczvcZ?XE(!kAxh`{d;lu|zBEm4CMC;IZrb zn4u}Y_XSY}bzbV(Uc_nXEXHFrRokPLK90}%8nvBu6d8Sj3X*zAANG>Mk~qjKV~ioO zszNYnB{hvN-YS#D0r4znTl`{v`5O4mHI8N`sLN{e`yL5 z`;h&(Nyy!66RRe6yN$sD`fxRJyKIz_MH-VV(#=+V+r2x$%;g-{C}sGHX{k3gu8QfQ#Gq~aOhiYu{&4-B}WpskJWN}`n7 z?+*J2NP9zQAn)Tt@Uin_fVF$UZ%2!poNOm8*{nu*&es{v_sId?uVC;hY@1oP5Hy8y zfS&!co*4B{79iQ`YsW;K=A_>eNWRcm9Ywl2-aKA}hST8l7p?VEYkJUF31v zpVO)K$_p#SfmO5_MJYO$&%x?BV`C$()#N=#P0viyH?iZGw@OQkO%tcB$zE2%@6AGR zAzb;on;+Hvl_zWt`J&$!U)m*LiLx3M`G@UNePK&eEnd6h z3fnh{jej*w8GZL_3$hSq%AMj?Oqdq zEHB9$hLKco#8Tjh#y8!E%_zL`Hai*4dm;wGH5E(F%F?I2tg;TL{vku1qV_0vUu|Mc z>MQS!-Nbv7T8nFsu{4w-`m%PP^CM*8$d~u#P9P1M($#2A(rFwMFt%nyDm_kH_waQ6 zUej~}T$a~&-30pgg49-pJxCfUKNm#$|pX<5;$~J0Oq^qZz!X@1dZ=24lDu~s3q^7 z7BAxHHF@M&p^va`ur~a2R5dBqg{5#A4WT%*()1}+DL5VF$ie;`VD2-%wl%FiDk`~ z9V=Y&pVeOky>0|tu0EPM%HP+!c&Efm)7+EU>@_=i>hnqe>0D2tIX{ETb+&dtft!?~ zIGg*)AKC^;L}9)d2XQUm!efDH&X2IxU7BdaYn1b#UuP$S4Wgg3ymZBAl%Ld58V^?Z z@Q-lSQ@spIaei81Jp1*DpW0*6{n_{;IXAbz^K+NbbTT?e_W03)w$QiXPF>HEb*p|s zc!Or^>@kC6kMHe7Y+Ez9Pq%O^n$GP{&-Yd`WiMSLsO(Ocn z{EMEYEn*|=5jS0^Nsy3CgUT?)Ah{wft$fRPzk@vPSK04lZ8i8T`;KE4q{x(;)o>9@ zNn~MrW#cE?8n?8%Wr%m`T`*rm?Y4JrwYkSmAY;m12;fXZmiDt(LZqg)Xq)L1X0;^w z-EpuryLPCHGdiu=jkNnKd3lQ+Tfg#M|%X@TipT+KKzjfmc(K z1iqMSKsQtMaD&kTT9)!boB_rcJy3Q7eYfvl(*WGxK$dK#sD2*w@Zi=2kAJ$uuXlS0 z(ve1`!7Ob)PRX*}?~MTeO^z5MoSF=KwKceGna-hz?bEv^opw41gF&~xYJX=Avv6$;)Pbl6qPvCypOk69q zFlr(lmbPo0@NM*mCl@H*!$A7nqv6C0tkBR*z8EZDRjlY!MqFy6rju_}EgDcI0Q8&Q znm#+TN{elS0HPQEN6Jch&tWR%o-v$m5%Wme;0hl*O?GEls2_kgtCSTa`qpkE^i@BM z;*ZAzgoWy06^DsycShu}ihQ10M+lGP30=Waj_AXxbQH{M6ukKJZZH&E>b0E9^` zUGBVX`nF6lDz$sqBw#JADZpkIGk%HE9`$VjH}yZVnTSUpmO*CWkGM5Q)NeAHRu5(# zFA!EQKeWX(Z|{h0pV3fHS>jr+Pa+{)B}n_BubQIO5>u&RJAE*2VO92xyW2#x7l5@< zbte@yp$+S+XOciQ!0GhDC|XxiaciYMKRp^C_z<{WNLT#^0!B4xzZmT5j_Ru-n;WfN zHI_!7yu4%g2~#5IrL;ITQ_afp8uxV)LabpjlC*@!C0`P%ercM{2C5mI-Ec z9K_kahr&)m(lqsJfJ;ljOD7+BO}FMm7PtlfyxS*)c7&awBXS2bI8_BcHZOeUR74_4 z`yNRnMbVuBP@HVw)8r*0TSARKq~?5_$8i+5iARlmtsr2+BoQh=Ye!iR=}&Z(R+ILC zoi*CI3lazY&X(CT4__@w@paTnSo#KW`r862mbX4zBGJO!B#uignzbu!M430NgPFX)y}at*G1c>Hk52c)JT~C?2s8^ z(-J(BKkvrg-5O!%xPqVd@s89eZ@^I}6QU7Wgc_%L!#Agi3whqf6VsTL%$hAsybm@6SLl4faM{}MIxgudWllx z59-Q8waL@KzhQKx#D#Ao<5{Og**>vn%Ibi6y$1FN^dO`OopN(mpgYT9HR$}{4bCa7 z3b730S)gO`uc0jGbLD>cNeSNBFpO9}TwvOJ3M^v~0*RDkb<;qNi z-0(p^zw4)4#Y$1DKyMI`evj{d*ORf2Xb5#03_#%mgPZXL-#f;YGiD$A|DbEaoaOho zTho~52%}4TdG&Rw@98~uIbjV1_y%tO0=7U;taRPQ!+!a!2JJ&3y|X+sY>jC3pkS9d zmkEp5&1#AWseECjl0&5c#_`XtJbN>Z56|(X5NrSl66cQppm+!rS&$%R76@21aVz=Z z5!Yu(RI9{pcm!?mc+KgZW6Qj~bX70r_l17mLs(b#^;Qg*xu%>qnB)5<#dzOq1OPus z&He2>hI#7xPhSxFdwD5^0syYWTBCdp1sc;`igWFl<`J@+UJ;8j0oXCEf8B35)>l`; z8-Ak~nw&##>?m6)btEb+!G@G9jE=4SH0P_4AR_PNLdx6SN32Ag74nqr z-D}M056wS^i$^UmnI&Mf?!=2pvD{WE} zYk|#sKKyvw+8-Al(#M}EK(uDDaTQ-j6oo&5fFgQ*Oh%o7@`gey1cFaEsR5n~7AN&V zXR}KY_5R_pvz|nAD9hE+vXW@uFMv*B4bRCpQ_QF*Vs~v#*amw3vpc*59o(1zXv45x zV=GzdjYVP>MT6NLeHS(K_z^@90UEmOL(=^UYyT!?$_KSMECt&Gl6IhjU^UD5i}~E% ztzzJY2E&hTNJ3XeiZ`(v0{5w3Qp8i_PCSNrW; zy-6C{s~Y#4&9!-Vs5a%hOG{0{#Fh+&Q=nH)Wk&Ed- z*GEY$Jd}%@Cgfgb2UyB4AszHCuP2QL3q#uR&&IF+KX7pO=V>3{bW$AWBbx%1SoPHq z*ojBNC9MX?^lA0d_Q3n~5|_zA_ORCIC%+nOn)>7k7$3V-1ZIHwd%OVG2yuQ}we2~r z(FZqWuKDrAG+#w;c=5!d>=93>f})e7#>W@L5XEd4~Kr1fF9~>%qYjjeh*5aYa1EC@98ZstqGbz4}pF*+hcF2T7L6 z@4(wy6kUi`=ll6fere6D`Kb%e1*HRb(gry}H zyu>MvB$Mv|_LMFTl&&7p^|<*`FE3@YfkJB$g^pA0v%szXq*~_H#+MW6|8cP?61B>g z)age|DX&SZ`mM*!i@HwHoYV)_drNC*DnxaiS-#_W(H1D9v{71Jzp*5OJOup`SwDa)v z$dh?2#OV%^@v%G+O^V`4<0}uYM{}*b`vab~@E?=&0?}FudE8UxJaW0%?zDEV^XNYR zQ~3xiN+_?{{qjVYYK#Pou1t@qAeGp>Mfw;1;Je*DE$6H0wUJ&c&%CH)3i8cOmsP)7 z^?(L2Cb8>*^mKN#s>9V)1!fse_yF}1TeBy9%(IwLpkx#x{ZI+ty>51MbFYFn@gWW) zwu%*1{2iVtDCe><4#4g3KA9FaJ$xdT?#&JArEjc0PZ;_;VaHiA{w}$u@NvsjGpq3? z9&ynqGtW%4fOhnG$(Cp&|7iEjjvV6;e!xXBb-J+eC%vqVsvIrfXDmBz585l7nP#m{ z;r7tK0u`(l*Orn3zqN#%vQy{4ewwo7u^xnu-nxf1?GG_^<|Kl z7xsmWFkLw%@XqAodr}DoX~?h5Ui)++<|=#%bAbLh3u|Z|6jYcmsckF(>L3GXG<$Ls z1o|u%%Kpg8$y&H%>-7F?PU~^RnB(1$C~BT^$zuqvwUjEI%nzBd^rE z-}E7W-v?%!*GU{aD0yjk>#)lVR4XqnB0LCSnduE0RSu$7{+O@=Mk%kNe*L5S{9uEtukSB z67m#vm)#?EuIa-Z*2}?21V|=*?EuVt_lG~;vBiQKH3M~|z@nrC_TmWWu@W1i9#J1k zt!R-rr;kV2VsxrjCs&_h?JqyOyDWHox?SsOCa8uPU#XVJlA5nOy~Q>lel~{>oKJq? z>v0OW(OvP`To1MW9NQ*H?gJTWjK6^w0VbE!WMKsbeOey}m`r#n62w&RfqgZ5bb-2vlbszokH0^_h= zF*JC( z8vM;}ZW?{QpJ9b5>R;1^WKVODUcV>ofU1mh?%Bd0)e;{pq^pzxVa<=!e|EZ942jvS zM`}ESY@eSI|BJU0QGk*b%;mEWWQ&uNdwYi{qLt4|3io@t9nW2ytv}$`+eT@JCYh)0 z%*$DT+3%btgglbPzs0a7@|HRaD#mY(3Wfa!CjffhdQ%R!u8s%pgU??Cw27oUhaMMj|<)D zBYm?PBYEj&epPgvx{L@*Ih)TXpbl3>HrbxfjZQBGx5q7>V7jkCJ{zsmF3Z25>?v4& zf>96U(J?-eZ9a#=8XL{{d?H@!&%qiit7@NVI(rX^j948w%w;*QbLIVD@|k2No3P&9 z2gLILP2xlkD#yp(%iz@HU<>bib035%|tRL~xW41_z*zXH= z9UA;f!kRP+`E`9CrebaNeQCIn#(RUj}`0~9`9}d5Esry6vbu-I<>4F;qVt#mEo0<0FLEX{O z!8186t^UEm$w|!Va+65ZTkzTmD}-9GohcuSa=LzE%t-QhgF!%JWgdKJo$q+Iz5LVP zLJ|fmps7uIG)!JJM}(qBr$Dxmyl~uVQ4iA3GgB&|KfPT}`&Df>+_6UzC0@N!3^l+u zYAWIueuaFHyYaBxv`4cMF+Wv`papY4+o)wVOw%;tY!Xp}Ai8pr4}*3X5%j>~9M9{Y z1?qzV07+lfmCM{Cb#!!HI`m)A!*5zG;QHT(f8Co>(;6E+-y3(%&l?*@1w{V&I(2@& zoafwFey#3kFR`sV5oJwLm9`RRmh6Ffx5EI{C zB-UNaOJzgNm&*BWMxf(|ScokUpteo2l7`(zRwJW5n%KJ6360i?D~S{qBAei(gZNb5 zlIc}u6nf3OFP_M;?;%+ zsDg#TjK9q-eW3xH)YLY;CX8cfGx=sA4$c}er!lUj#NRyQ(Vj~JXDVt}wfAj#s8KZ# zts*HOw8&L;`{t8{=en_(%GdYQ#^CWhg?)JxC7zw8X~agWr1kx8Iyongo?)tm)^fzV zgA|)cTx}DEjE)Z~M;H75Qjo&`UH|--vTkqhUVV30>N5;BGOTZa?H+M|SNsU4j7Q=|BW2 zW>t2~Ix{HiT4?}YGhT`Dy&<*gdGWlo9lJ0+c8D%hs#^qm3>t6TQLw zQI1kARpZ1^T4f9|2qfqVa(u1eA_}IHoCkj(w+Br|)QLWi(d@jsB2~W_B~pD7_z)-m ztju37-P~7M@jb+>?GouVwB*;RAdtIJl-T%K@&1q|1kwDdCG9dPtqs{7W&k>wVcT{f z%J_@13lWRMbaiwuuyQmO;isnxfVPW{zR>$nPfzD~eIt0N!|r+JLjr4{)m&JXDGC`Z z@woX|3wK{g;@*dTc%}`9;=x#7T5T`k3o1`&Qw0hD0F;PE(>tnLIk;vSNeuF<(Jn^ko2>zx3F%k5dJfX+8$a(VGy=L#yJs-M)F77L@%(~e zuVnPuy>zdAQ;5BNU=IH{71gg_t*!DUTD-X(5VeL&z?&imi@BKu&g(bZ%jG_#^3^0J zsrS(!v1q#NsJMJM7F!tN!-viQJb~#IN8TZtbWLuk{etvM%L#?Yni2oDM>FhxPk*GP zSzHX~hR3Z~e;V!fQS!wy;X@!I)EIO@*}J~T1WwhF4{uU{+|$jamv$3A_6e6YZB-a% zgq7j=g!}J)|J|$aNEYQq^ zb6H4uPEDZ4cqTcaEl^MNr=ZFA&&97PXiXQqjM%RQo~DXHB1+u28Kl>kxSi03;|3p2 z>DNzcGJpzMKLa@Dp5~z!J_smsqiOg$hNopOVrA=G0Vwl-ht5Vh7u+E6R0+>LB*Yn? zDnU$MHvjd;id_hK*1Qlk2T$477P*(+rRxqzla)%1utD66PABZcAfZNCKZ+$(C5!W3~mk^ z;O&=SX%7`1#f^C1?^a$w_8$C$27Yb6BlC!ZGx&ey7tyw)W{@6OsB5rMsk#Tod zTpY7a+x{*hgowIJk2uP~%9g4F$|X^+u^VX9m{KeXUN3=~3Jj%5#4sphQ`W3{EOA3L z9hM0uoTXpjC>Lodeu)vrcZBoNosQoZxiLn+5=&Pn3HU@VEIcRg#P`ZsE-BtHugi$S zuj94>?G)=aW9TuIO8 zLNrPilgY8pD#~ROXK(I< z6?Qys(4U+t@9_lx%`X>7b`^e|g$}Nq2E4!k)PzJ>nLRxwr_SWCtsk|w&VOhV#TCAh z#5K)#d@iC*WHH{Vu&8GVd9Mln4N+k@iXMJ9*CX29Y<8h#Qgff{y-61$Hq}$jKYTQbcC`ib{JG+DC~ia<-h+yD zJ?|QG1 z0q*shzHtHSQc`Yj?<0h%@j149ljKkxsytY<(yCYH_eP~2V&v5`5L}~ZZEt_}Cn{?% z)zKKnQCyngUUNgqV6U9UI5h=v$@hMECr%a2QS{Zp$p+9=CC;2@KPir@jL6>AkhKCoF zx$K=!=iT26XfSUQ{1XM3yrbmsG5l$oxcTadcnCxFdQJ;}&EDyHahQorbRT9gOq&O; zniwQMH^qBYPuUV!a-R7)PbF#b6G2_8_$il1&TFU})J#93sd`kHciIx2-m+KAdRbzY>Sz3ISCf;4uUBm>H9 zc_r`w#Y0|>V&?*F7Iz2jKBZ1fSl!~W@vk>gCDhh6QdC+ZpQGcoW??S5W%1MWD4+MQ z_|=wv#bPV;1h^>F((>z2#gV9052}Iw1q)K$i>&Vc`1&Zs;YRyoClQAEYoRyMKZ4v za6Z;VhQo_hi#eyao=>1k;YNB8mZc=XGjc96w)5xc1J0B3s3!zKc(j6gvgw0olCjwF zr-lWm5{uZcy!~^|m*361kh+933<%=a>NYzq)yv=P{is~sm2y;!RcE2cL2M1B{Z_x1 z>2~3mW^hQo_ZAv&W2w=dESK0F5M$QZNS*r^?bKzj{l43toXmz-)kbekOjuYzWQWO_ z>J-(s>C|ZlSpM)CvDu(LUqXU{N1Rx#o>T-$YTMB&|e%uTk;-t*} zZKi|vC)W+mPr^>^m-xEQ&2x5WawRrsX*zLSUC}l+B7(oq2#j6tDrc4xq)XUOwFgwv z?*K_p7T`}147o03R{9+~MPm4mzA*Ppc<#wTIC{ET)XcIuuM=6#{_^|m!EzWHZI-a> zT9|u{xW|!9%?7_m@BU&^>&-WX4lTuazwWMrKA-LIprQ}Aj9%b_NU{?$S#7;WGdi%V zqK0S^1dRLz3DcLqo#Ip&42=uV^+xI7>Kcq$SV(MrBA8I&nJQ2GMO7vS0szVE1il`MQ>ZRCjXk1!~gUblSmqTgYo*Q5Oc~{}s=28gP2MI*{@Jq58;@(%_!R69N(TndgAX|6H4*PE{KoE~11Ykd9iKY`u&m~VVU!x^ECy>Z3eU#lil zw%Cd;qRtO5{4f7)2}1CO8dkP_%XsV^B?)Od$bnHvcyH3H<}QY&C}MC5VXR?l^*R$l zZ9l{qd`bigR~b?;X0ji8A1L-ogR+%N@*qJ<cr& z(~u6p>0;jf<8o12S`31Nyxd<(CZD|Nn=qyxgqvXub{*JjT^`=M{dD3Ah=c@~WoW`^ zrJ)~_t#c!$IaFb}+KMSpf($Vjwvb6E6L?-F?gy3lhfW4HOsfQwsQT z4{ExMkVDqSfS0-*@gU08k*O~KXnzUNy}d&$nuZxk%dLw^T*O@H`ifC6;v zRM~@QNQV1A(H*=uciEMan$Lt_k!aI>tYI4Zn2z^S{nI^WuN$K;=-aJ*DJlI*`cZ?v zL0a1P(;Wi3sG*PdU&_B3c6sW8YJA&cdvPBlaM%p(P*@4L) z9wV*>q@bx5v|T>6Zq>22HmbFXCL68R^#WQJe{1>q1n2Al}YG?$= ziWmAR*826tA~jp9fQA&Qc?lb+Z!{V4P5rpmZG5Bh2S<$k;MVN0^dyLSgeGF!rRhQ0 zfa(q#LHTHtzb#~jE*)Q}Pi63F0{Cs-`NpEQh6zloKV{TnN}PR^o;VyWOVz=?0W;I? zQma+n0@r^MYo8KcsWBTl7(-NqwA_)bj7eVxzdM2QhaVr5KEd3Kc0h25?(S ztgmE7+)zh7o-Z%`Yd;}y%1ILr<#TqBlOeCAQ^8;y&l!~cqA-D5j>sosN~fr|2I)i^ zJIf_7g9Dm_VT&)A>{>nc98K@yi43yICm&;M*qVD+6`7dzu3x&@|9+_E?^V;AsQ=W6 zMQJvejOB-(pw(YY%kpSxZOy?!usk3XLtKtkVnP4oOh*2|k{48Vl=KeapkfmxuVHE? zGd*@7Z9S3R=l7jv`wplct)tgnib)9w=NDF#+UW+Vwrh~t!G2~)&FMt;yh<}vvuZl_ z_>m{!^TIFsQRPgcIIChgHinSs=+&*B7d)BY5~C@N0@UEBZ1wZH=n}j~g;^a*BCj1e z8yeU`79A!iI^LgBJw}GVq;c_gApKX#tj=LxKWkdg=fCm`&bKQU7V`5C4pLI`^H)|X zDtHYlD@Ef0f(&!&+C$&~?F(4iJC3D_+f76y&4)wPp{nxkvG#AcLM@b>qdwAWoulP1 z1bS30ikbJU%a?H;x3{+HhLs8`8zcw!Cc5hu0>)u6pNu$2A4CJ@U6e_rZ}tW-tTv+@ zADs$5BZF}u`CYL73nhVu*!o|Gte+czHj3@XK!!ILZqy$HB5FHx9_@R_{a3~`K3ELY zu&_8f`u=&|!^+BOTeFve_49i8m0M8m(vGoAf}1h~O^3&K!;nkY9|ZzLQLc5?Qd|-~ zD@xF)HfrJkEhJI=s^M>eD_MxAXg%O>!RP}{E&EVW8^ds!#5BxHF9)l_#5Hx+|v>#m-{1Krq41>TA7A&W%>HYNFxYjSfn0xiKYm**yuv7Re$)tip8CY?o0ZS{|BKP@^_Xwb=?R++VKVIzi>*^!d5x-DNl zcy6Ihrtp#&yl~Qpl?ZKFXP+|P3H4vU=mr$c70pWz7C}P`#KWHSO*ak)dG-TmHA{?g zF3XG!xX;hHaKlvhmVr7FDX1iG4~4a>@7m=v|M0Mwi5OFuQ(`4J;9jJ6bv5+Dx%S%> zBV4~}^TX%$qT(v-G_mz{OY6wnxf))YS{&>fY_bvwB`fUgUpZB&Y5;mxZHfxzu_nR{ z?t)VWjqnwo`Mpea%+t=lLn1~@6Ge!-Y)C#VCDw=gK}D5Qg@}Uumv5S|sl4qY)3Z_% z#6=#6#f}VP)E%~*0e-@=`C9<1jAm+awct4;rc zy1wDKaCOS6Y>;nUd$;}kmD+GG@6xvMjrCF2v0ueVIcHd7>*6InrY*?aJ6Co3ZqaXL zUpq}p~ zw4T{RPg|GG$3N>?ypBEtt%aQ02{Ay(GM;_jaa52IMk_dr!xwwDeZ)?>De2SDc+;aN)>TzmSQHi>9mT|nm}c-a@NAS1ttXqXqJ&km z`}wsK4?eOe&07tmph*!kcY`7>hxam#mnS%Bgjqi@7;7tnrX8veMKw3OJ##lAy_B4l z6=GuXUwJenKEq5fKRojGbe zz&>t{u4C*Za6@-JPCd9F$}_iE?i2wnlx~6l#k2TtloYbhA&h z6Xp=&9`2o|3uw|6h3`IzsC6OOkE>nMilR%phIkAMX>a<0>2deIf-o4-y$An5MnhN{ z^qmg^FTMIHBir?EjXir{bqTR`Ai5)YVK}F zxF41+ooXvLi-360p7kEh-svVi-+7y;BYgO0h-4C(KW=Ov@vTfES%8s8sASu^hEmSZ zm%O>)Ux66M$u|AI+skKehbyg9>M&RUN9hd`+h*Pv5AyTQ$ZsKpHIz&f_rMQFn?Mg LeYFM^+nE0kG0W-* diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css deleted file mode 100644 index 77095d3a..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css +++ /dev/null @@ -1,172 +0,0 @@ -@import url("/CSS/A318HS_Display_Common.css"); - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: get-vh(640px); - height: get-vh(640px); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} - -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} - -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - fill: none; -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke-width: 1px !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .danger { - stroke-width: 1px !important; - stroke: var(--displayRed) !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .warning { - stroke-width: 1px !important; - stroke: var(--displayAmber) !important; -} -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - stroke-width: 2px; - fill: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); - stroke-width: 6px; -} -a320-neo-ecam-gauge #RootSVG #OuterIndicatorOffset { - stroke: var(--displayCyan) !important; - stroke-width: 1.5px !important; - fill: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 2; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 2px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; - font-size: 20px !important; - fill: var(--displayBackground); -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder, -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.active { - fill: none; - stroke: lightblue; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.inactive { - fill: none; - stroke: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.decimal { - font-size: 15px !important; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.gaugedecimalpoint { - fill: var(--displayGreen); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: var(--displayBackground); - stroke: lightblue; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text.amber { - fill: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .avail { - font-size: 19.2px !important; -} diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js deleted file mode 100644 index 7fbc8b5c..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js +++ /dev/null @@ -1,549 +0,0 @@ -var A320_Neo_ECAM_Common; -(function (A320_Neo_ECAM_Common) { - const absoluteZeroThermodynamicTemperature = -273.15; - - function hasThermodynamicTemperatureValue(value) { - return value >= absoluteZeroThermodynamicTemperature; - } - - function isEngineDisplayActive(_index) { - return ((SimVar.GetSimVarValue("ENG N1 RPM:" + _index, "percent") >= 0.05) || (SimVar.GetSimVarValue("ENG N2 RPM:" + _index, "percent") >= 0.05)); - } - A320_Neo_ECAM_Common.isEngineDisplayActive = isEngineDisplayActive; - class GaugeDefinition { - constructor() { - this.startAngle = -225; - this.arcSize = 180; - this.cursorOffset = 0; - this.minValue = 0; - this.maxValue = 100; - this.minRedValue = 0; - this.maxRedValue = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.cursorLength = 1.0; - this.cursorMultiplier = 1.1; - this.currentValuePos = new Vec2(0.65, 0.65); - this.currentValueFunction = null; - this.currentValuePrecision = 0; - this.currentValueBorderWidth = 0; - this.outerIndicatorFunction = null; - this.outerDynamicArcFunction = null; - this.extraMessageFunction = null; - this.extraMessageStyleFunction = null; - this.outerDynamicMarkerFunction = null; - this.dangerMinDynamicFunction = null; - this.outerMarkerValue = null; - this.roundDisplayValueToNearest = null; - } - } - A320_Neo_ECAM_Common.GaugeDefinition = GaugeDefinition; - class Gauge extends HTMLElement { - constructor() { - super(...arguments); - this.viewBoxSize = new Vec2(100, 100); - this.startAngle = -225; - this.cursorOffset = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.outerDynamicArcCurrentValues = [0, 0]; - this.outerDynamicArcTargetValues = [0, 0]; - this.extraMessageString = ""; - this.extraMessageStyle = ""; - this.isActive = true; - this.extraMessagePosXMultiplier = 0; - this.extraMessagePosYMultiplier = 0; - this.extraMessageBorderPosXMultiplier = 0; - this.extraMessageBorderPosYMultiplier = 0; - this.extraMessageBorderWidthMultiplier = 0; - this.extraMessageBorderHeightMultiplier = 0; - this.cursorMultiplier = 1.1; - this.uppercam = false; - } - get mainArcRadius() { - return (this.viewBoxSize.x * 0.5 * 0.975); - } - get cursorArcRadius() { - return (this.mainArcRadius * this.cursorMultiplier); - } - get graduationInnerLineEndOffset() { - return (this.mainArcRadius * 0.9); - } - get graduationOuterLineEndOffset() { - return (this.mainArcRadius * 1.175); - } - get graduationTextOffset() { - return (this.mainArcRadius * 0.625); - } - get redArcInnerRadius() { - return (this.mainArcRadius * 1); - } - get outerIndicatorOffset() { - return (this.viewBoxSize.x * 0.03); - } - get outerIndicatorRadius() { - return (this.viewBoxSize.x * 0.03); - } - get outerDynamicArcRadius() { - return (this.mainArcRadius * 1.15); - } - get currentValueBorderHeight() { - return (this.viewBoxSize.y * 0.20); - } - get extraMessagePosX() { - return (this.center.x + (this.viewBoxSize.x * this.extraMessagePosXMultiplier)); - } - get extraMessagePosY() { - return (this.center.y - (this.viewBoxSize.y * this.extraMessagePosYMultiplier)); - } - get extraMessageBorderPosX() { - return (this.extraMessagePosX - (this.viewBoxSize.x * this.extraMessageBorderPosXMultiplier)); - } - get extraMessageBorderPosY() { - return (this.extraMessagePosY - (this.viewBoxSize.y * this.extraMessageBorderPosYMultiplier)); - } - get extraMessageBorderWidth() { - return (this.viewBoxSize.x * this.extraMessageBorderWidthMultiplier); - } - get extraMessageBorderHeight() { - return (this.viewBoxSize.y * this.extraMessageBorderHeightMultiplier); - } - set active(_isActive) { - if (this.isActive != _isActive) { - this.isActive = _isActive; - this.refreshActiveState(); - } - } - get active() { - return this.isActive; - } - polarToCartesian(_centerX, _centerY, _radius, _angleInDegrees) { - const angleInRadians = _angleInDegrees * (Math.PI / 180.0); - return new Vec2(_centerX + (_radius * Math.cos(angleInRadians)), _centerY + (_radius * Math.sin(angleInRadians))); - } - valueToAngle(_value, _radians) { - const valuePercentage = (_value - this.minValue) / (this.maxValue - this.minValue); - let angle = (this.startAngle + (valuePercentage * this.arcSize)); - if (_radians) { - angle *= (Math.PI / 180.0); - } - return angle; - } - valueToDir(_value) { - const angle = this.valueToAngle(_value, true); - return (new Vec2(Math.cos(angle), Math.sin(angle))); - } - init(_gaugeDefinition) { - this.cursorOffset = _gaugeDefinition.cursorOffset; - this.startAngle = _gaugeDefinition.startAngle; - this.arcSize = _gaugeDefinition.arcSize; - this.minValue = _gaugeDefinition.minValue; - this.maxValue = _gaugeDefinition.maxValue; - this.minRedValue = _gaugeDefinition.minRedValue; - this.previousUpdateMinRedValue = _gaugeDefinition.minRedValue; - this.maxRedValue = _gaugeDefinition.maxRedValue; - this.warningRange[0] = _gaugeDefinition.warningRange[0]; - this.warningRange[1] = _gaugeDefinition.warningRange[1]; - this.dangerRange[0] = _gaugeDefinition.dangerRange[0]; - this.dangerRange[1] = _gaugeDefinition.dangerRange[1]; - this.cursorMultiplier = _gaugeDefinition.cursorMultiplier; - this.currentValueFunction = _gaugeDefinition.currentValueFunction; - this.currentValuePrecision = _gaugeDefinition.currentValuePrecision; - this.outerIndicatorFunction = _gaugeDefinition.outerIndicatorFunction; - this.outerDynamicArcFunction = _gaugeDefinition.outerDynamicArcFunction; - this.extraMessageFunction = _gaugeDefinition.extraMessageFunction; - this.extraMessageStyleFunction = _gaugeDefinition.extraMessageStyleFunction; - this.roundDisplayValueToNearest = _gaugeDefinition.roundDisplayValueToNearest; - this.extraMessagePosXMultiplier = 0.025; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - this.outerDynamicMarkerFunction = _gaugeDefinition.outerDynamicMarkerFunction; - this.dangerMinDynamicFunction = _gaugeDefinition.dangerMinDynamicFunction; - this.uppercam = _gaugeDefinition.uppercam; - this.endAngle = this.startAngle + _gaugeDefinition.arcSize; - this.center = new Vec2(this.viewBoxSize.x * 0.5, this.viewBoxSize.y * 0.5); - this.rootSVG = document.createElementNS(Avionics.SVG.NS, "svg"); - this.rootSVG.id = "RootSVG"; - this.rootSVG.setAttribute("viewBox", "0 0 " + this.viewBoxSize.x + " " + this.viewBoxSize.y); - this.appendChild(this.rootSVG); - this.mainArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.mainArc.id = "MainArc"; - { - const startPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.endAngle); - const endPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.startAngle); - const largeArcFlag = ((this.endAngle - this.startAngle) <= 180) ? "0" : "1"; - var d = ["M", startPos.x, startPos.y, "A", this.mainArcRadius, this.mainArcRadius, 0, largeArcFlag, 0, endPos.x, endPos.y].join(" "); - this.mainArc.setAttribute("d", d); - } - this.rootSVG.appendChild(this.mainArc); - if (this.minRedValue != this.maxRedValue) { - this.redArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.redArc.id = "RedArc"; - - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.rootSVG.appendChild(this.redArc); - } - this.graduationsGroup = document.createElementNS(Avionics.SVG.NS, "g"); - this.graduationsGroup.id = "GraduationsGroup"; - this.rootSVG.appendChild(this.graduationsGroup); - const cursorGroup = document.createElementNS(Avionics.SVG.NS, "g"); - cursorGroup.id = "CursorGroup"; - this.cursor = document.createElementNS(Avionics.SVG.NS, "line"); - this.cursorArcRadiusChoice = this.cursorArcRadius; - if (this.outerDynamicArcFunction != null) { - this.cursorArcRadiusChoice = this.outerDynamicArcRadius; - } - this.cursor.setAttribute("x1", (this.cursorArcRadiusChoice * (1 - _gaugeDefinition.cursorLength)).toString()); - this.cursor.setAttribute("y1", "0"); - this.cursor.setAttribute("x2", this.cursorArcRadiusChoice.toString()); - this.cursor.setAttribute("y2", "0"); - cursorGroup.setAttribute("transform", "translate(" + this.center.x + ", " + this.center.y + ")"); - cursorGroup.appendChild(this.cursor); - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerDynamicArcObject.id = "OuterDynamicArcObject"; - this.rootSVG.appendChild(this.outerDynamicArcObject); - } - if (this.outerIndicatorFunction != null) { - this.outerIndicatorObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerIndicatorObject.id = "OuterIndicatorOffset"; - const radius = this.outerIndicatorRadius; - var d = [ - "M", (this.mainArcRadius + this.outerIndicatorOffset), "0", - "a", radius, radius, "0 1 0", (radius * 2), "0", - "a", radius, radius, "0 1 0", -(radius * 2), "0" - ].join(" "); - this.outerIndicatorObject.setAttribute("d", d); - cursorGroup.appendChild(this.outerIndicatorObject); - } - this.rootSVG.appendChild(cursorGroup); - const textPosX = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.x; - const textPosY = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.y; - const textPosXdec = (this.currentValuePrecision == 1) ? textPosX - 19 : textPosX; - const textPosYdec = (this.currentValuePrecision == 1) ? textPosY + 7 : textPosY; - this.currentValueText = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueText.id = "CurrentValue"; - this.currentValueText.setAttribute("x", textPosXdec.toString()); - this.currentValueText.setAttribute("y", textPosY.toString()); - this.currentValueText.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueText); - const textPosXdecimal = textPosX; - const textPosYdecimal = textPosYdec; - this.currentValueTextdecimal = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimal.id = "CurrentValue"; - this.currentValueTextdecimal.setAttribute("x", textPosXdecimal.toString()); - this.currentValueTextdecimal.setAttribute("y", textPosYdecimal.toString()); - this.currentValueTextdecimal.setAttribute("alignment-baseline", "text-bottom"); - this.rootSVG.appendChild(this.currentValueTextdecimal); - const textPosXdecP = textPosX - 9; - this.currentValueTextdecimalP = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimalP.id = "CurrentValue"; - this.currentValueTextdecimalP.setAttribute("x", textPosXdecP.toString()); - this.currentValueTextdecimalP.setAttribute("y", textPosY.toString()); - //this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueTextdecimalP); - if (_gaugeDefinition.currentValueBorderWidth > 0) { - const borderWidth = this.viewBoxSize.x * _gaugeDefinition.currentValueBorderWidth; - const borderHeight = this.currentValueBorderHeight * 1.2; - const borderPosX = textPosX - (borderWidth * 0.95); - const borderPosY = textPosY - (borderHeight * 0.55); - this.currentValueBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.currentValueBorder.id = "CurrentValueBorder"; - this.currentValueBorder.setAttribute("x", borderPosX.toString()); - this.currentValueBorder.setAttribute("y", borderPosY.toString()); - this.currentValueBorder.setAttribute("width", borderWidth.toString()); - this.currentValueBorder.setAttribute("height", borderHeight.toString()); - this.rootSVG.appendChild(this.currentValueBorder); - } - if (this.extraMessageFunction != null) { - const extraMessageGroup = document.createElementNS(Avionics.SVG.NS, "g"); - extraMessageGroup.id = "ExtraMessage"; - this.extraMessageBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageBorder.setAttribute("class", "inactive"); - extraMessageGroup.appendChild(this.extraMessageBorder); - this.extraMessageText = document.createElementNS(Avionics.SVG.NS, "text"); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageText.setAttribute("class", "active"); - extraMessageGroup.appendChild(this.extraMessageText); - this.rootSVG.appendChild(extraMessageGroup); - } - this.refreshMainValue(this.minValue, true); - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(0, true); - } - if (this.outerDynamicArcFunction != null) { - this.refreshOuterDynamicArc(0, 0); - } - this.refreshActiveState(); - } - - //accepts two more parameters to set custom ID for dynamic markers - addGraduation(_value, _showInnerMarker, _text = "", _showOuterMarker = false, _setid = false, _idName = "", _markerColour = "") { - const dir = this.valueToDir(_value + this.cursorOffset); - if (_showInnerMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationInnerLineEndOffset), this.center.y + (dir.y * this.graduationInnerLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - if (_setid) { - marker.setAttribute("id",_idName); - } - if (_markerColour != "") { - marker.setAttribute("class", "InnerMarker" + " " + _markerColour); - } else { - marker.setAttribute("class", "InnerMarker"); - } - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_showOuterMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - this.outerMarkerValue = _value; - marker.setAttribute("id", _idName); - marker.setAttribute("class", "OuterMarker"); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_text.length > 0) { - const pos = new Vec2(this.center.x + (dir.x * this.graduationTextOffset), this.center.y + (dir.y * this.graduationTextOffset)); - const text = document.createElementNS(Avionics.SVG.NS, "text"); - text.textContent = _text; - text.setAttribute("x", pos.x.toString()); - text.setAttribute("y", pos.y.toString()); - text.setAttribute("alignment-baseline", "central"); - this.graduationsGroup.appendChild(text); - } - } - refreshActiveState() { - const style = this.isActive ? "active" : "inactive"; - if (this.mainArc != null) { - this.mainArc.setAttribute("class", style); - } - if (this.redArc != null) { - this.redArc.setAttribute("class", style); - } - if (this.graduationsGroup != null) { - this.graduationsGroup.setAttribute("class", style); - } - if (this.cursor != null) { - this.cursor.setAttribute("class", style); - } - if (this.outerIndicatorObject != null) { - this.outerIndicatorObject.setAttribute("class", style); - } - if (this.outerDynamicArcObject != null) { - this.outerDynamicArcObject.setAttribute("class", style); - } - if (this.currentValueText != null) { - this.currentValueText.setAttribute("class", style); - if (this.uppercam) { - this.currentValueBorder.setAttribute('class', style); - } - if (!this.isActive) { - this.currentValueText.textContent = "XX"; - this.currentValueTextdecimal.textContent = ""; - this.currentValueTextdecimalP.textContent = ""; - } - } - } - update(_deltaTime) { - if (this.isActive) { - if (this.currentValueFunction != null) { - this.refreshMainValue(this.currentValueFunction()); - } - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(this.outerIndicatorFunction()); - } - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcFunction(this.outerDynamicArcTargetValues); - this.refreshOuterDynamicArc(this.outerDynamicArcTargetValues[0], this.outerDynamicArcTargetValues[1]); - } - if (this.outerDynamicMarkerFunction != null) { - this.refreshOuterMarkerFunction(this.outerDynamicMarkerFunction()); - } - if (this.dangerMinDynamicFunction != null) { - this.refreshDangerMinFunction(this.dangerMinDynamicFunction()); - } - if (this.previousUpdateMinRedValue != this.minRedValue) { - this.refreshRedArc(); - } - } - if ((this.extraMessageFunction != null) && (this.extraMessageText != null) && (this.extraMessageBorder != null)) { - const extraMessage = this.isActive ? this.extraMessageFunction().toString() : ""; - const extraMessageStyle = this.extraMessageStyleFunction().toString(); - - let style = ""; - - if (extraMessage != this.extraMessageString || extraMessageStyle != this.extraMessageStyle) { - if (this.extraMessageFunction().toString() == "AVAIL") { - this.extraMessagePosXMultiplier = 0.198; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.345; - this.extraMessageBorderPosYMultiplier = 0.125; - this.extraMessageBorderWidthMultiplier = 0.68; - this.extraMessageBorderHeightMultiplier = 0.25; - style = "avail "; - } else { - this.extraMessagePosXMultiplier = 0.05; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - } - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageString = extraMessage; - this.extraMessageStyle = extraMessageStyle; - style += (this.extraMessageString.length > 0) ? "active" : "inactive"; - style += extraMessageStyle; - this.extraMessageBorder.setAttribute("class", style); - this.extraMessageText.setAttribute("class", style); - this.extraMessageText.textContent = this.extraMessageString; - } - } - } - refreshRedArc() { - if (this.redArc) { - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.previousUpdateMinRedValue = this.minRedValue; - } - } - calculateRedArcD() { - const minRedDir = this.valueToDir(this.minRedValue + this.cursorOffset); - const maxRedDir = this.valueToDir(this.maxRedValue + this.cursorOffset); - const topRight = new Vec2(this.center.x + (maxRedDir.x * this.mainArcRadius), this.center.y + (maxRedDir.y * this.mainArcRadius)); - const topLeft = new Vec2(this.center.x + (minRedDir.x * this.mainArcRadius), this.center.y + (minRedDir.y * this.mainArcRadius)); - const bottomRight = new Vec2(this.center.x + (maxRedDir.x * this.redArcInnerRadius), this.center.y + (maxRedDir.y * this.redArcInnerRadius)); - const bottomLeft = new Vec2(this.center.x + (minRedDir.x * this.redArcInnerRadius), this.center.y + (minRedDir.y * this.redArcInnerRadius)); - return [ - "M", topRight.x, topRight.y, - "A", this.mainArcRadius, this.mainArcRadius, 0, "0", 0, topLeft.x, topLeft.y, - "L", bottomLeft.x, bottomLeft.y, - "M", topRight.x, topRight.y, - "L", bottomRight.x, bottomRight.y, - "A", this.redArcInnerRadius, this.redArcInnerRadius, 0, "0", 0, bottomLeft.x, bottomLeft.y - ].join(" "); - } - //accepts ID_EGT, _value[0] = _id, _value[1] = EGT - refreshOuterMarkerFunction(_value, _force = false) { - if (_value[1] != this.outerMarkerValue) { - this.outerMarkerValue = _value[1]; - const marker = document.getElementById(_value[0]); - marker.style.display = hasThermodynamicTemperatureValue(this.outerMarkerValue) ? "block" : "none"; - - if (marker.style.display === "block") { - const dir = this.valueToDir(_value[1]); - const start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - const end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - } - } - } - refreshDangerMinFunction(_value, _force = false) { - if (_value != this.dangerRange[0]) { - this.dangerRange[0] = _value; - } - } - refreshMainValue(_value, _force = false) { - this.currentValue = _value; - this.currentValueCursor = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - const clampedValue = Utils.Clamp(this.currentValue, this.minValue, this.maxValue); - const clampedValueCursor = Utils.Clamp(this.currentValueCursor, this.minValue, this.maxValue); - let style = ""; - if ((this.dangerRange[0] != this.dangerRange[1]) && (clampedValue >= this.dangerRange[0]) && (clampedValue <= this.dangerRange[1])) { - style = "danger"; - } else if ((this.warningRange[0] != this.warningRange[1]) && (clampedValue >= this.warningRange[0]) && (clampedValue <= this.warningRange[1])) { - style = "warning"; - } else { - style = "active"; - } - if (this.cursor != null) { - const angle = this.valueToAngle(clampedValueCursor, false); - this.cursor.setAttribute("transform", "rotate(" + angle + ")"); - this.cursor.setAttribute("class", style); - } - if (this.currentValueText != null) { - let displayValue = this.currentValue; - if (this.roundDisplayValueToNearest) { - displayValue = Math.round(displayValue / this.roundDisplayValueToNearest) * this.roundDisplayValueToNearest; - } - const strValue = displayValue.toFixed(this.currentValuePrecision); - this.currentValueText.textContent = strValue; - this.currentValueText.setAttribute("class", style); - if (this.currentValuePrecision > 0) { - const strValueArray = strValue.split("."); - this.currentValueText.textContent = strValueArray[0]; - this.currentValueTextdecimal.textContent = strValueArray[1]; - this.currentValueTextdecimal.setAttribute("class", style + " decimal"); - this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("class", style + " decimalpoint"); - } - } - } - refreshOuterIndicator(_value, _force = false) { - if ((_value != this.outerIndicatorValue) || _force) { - this.outerIndicatorValue = _value; - if (this.outerIndicatorObject != null) { - const valueThrottlePosition = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - //const valueThrottlePosition = _value + this.cursorOffset; - const clampedValueThrottlePosition = Utils.Clamp(valueThrottlePosition , this.minValue, this.maxValue); - const angle = this.valueToAngle(clampedValueThrottlePosition, false); - this.outerIndicatorObject.setAttribute("transform", "rotate(" + angle + ")"); - } - } - } - refreshOuterDynamicArc(_start, _end, _force = false) { - if ((_start != this.outerDynamicArcCurrentValues[0]) || (_end != this.outerDynamicArcCurrentValues[1]) || _force) { - this.outerDynamicArcCurrentValues[0] = Utils.Clamp(_start, this.minValue, this.maxValue); - this.outerDynamicArcCurrentValues[1] = Utils.Clamp(_end, this.minValue, this.maxValue); - let d = ""; - if (this.outerDynamicArcCurrentValues[0] != this.outerDynamicArcCurrentValues[1]) { - const startAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[0], true); - const startX = this.center.x + (Math.cos(startAngle) * this.outerDynamicArcRadius); - const startY = this.center.y + (Math.sin(startAngle) * this.outerDynamicArcRadius); - const endAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[1], true); - const endX = this.center.x + (Math.cos(endAngle) * this.outerDynamicArcRadius); - const endY = this.center.y + (Math.sin(endAngle) * this.outerDynamicArcRadius); - const largeArcFlag = ((endAngle - startAngle) <= Math.PI) ? "0 0 0" : "0 1 0"; - d = [ - "M", endX, endY, - "A", this.outerDynamicArcRadius, this.outerDynamicArcRadius, largeArcFlag, startX, startY - ].join(" "); - } - this.outerDynamicArcObject.setAttribute("d", d); - } - } - } - A320_Neo_ECAM_Common.Gauge = Gauge; -})(A320_Neo_ECAM_Common || (A320_Neo_ECAM_Common = {})); -customElements.define('a320-neo-ecam-gauge', A320_Neo_ECAM_Common.Gauge); diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.css b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.css deleted file mode 100644 index a2c2f8bb..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.css +++ /dev/null @@ -1,68 +0,0 @@ -@import url("/CSS/A318HS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; -} -#Electricity[state="off"] { - display: none; -} - -eicas-common-display { - display: block; - position: absolute; - bottom: 0%; - left: 0%; - width: 100%; - height: 25%; -} -eicas-common-display line { - stroke: var(--displayWhite) !important; - stroke-width: 3; -} -eicas-common-display text { - font-size: 20px; - font-family: "ECAMFontRegular"; -} -eicas-common-display text.Cyan { - fill: var(--displayCyan) !important; -} -eicas-common-display text.White { - fill: var(--displayWhite) !important; -} -eicas-common-display text.Value { - fill: var(--displayGreen) !important; -} -eicas-common-display text.Unit { - font-size: 15px !important; - fill: var(--displayCyan) !important; -} -eicas-common-display text.Warning { - fill: var(--displayAmber) !important; -} -eicas-common-display text.Small { - font-size: 18px !important; -} diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.html b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.html deleted file mode 100644 index 2414fda8..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - diff --git a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.js b/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.js deleted file mode 100644 index e8c6916a..00000000 --- a/hsim-a318ceo/src/base/lvfr-horizonsim-airbus-a318-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a318-ceo/EICAS/EICAS_Common.js +++ /dev/null @@ -1,191 +0,0 @@ -class EICASCommonDisplay extends Airliners.EICASTemplateElement { - constructor() { - super(); - this.isInitialised = false; - } - get templateID() { - return "EICASCommonDisplayTemplate"; - } - connectedCallback() { - super.connectedCallback(); - TemplateElement.call(this, this.init.bind(this)); - } - init() { - this.tatText = this.querySelector("#TATValue"); - this.satText = this.querySelector("#SATValue"); - this.isaText = this.querySelector("#ISAValue"); - this.isaContainer = this.querySelector("#ISA"); - this.areAdirsAligned = null; - this.isSATVisible = null; - this.isTATVisible = null; - this.isISAVisible = null; - this.currentSeconds = 0; - this.currentMinutes = 0; - this.hoursText = this.querySelector("#HoursValue"); - this.minutesText = this.querySelector("#MinutesValue"); - this.loadFactorContainer = this.querySelector("#LoadFactor"); - this.loadFactorText = this.querySelector("#LoadFactorValue"); - this.loadFactorSet = new NXLogic_ConfirmNode(2); - this.loadFactorReset = new NXLogic_ConfirmNode(5); - this.loadFactorVisible = new NXLogic_MemoryNode(true); - this.gwUnit = this.querySelector("#GWUnit"); - this.gwValue = this.querySelector("#GWValue"); - this.refreshTAT(Arinc429Word.empty()); - this.refreshSAT(Arinc429Word.empty()); - this.refreshISA(Arinc429Word.empty()); - this.refreshClock(); - this.refreshGrossWeight(true); - this.isInitialised = true; - } - update(_deltaTime) { - if (!this.isInitialised) { - return; - } - - const airDataReferenceSource = this.getStatusAirDataReferenceSource(); - const inertialReferenceSource = this.getStatusInertialReferenceSource(); - const sat = Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_STATIC_AIR_TEMPERATURE`); - /* this.refreshTAT(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_TOTAL_AIR_TEMPERATURE`)); - this.refreshSAT(sat); - this.refreshISA(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_INTERNATIONAL_STANDARD_ATMOSPHERE_DELTA`), sat); */ - - this.refreshClock(); - this.refreshLoadFactor(_deltaTime, Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_IR_${inertialReferenceSource}_BODY_NORMAL_ACC`)); - this.refreshGrossWeight(); - this.refreshHomeCockpitMode(); - } - - getStatusAirDataReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_AIR_DATA_SWITCHING_KNOB', 'Enum')); - } - - getStatusInertialReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_ATT_HDG_SWITCHING_KNOB', 'Enum')); - } - - getStatusSupplier(knobValue) { - const adirs3ToCaptain = 0; - return knobValue === adirs3ToCaptain ? 3 : 1; - } - - refreshTAT(tat) { - if (!tat.isNormalOperation()) { - this.tatText.textContent = "XX"; - this.toggleWarning(true, this.tatText); - } else { - this.setValueOnTemperatureElement(Math.round(tat.value), this.tatText); - this.toggleWarning(false, this.tatText); - } - } - - refreshSAT(sat) { - if (!sat.isNormalOperation()) { - this.satText.textContent = "XX"; - this.toggleWarning(true, this.satText); - } else { - this.setValueOnTemperatureElement(Math.round(sat.value), this.satText); - this.toggleWarning(false, this.satText); - } - } - - refreshISA(isa, sat) { - const isInStdMode = Simplane.getPressureSelectedMode(Aircraft.A320_NEO) === "STD"; - // As ISA relates to SAT, we cannot present ISA when SAT is unavailable. We might want to move this into - // Rust ADIRS code itself. - const isaShouldBeVisible = isInStdMode && isa.isNormalOperation() && sat.isNormalOperation(); - this.isaContainer.setAttribute("visibility", isaShouldBeVisible ? "visible" : "hidden"); - - this.setValueOnTemperatureElement(Math.round(isa.value), this.isaText); - } - - setValueOnTemperatureElement(value, element) { - if (value > 0) { - element.textContent = "+" + value.toString().padStart(2); - } else { - element.textContent = (value < 0 ? "-" : "") + Math.abs(value).toString().padStart(2); - } - } - - toggleWarning(isWarning, element) { - element.classList.toggle("Warning", isWarning); - element.classList.toggle("Value", !isWarning); - } - - refreshLoadFactor(_deltaTime, n_z) { - const value = n_z.value; - const conditionsMet = value > 1.4 || value < 0.7; - const loadFactorSet = this.loadFactorSet.write(conditionsMet && n_z.isNormalOperation(), _deltaTime); - const loadFactorReset = this.loadFactorReset.write(!conditionsMet || !n_z.isNormalOperation(), _deltaTime); - const flightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - const isVisible = ( - flightPhase >= 4 && - flightPhase <= 8 && - this.loadFactorVisible.write(loadFactorSet, loadFactorReset) - ); - - if (this.loadFactorContainer) { - if (!isVisible) { - this.loadFactorContainer.setAttribute("visibility", "hidden"); - if (this.loadFactorText) { - this.loadFactorText.textContent = ""; - } - return; - } - this.loadFactorContainer.setAttribute("visibility", "visible"); - } - - if (this.loadFactorText) { - if (n_z.isNormalOperation()) { - const clamped = Math.min(Math.max(value, -3), 5); - this.loadFactorText.textContent = (clamped >= 0 ? "+" : "") + clamped.toFixed(1); - } else { - this.loadFactorText.textContent = 'XX'; - } - - } - } - refreshClock() { - const seconds = Math.floor(SimVar.GetGlobalVarValue("ZULU TIME", "seconds")); - if (seconds != this.currentSeconds) { - this.currentSeconds = seconds; - const hours = Math.floor(seconds / 3600); - const minutes = Math.floor((seconds - (hours * 3600)) / 60); - if (minutes != this.currentMinutes) { - this.currentMinutes = minutes; - if (this.hoursText != null) { - this.hoursText.textContent = hours.toString().padStart(2, "0"); - } - if (this.minutesText != null) { - this.minutesText.textContent = minutes.toString().padStart(2, "0"); - } - } - } - } - refreshGrossWeight(_force = false) { - const isOneEngineRunning = SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:1", "Number") >= 15 || SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:2", "Number") >= 15; //BASED ON IRL REFERENCE - const gw = Math.round(NXUnits.kgToUser(SimVar.GetSimVarValue("L:A32NX_FM_GROSS_WEIGHT", "number") * 1000)); - const gwUnit = NXUnits.userWeightUnit(); - if ((gw != this.currentGW) || (this.isOneEngineRunning != isOneEngineRunning) || _force) { - this.currentGW = gw; - this.isOneEngineRunning = isOneEngineRunning; - - if (isOneEngineRunning && this.currentGW != 0) { - // Lower EICAS displays GW in increments of 100 - this.gwValue.classList.add("Value"); - this.gwValue.classList.remove("Cyan"); - this.gwValue.textContent = (Math.floor(this.currentGW / 100) * 100).toString(); - } else { - this.gwValue.classList.remove("Value"); - this.gwValue.classList.add("Cyan"); - this.gwValue.textContent = "--"; - } - } - if (gwUnit != this.currentGwUnit) { - this.currentGwUnit = gwUnit; - if (this.gwUnit != null) { - this.gwUnit.textContent = gwUnit; - } - } - } -} -customElements.define("eicas-common-display", EICASCommonDisplay); diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.css b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.css deleted file mode 100644 index ca6d2c25..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.css +++ /dev/null @@ -1,256 +0,0 @@ -@import url("/CSS/A319HS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); -} -#Electricity[state="off"] { - display: none; -} - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); - height: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #RedArc { - fill: none; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 3; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder { - fill: none; - stroke: var(--displayGrey); - stroke-width: 3px; -} - -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: black; - stroke: var(--displayGrey); - stroke-width: 3px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none; -} - -a320-neo-eicas-element { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; -} -a320-neo-eicas-element #highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -a320-neo-eicas-element #Mainframe { - top: 0; - left: 0; - width: 100%; - height: 100%; - display: block; - position: relative; -} -a320-neo-eicas-element #Mainframe #TopScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); - transform: rotateX(0); - top: 0%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} -a320-neo-eicas-element #Mainframe #BottomScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); - transform: rotateX(0); - top: 5%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} - -a320-neo-eicas-element[index="1"] #Mainframe #TopScreen { - display: block; -} -a320-neo-eicas-element[index="2"] #Mainframe #BottomScreen { - display: block; -} -.blue-text { - color: var(--displayCyan); -} -.SelfTestWrapper { - position: absolute; - left: 0%; - top: 0%; - width: 100%; - height: 100%; - border: none; - visibility: hidden; -} -#BottomScreen #door-video-wrapper { - position: absolute; - top: -5%; - width: 100%; - height: 82%; - z-index: 100; - visibility: hidden; - background-image: url(DoorVideoResources/empty.png); - background-size: cover; -} diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.html b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.html deleted file mode 100644 index 479d274b..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.js b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.js deleted file mode 100644 index 7555c287..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS.js +++ /dev/null @@ -1,315 +0,0 @@ -class A320_Neo_EICAS extends Airliners.BaseEICAS { - get templateID() { - return "A320_Neo_EICAS"; - } - - // This js file has 2 intances at runtime, 1 upper screen and 1 lower - get isTopScreen() { - return this.urlConfig.index === 1; - } - - get isBottomScreen() { - return this.urlConfig.index === 2; - } - - // The following two functions can be called from anywhere on the EICAS - static isOnTopScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isTopScreen; - } - - static isOnBottomScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isBottomScreen; - } - - changePage(_pageName) { - let pageName = _pageName.toUpperCase(); - const isOnGround = SimVar.GetSimVarValue("GEAR IS ON GROUND","Bool"); - for (let i = 0; i < this.lowerScreenPages.length; i++) { - //skip CRZ and go back to ENG Page - if (this.lowerScreenPages[i].name == "CRZ" && isOnGround) { - pageName = "ENG"; - //The index of the ENG page is 0 so loop counter will point to correct index without triggering a new iteration. - i = 0; - } - if (this.lowerScreenPages[i].name == pageName) { - let pageIndex = i; - if (pageIndex == this.currentPage) { - pageName = this.pageNameWhenUnselected; - pageIndex = -1; - } - - this.currentPage = pageIndex; - break; - } - } - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, pageName); - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", this.currentPage); - } - - createLowerScreenPages() { - this.addIndependentElementContainer(new Airliners.EICASScreen("BottomScreenCommon", "BottomScreen", "eicas-common-display")); - this.createLowerScreenPage("ENG", "BottomScreen", "a32nx-eng-page-element"); - this.createLowerScreenPage("BLEED", "BottomScreen", "a32nx-bleed-page-element"); - this.createLowerScreenPage("PRESS", "BottomScreen", "a32nx-press-page-element"); - this.createLowerScreenPage("ELEC", "BottomScreen", "a32nx-elec-page-element"); - this.createLowerScreenPage("HYD", "BottomScreen", "a32nx-hyd-page-element"); - this.createLowerScreenPage("FUEL", "BottomScreen", "a32nx-fuel-page-element"); - this.createLowerScreenPage("APU", "BottomScreen", "a32nx-apu-page-element"); - this.createLowerScreenPage("COND", "BottomScreen", "a32nx-cond-page-element"); - this.createLowerScreenPage("DOOR", "BottomScreen", "a32nx-door-page-element"); - this.createLowerScreenPage("WHEEL", "BottomScreen", "a32nx-wheel-page-element"); - this.createLowerScreenPage("FTCL", "BottomScreen", "a32nx-fctl-page-element"); - this.createLowerScreenPage("STS", "BottomScreen", "a32nx-status-page-element"); - this.createLowerScreenPage("CRZ", "BottomScreen", "a32nx-crz-page-element"); - } - - getLowerScreenChangeEventNamePrefix() { - return "ECAM_CHANGE_PAGE_"; - } - - Init() { - super.Init(); - this.getDeltaTime = A32NX_Util.createDeltaTimeCalculator(this._lastTime); - this.currentPage = -1; - this.ecamAllButtonTimer = 1000; - this.ecamAllButtonTimerStarted = false; - - this.pageNameWhenUnselected = "DOOR"; - - this.ecamFCTLTimer = -1; - - this.changePage("FUEL"); // MODIFIED - - this.lastAPUMasterState = 0; // MODIFIED - this.ApuAboveThresholdTimer = -1; // MODIFIED - this.MainEngineStarterOffTimer = -1; - this.CrzCondTimer = 60; - this.PrevFailPage = -1; - - this.doorVideoWrapper = this.querySelector("#door-video-wrapper"); - - this.lowerEngTestDiv = this.querySelector("#Eicas2EngTest"); - this.lowerEngMaintDiv = this.querySelector("#Eicas2MaintMode"); - - this.doorVideoPressed = false; - this.doorVideoEnabled = false; - - // Using ternary in case the LVar is undefined - this.poweredDuringPreviousUpdate = SimVar.GetSimVarValue("L:A32NX_COLD_AND_DARK_SPAWN", "Bool") ? 0 : 1; - - this.changePage("DOOR"); // MODIFIED - this.changePage("DOOR"); // This should get the ECAM into the "unselected" state - - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:7", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:84", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:85", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:86", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:87", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:88", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:89", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:90", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:91", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:92", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:93", "number", 0.1); - - this.ecamAllButtonPrevState = false; - this.updateThrottler = new UpdateThrottler(500); - - this.displayUnit = new DisplayUnit( - this.querySelector("#Electricity"), - () => { - return SimVar.GetSimVarValue("L:A32NX_ELEC_AC_2_BUS_IS_POWERED", "Bool"); - }, - () => parseInt(NXDataStore.get("CONFIG_SELF_TEST_TIME", "15")), - 93, - this.querySelector("#BottomSelfTest") - ); - } - - onUpdate() { - let deltaTime = this.getDeltaTime(); - super.onUpdate(deltaTime); - - const ecamAllButtonBeingPushed = SimVar.GetSimVarValue("L:A32NX_ECAM_ALL_Push_IsDown", "Bool"); - - deltaTime = this.updateThrottler.canUpdate(deltaTime, this.displayUnit.isJustNowTurnedOn() || ecamAllButtonBeingPushed); - if (deltaTime === -1) { - return; - } - - this.displayUnit.update(deltaTime); - - this.updateDoorVideoState(); - - // Engineering self-tests - updateDisplayDMC("EICAS2", this.lowerEngTestDiv, this.lowerEngMaintDiv); - - //Determine displayed page when no button is selected - const prevPage = this.pageNameWhenUnselected; - - const fwcFlightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - - switch (fwcFlightPhase) { - case 10: - case 1: - this.CrzCondTimer = 60; - this.pageNameWhenUnselected = "DOOR"; - //TODO: Emergency Generator Test displays ELEC - //Needs system implementation (see A320_NEO_INTERIOR Component ID EMER_ELEC_PWR [LVar: L:A32NX_EMERELECPWR_GEN_TEST]) - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 2: - const sidestickPosX = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_X", "Number"); - const sidestickPosY = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_Y", "Number"); - const rudderPos = SimVar.GetSimVarValue("RUDDER PEDAL POSITION", "Position"); - const controlsMoved = Math.abs(sidestickPosX) > 0.05 || Math.abs(sidestickPosY) > 0.05 || Math.abs(rudderPos) > 0.2; - - this.pageNameWhenUnselected = "WHEEL"; - // When controls are moved > threshold, show FCTL page for 20s - if (controlsMoved) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer = 20; - } else if (this.ecamFCTLTimer >= 0) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer -= deltaTime / 1000; - } - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 3: - case 4: - case 5: - this.pageNameWhenUnselected = "ENG"; - break; - case 6: - case 7: - case 8: - case 9: - const isGearExtended = SimVar.GetSimVarValue("GEAR TOTAL PCT EXTENDED", "percent") > 0.95; - const ToPowerSet = Math.max(SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:1", "number"), SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:2", "number")) >= 35 && SimVar.GetSimVarValue("ENG N1 RPM:1", "Percent") > 15 && SimVar.GetSimVarValue("ENG N1 RPM:2", "Percent") > 15; - const spoilerOrFlapsDeployed = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "number") !== 0 || SimVar.GetSimVarValue("L:A32NX_SPOILERS_HANDLE_POSITION", "percent") !== 0; - - if (isGearExtended && (Simplane.getAltitude() < 16000)) { - this.pageNameWhenUnselected = "WHEEL"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - // Else check for CRZ - } - - if ((spoilerOrFlapsDeployed || ToPowerSet)) { - if (this.CrzCondTimer <= 0) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } else { - this.CrzCondTimer -= deltaTime / 1000; - } - } else if (!spoilerOrFlapsDeployed && !ToPowerSet) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } - break; - default: - // Sometimes happens when loading in, in which case we have to initialise pageNameWhenUnselected here. - this.pageNameWhenUnselected = "DOOR"; - break; - } - - const sFailPage = SimVar.GetSimVarValue("L:A32NX_ECAM_SFAIL", "Enum"); - - if (sFailPage != -1) { - this.pageNameWhenUnselected = this.lowerScreenPages[sFailPage].name; - - // Disable user selected page when new failure detected - if (this.PrevFailPage !== sFailPage) { - this.currentPage = -1; - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", -1); - } - } - - // switch page when desired page was changed, or new Failure detected - if ((this.pageNameWhenUnselected != prevPage && this.currentPage == -1) || (this.PrevFailPage !== sFailPage)) { - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, this.pageNameWhenUnselected); - } - - if (ecamAllButtonBeingPushed && !this.ecamAllButtonPrevState) { // button press - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - this.ecamCycleInterval = setInterval(() => { - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - }, 1000); - } else if (!ecamAllButtonBeingPushed && this.ecamAllButtonPrevState) { // button release - clearInterval(this.ecamCycleInterval); - } - - this.ecamAllButtonPrevState = ecamAllButtonBeingPushed; - this.PrevFailPage = sFailPage; - } - - checkEnginePage(deltaTime) { - const engModeSel = SimVar.GetSimVarValue("L:XMLVAR_ENG_MODE_SEL", "number"); - const eng1State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:1", "number"); - const eng2State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:2", "number"); - const oneEngOff = eng1State !== 1 || eng2State !== 1; - - if (engModeSel === 0 || (oneEngOff && engModeSel === 2) || this.MainEngineStarterOffTimer >= 0) { - // Show ENG until >10 seconds after both engines are fully started - if (engModeSel === 0 || (oneEngOff && engModeSel === 2)) { - this.MainEngineStarterOffTimer = 10; - } else if (this.MainEngineStarterOffTimer >= 0) { - this.MainEngineStarterOffTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "ENG"; - } - } - - checkApuPage(deltaTime) { - const currentAPUMasterState = SimVar.GetSimVarValue("L:A32NX_OVHD_APU_MASTER_SW_PB_IS_ON", "Bool"); - const apuRpm = Arinc429Word.fromSimVarValue("L:A32NX_APU_N"); - if (currentAPUMasterState && apuRpm.isNormalOperation() && (apuRpm.value <= 95 || this.ApuAboveThresholdTimer >= 0)) { - // Show APU on Lower ECAM until 15s after RPM > 95% - if (this.ApuAboveThresholdTimer <= 0 && apuRpm.value <= 95) { - this.ApuAboveThresholdTimer = 15; - } else if (apuRpm.value > 95) { - this.ApuAboveThresholdTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "APU"; - } - } - - updateDoorVideoState() { - const doorVideoEnabledNow = SimVar.GetSimVarValue("L:A32NX_OVHD_COCKPITDOORVIDEO_TOGGLE", "Bool") === 1; - const doorVideoPressedNow = SimVar.GetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool") === 1; - - if (this.doorVideoEnabled !== doorVideoEnabledNow || this.doorVideoPressed !== doorVideoPressedNow) { - this.doorVideoEnabled = doorVideoEnabledNow; - this.doorVideoPressed = doorVideoPressedNow; - - this.setDoorVideo(); - } - } - - setDoorVideo() { - this.doorVideoWrapper.style.visibility = this.doorVideoEnabled && this.doorVideoPressed ? "visible" : "hidden"; - } - - SwitchToPageName(_menu, _page) { - if (this.doorVideoPressed) { - SimVar.SetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool", 0); - } - - super.SwitchToPageName(_menu, _page); - } -} - -registerInstrument("a320-neo-eicas-element", A320_Neo_EICAS); diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_IAE.html b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_IAE.html deleted file mode 100644 index 99688898..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_IAE.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_SL.html b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_SL.html deleted file mode 100644 index 4139222b..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/A320_Neo_EICAS_SL.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/DoorVideoResources/empty.png b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/DoorVideoResources/empty.png deleted file mode 100644 index f35008acb166bc2754c26028bd43a83cb0e95e0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48821 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 LeYFM^+nE0kG0W-* diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css deleted file mode 100644 index 2d3655fc..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css +++ /dev/null @@ -1,172 +0,0 @@ -@import url("/CSS/A319HS_Display_Common.css"); - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: get-vh(640px); - height: get-vh(640px); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} - -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} - -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - fill: none; -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke-width: 1px !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .danger { - stroke-width: 1px !important; - stroke: var(--displayRed) !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .warning { - stroke-width: 1px !important; - stroke: var(--displayAmber) !important; -} -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - stroke-width: 2px; - fill: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); - stroke-width: 6px; -} -a320-neo-ecam-gauge #RootSVG #OuterIndicatorOffset { - stroke: var(--displayCyan) !important; - stroke-width: 1.5px !important; - fill: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 2; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 2px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; - font-size: 20px !important; - fill: var(--displayBackground); -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder, -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.active { - fill: none; - stroke: lightblue; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.inactive { - fill: none; - stroke: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.decimal { - font-size: 15px !important; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.gaugedecimalpoint { - fill: var(--displayGreen); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: var(--displayBackground); - stroke: lightblue; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text.amber { - fill: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .avail { - font-size: 19.2px !important; -} diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js deleted file mode 100644 index 7fbc8b5c..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js +++ /dev/null @@ -1,549 +0,0 @@ -var A320_Neo_ECAM_Common; -(function (A320_Neo_ECAM_Common) { - const absoluteZeroThermodynamicTemperature = -273.15; - - function hasThermodynamicTemperatureValue(value) { - return value >= absoluteZeroThermodynamicTemperature; - } - - function isEngineDisplayActive(_index) { - return ((SimVar.GetSimVarValue("ENG N1 RPM:" + _index, "percent") >= 0.05) || (SimVar.GetSimVarValue("ENG N2 RPM:" + _index, "percent") >= 0.05)); - } - A320_Neo_ECAM_Common.isEngineDisplayActive = isEngineDisplayActive; - class GaugeDefinition { - constructor() { - this.startAngle = -225; - this.arcSize = 180; - this.cursorOffset = 0; - this.minValue = 0; - this.maxValue = 100; - this.minRedValue = 0; - this.maxRedValue = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.cursorLength = 1.0; - this.cursorMultiplier = 1.1; - this.currentValuePos = new Vec2(0.65, 0.65); - this.currentValueFunction = null; - this.currentValuePrecision = 0; - this.currentValueBorderWidth = 0; - this.outerIndicatorFunction = null; - this.outerDynamicArcFunction = null; - this.extraMessageFunction = null; - this.extraMessageStyleFunction = null; - this.outerDynamicMarkerFunction = null; - this.dangerMinDynamicFunction = null; - this.outerMarkerValue = null; - this.roundDisplayValueToNearest = null; - } - } - A320_Neo_ECAM_Common.GaugeDefinition = GaugeDefinition; - class Gauge extends HTMLElement { - constructor() { - super(...arguments); - this.viewBoxSize = new Vec2(100, 100); - this.startAngle = -225; - this.cursorOffset = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.outerDynamicArcCurrentValues = [0, 0]; - this.outerDynamicArcTargetValues = [0, 0]; - this.extraMessageString = ""; - this.extraMessageStyle = ""; - this.isActive = true; - this.extraMessagePosXMultiplier = 0; - this.extraMessagePosYMultiplier = 0; - this.extraMessageBorderPosXMultiplier = 0; - this.extraMessageBorderPosYMultiplier = 0; - this.extraMessageBorderWidthMultiplier = 0; - this.extraMessageBorderHeightMultiplier = 0; - this.cursorMultiplier = 1.1; - this.uppercam = false; - } - get mainArcRadius() { - return (this.viewBoxSize.x * 0.5 * 0.975); - } - get cursorArcRadius() { - return (this.mainArcRadius * this.cursorMultiplier); - } - get graduationInnerLineEndOffset() { - return (this.mainArcRadius * 0.9); - } - get graduationOuterLineEndOffset() { - return (this.mainArcRadius * 1.175); - } - get graduationTextOffset() { - return (this.mainArcRadius * 0.625); - } - get redArcInnerRadius() { - return (this.mainArcRadius * 1); - } - get outerIndicatorOffset() { - return (this.viewBoxSize.x * 0.03); - } - get outerIndicatorRadius() { - return (this.viewBoxSize.x * 0.03); - } - get outerDynamicArcRadius() { - return (this.mainArcRadius * 1.15); - } - get currentValueBorderHeight() { - return (this.viewBoxSize.y * 0.20); - } - get extraMessagePosX() { - return (this.center.x + (this.viewBoxSize.x * this.extraMessagePosXMultiplier)); - } - get extraMessagePosY() { - return (this.center.y - (this.viewBoxSize.y * this.extraMessagePosYMultiplier)); - } - get extraMessageBorderPosX() { - return (this.extraMessagePosX - (this.viewBoxSize.x * this.extraMessageBorderPosXMultiplier)); - } - get extraMessageBorderPosY() { - return (this.extraMessagePosY - (this.viewBoxSize.y * this.extraMessageBorderPosYMultiplier)); - } - get extraMessageBorderWidth() { - return (this.viewBoxSize.x * this.extraMessageBorderWidthMultiplier); - } - get extraMessageBorderHeight() { - return (this.viewBoxSize.y * this.extraMessageBorderHeightMultiplier); - } - set active(_isActive) { - if (this.isActive != _isActive) { - this.isActive = _isActive; - this.refreshActiveState(); - } - } - get active() { - return this.isActive; - } - polarToCartesian(_centerX, _centerY, _radius, _angleInDegrees) { - const angleInRadians = _angleInDegrees * (Math.PI / 180.0); - return new Vec2(_centerX + (_radius * Math.cos(angleInRadians)), _centerY + (_radius * Math.sin(angleInRadians))); - } - valueToAngle(_value, _radians) { - const valuePercentage = (_value - this.minValue) / (this.maxValue - this.minValue); - let angle = (this.startAngle + (valuePercentage * this.arcSize)); - if (_radians) { - angle *= (Math.PI / 180.0); - } - return angle; - } - valueToDir(_value) { - const angle = this.valueToAngle(_value, true); - return (new Vec2(Math.cos(angle), Math.sin(angle))); - } - init(_gaugeDefinition) { - this.cursorOffset = _gaugeDefinition.cursorOffset; - this.startAngle = _gaugeDefinition.startAngle; - this.arcSize = _gaugeDefinition.arcSize; - this.minValue = _gaugeDefinition.minValue; - this.maxValue = _gaugeDefinition.maxValue; - this.minRedValue = _gaugeDefinition.minRedValue; - this.previousUpdateMinRedValue = _gaugeDefinition.minRedValue; - this.maxRedValue = _gaugeDefinition.maxRedValue; - this.warningRange[0] = _gaugeDefinition.warningRange[0]; - this.warningRange[1] = _gaugeDefinition.warningRange[1]; - this.dangerRange[0] = _gaugeDefinition.dangerRange[0]; - this.dangerRange[1] = _gaugeDefinition.dangerRange[1]; - this.cursorMultiplier = _gaugeDefinition.cursorMultiplier; - this.currentValueFunction = _gaugeDefinition.currentValueFunction; - this.currentValuePrecision = _gaugeDefinition.currentValuePrecision; - this.outerIndicatorFunction = _gaugeDefinition.outerIndicatorFunction; - this.outerDynamicArcFunction = _gaugeDefinition.outerDynamicArcFunction; - this.extraMessageFunction = _gaugeDefinition.extraMessageFunction; - this.extraMessageStyleFunction = _gaugeDefinition.extraMessageStyleFunction; - this.roundDisplayValueToNearest = _gaugeDefinition.roundDisplayValueToNearest; - this.extraMessagePosXMultiplier = 0.025; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - this.outerDynamicMarkerFunction = _gaugeDefinition.outerDynamicMarkerFunction; - this.dangerMinDynamicFunction = _gaugeDefinition.dangerMinDynamicFunction; - this.uppercam = _gaugeDefinition.uppercam; - this.endAngle = this.startAngle + _gaugeDefinition.arcSize; - this.center = new Vec2(this.viewBoxSize.x * 0.5, this.viewBoxSize.y * 0.5); - this.rootSVG = document.createElementNS(Avionics.SVG.NS, "svg"); - this.rootSVG.id = "RootSVG"; - this.rootSVG.setAttribute("viewBox", "0 0 " + this.viewBoxSize.x + " " + this.viewBoxSize.y); - this.appendChild(this.rootSVG); - this.mainArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.mainArc.id = "MainArc"; - { - const startPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.endAngle); - const endPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.startAngle); - const largeArcFlag = ((this.endAngle - this.startAngle) <= 180) ? "0" : "1"; - var d = ["M", startPos.x, startPos.y, "A", this.mainArcRadius, this.mainArcRadius, 0, largeArcFlag, 0, endPos.x, endPos.y].join(" "); - this.mainArc.setAttribute("d", d); - } - this.rootSVG.appendChild(this.mainArc); - if (this.minRedValue != this.maxRedValue) { - this.redArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.redArc.id = "RedArc"; - - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.rootSVG.appendChild(this.redArc); - } - this.graduationsGroup = document.createElementNS(Avionics.SVG.NS, "g"); - this.graduationsGroup.id = "GraduationsGroup"; - this.rootSVG.appendChild(this.graduationsGroup); - const cursorGroup = document.createElementNS(Avionics.SVG.NS, "g"); - cursorGroup.id = "CursorGroup"; - this.cursor = document.createElementNS(Avionics.SVG.NS, "line"); - this.cursorArcRadiusChoice = this.cursorArcRadius; - if (this.outerDynamicArcFunction != null) { - this.cursorArcRadiusChoice = this.outerDynamicArcRadius; - } - this.cursor.setAttribute("x1", (this.cursorArcRadiusChoice * (1 - _gaugeDefinition.cursorLength)).toString()); - this.cursor.setAttribute("y1", "0"); - this.cursor.setAttribute("x2", this.cursorArcRadiusChoice.toString()); - this.cursor.setAttribute("y2", "0"); - cursorGroup.setAttribute("transform", "translate(" + this.center.x + ", " + this.center.y + ")"); - cursorGroup.appendChild(this.cursor); - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerDynamicArcObject.id = "OuterDynamicArcObject"; - this.rootSVG.appendChild(this.outerDynamicArcObject); - } - if (this.outerIndicatorFunction != null) { - this.outerIndicatorObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerIndicatorObject.id = "OuterIndicatorOffset"; - const radius = this.outerIndicatorRadius; - var d = [ - "M", (this.mainArcRadius + this.outerIndicatorOffset), "0", - "a", radius, radius, "0 1 0", (radius * 2), "0", - "a", radius, radius, "0 1 0", -(radius * 2), "0" - ].join(" "); - this.outerIndicatorObject.setAttribute("d", d); - cursorGroup.appendChild(this.outerIndicatorObject); - } - this.rootSVG.appendChild(cursorGroup); - const textPosX = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.x; - const textPosY = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.y; - const textPosXdec = (this.currentValuePrecision == 1) ? textPosX - 19 : textPosX; - const textPosYdec = (this.currentValuePrecision == 1) ? textPosY + 7 : textPosY; - this.currentValueText = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueText.id = "CurrentValue"; - this.currentValueText.setAttribute("x", textPosXdec.toString()); - this.currentValueText.setAttribute("y", textPosY.toString()); - this.currentValueText.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueText); - const textPosXdecimal = textPosX; - const textPosYdecimal = textPosYdec; - this.currentValueTextdecimal = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimal.id = "CurrentValue"; - this.currentValueTextdecimal.setAttribute("x", textPosXdecimal.toString()); - this.currentValueTextdecimal.setAttribute("y", textPosYdecimal.toString()); - this.currentValueTextdecimal.setAttribute("alignment-baseline", "text-bottom"); - this.rootSVG.appendChild(this.currentValueTextdecimal); - const textPosXdecP = textPosX - 9; - this.currentValueTextdecimalP = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimalP.id = "CurrentValue"; - this.currentValueTextdecimalP.setAttribute("x", textPosXdecP.toString()); - this.currentValueTextdecimalP.setAttribute("y", textPosY.toString()); - //this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueTextdecimalP); - if (_gaugeDefinition.currentValueBorderWidth > 0) { - const borderWidth = this.viewBoxSize.x * _gaugeDefinition.currentValueBorderWidth; - const borderHeight = this.currentValueBorderHeight * 1.2; - const borderPosX = textPosX - (borderWidth * 0.95); - const borderPosY = textPosY - (borderHeight * 0.55); - this.currentValueBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.currentValueBorder.id = "CurrentValueBorder"; - this.currentValueBorder.setAttribute("x", borderPosX.toString()); - this.currentValueBorder.setAttribute("y", borderPosY.toString()); - this.currentValueBorder.setAttribute("width", borderWidth.toString()); - this.currentValueBorder.setAttribute("height", borderHeight.toString()); - this.rootSVG.appendChild(this.currentValueBorder); - } - if (this.extraMessageFunction != null) { - const extraMessageGroup = document.createElementNS(Avionics.SVG.NS, "g"); - extraMessageGroup.id = "ExtraMessage"; - this.extraMessageBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageBorder.setAttribute("class", "inactive"); - extraMessageGroup.appendChild(this.extraMessageBorder); - this.extraMessageText = document.createElementNS(Avionics.SVG.NS, "text"); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageText.setAttribute("class", "active"); - extraMessageGroup.appendChild(this.extraMessageText); - this.rootSVG.appendChild(extraMessageGroup); - } - this.refreshMainValue(this.minValue, true); - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(0, true); - } - if (this.outerDynamicArcFunction != null) { - this.refreshOuterDynamicArc(0, 0); - } - this.refreshActiveState(); - } - - //accepts two more parameters to set custom ID for dynamic markers - addGraduation(_value, _showInnerMarker, _text = "", _showOuterMarker = false, _setid = false, _idName = "", _markerColour = "") { - const dir = this.valueToDir(_value + this.cursorOffset); - if (_showInnerMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationInnerLineEndOffset), this.center.y + (dir.y * this.graduationInnerLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - if (_setid) { - marker.setAttribute("id",_idName); - } - if (_markerColour != "") { - marker.setAttribute("class", "InnerMarker" + " " + _markerColour); - } else { - marker.setAttribute("class", "InnerMarker"); - } - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_showOuterMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - this.outerMarkerValue = _value; - marker.setAttribute("id", _idName); - marker.setAttribute("class", "OuterMarker"); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_text.length > 0) { - const pos = new Vec2(this.center.x + (dir.x * this.graduationTextOffset), this.center.y + (dir.y * this.graduationTextOffset)); - const text = document.createElementNS(Avionics.SVG.NS, "text"); - text.textContent = _text; - text.setAttribute("x", pos.x.toString()); - text.setAttribute("y", pos.y.toString()); - text.setAttribute("alignment-baseline", "central"); - this.graduationsGroup.appendChild(text); - } - } - refreshActiveState() { - const style = this.isActive ? "active" : "inactive"; - if (this.mainArc != null) { - this.mainArc.setAttribute("class", style); - } - if (this.redArc != null) { - this.redArc.setAttribute("class", style); - } - if (this.graduationsGroup != null) { - this.graduationsGroup.setAttribute("class", style); - } - if (this.cursor != null) { - this.cursor.setAttribute("class", style); - } - if (this.outerIndicatorObject != null) { - this.outerIndicatorObject.setAttribute("class", style); - } - if (this.outerDynamicArcObject != null) { - this.outerDynamicArcObject.setAttribute("class", style); - } - if (this.currentValueText != null) { - this.currentValueText.setAttribute("class", style); - if (this.uppercam) { - this.currentValueBorder.setAttribute('class', style); - } - if (!this.isActive) { - this.currentValueText.textContent = "XX"; - this.currentValueTextdecimal.textContent = ""; - this.currentValueTextdecimalP.textContent = ""; - } - } - } - update(_deltaTime) { - if (this.isActive) { - if (this.currentValueFunction != null) { - this.refreshMainValue(this.currentValueFunction()); - } - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(this.outerIndicatorFunction()); - } - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcFunction(this.outerDynamicArcTargetValues); - this.refreshOuterDynamicArc(this.outerDynamicArcTargetValues[0], this.outerDynamicArcTargetValues[1]); - } - if (this.outerDynamicMarkerFunction != null) { - this.refreshOuterMarkerFunction(this.outerDynamicMarkerFunction()); - } - if (this.dangerMinDynamicFunction != null) { - this.refreshDangerMinFunction(this.dangerMinDynamicFunction()); - } - if (this.previousUpdateMinRedValue != this.minRedValue) { - this.refreshRedArc(); - } - } - if ((this.extraMessageFunction != null) && (this.extraMessageText != null) && (this.extraMessageBorder != null)) { - const extraMessage = this.isActive ? this.extraMessageFunction().toString() : ""; - const extraMessageStyle = this.extraMessageStyleFunction().toString(); - - let style = ""; - - if (extraMessage != this.extraMessageString || extraMessageStyle != this.extraMessageStyle) { - if (this.extraMessageFunction().toString() == "AVAIL") { - this.extraMessagePosXMultiplier = 0.198; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.345; - this.extraMessageBorderPosYMultiplier = 0.125; - this.extraMessageBorderWidthMultiplier = 0.68; - this.extraMessageBorderHeightMultiplier = 0.25; - style = "avail "; - } else { - this.extraMessagePosXMultiplier = 0.05; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - } - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageString = extraMessage; - this.extraMessageStyle = extraMessageStyle; - style += (this.extraMessageString.length > 0) ? "active" : "inactive"; - style += extraMessageStyle; - this.extraMessageBorder.setAttribute("class", style); - this.extraMessageText.setAttribute("class", style); - this.extraMessageText.textContent = this.extraMessageString; - } - } - } - refreshRedArc() { - if (this.redArc) { - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.previousUpdateMinRedValue = this.minRedValue; - } - } - calculateRedArcD() { - const minRedDir = this.valueToDir(this.minRedValue + this.cursorOffset); - const maxRedDir = this.valueToDir(this.maxRedValue + this.cursorOffset); - const topRight = new Vec2(this.center.x + (maxRedDir.x * this.mainArcRadius), this.center.y + (maxRedDir.y * this.mainArcRadius)); - const topLeft = new Vec2(this.center.x + (minRedDir.x * this.mainArcRadius), this.center.y + (minRedDir.y * this.mainArcRadius)); - const bottomRight = new Vec2(this.center.x + (maxRedDir.x * this.redArcInnerRadius), this.center.y + (maxRedDir.y * this.redArcInnerRadius)); - const bottomLeft = new Vec2(this.center.x + (minRedDir.x * this.redArcInnerRadius), this.center.y + (minRedDir.y * this.redArcInnerRadius)); - return [ - "M", topRight.x, topRight.y, - "A", this.mainArcRadius, this.mainArcRadius, 0, "0", 0, topLeft.x, topLeft.y, - "L", bottomLeft.x, bottomLeft.y, - "M", topRight.x, topRight.y, - "L", bottomRight.x, bottomRight.y, - "A", this.redArcInnerRadius, this.redArcInnerRadius, 0, "0", 0, bottomLeft.x, bottomLeft.y - ].join(" "); - } - //accepts ID_EGT, _value[0] = _id, _value[1] = EGT - refreshOuterMarkerFunction(_value, _force = false) { - if (_value[1] != this.outerMarkerValue) { - this.outerMarkerValue = _value[1]; - const marker = document.getElementById(_value[0]); - marker.style.display = hasThermodynamicTemperatureValue(this.outerMarkerValue) ? "block" : "none"; - - if (marker.style.display === "block") { - const dir = this.valueToDir(_value[1]); - const start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - const end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - } - } - } - refreshDangerMinFunction(_value, _force = false) { - if (_value != this.dangerRange[0]) { - this.dangerRange[0] = _value; - } - } - refreshMainValue(_value, _force = false) { - this.currentValue = _value; - this.currentValueCursor = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - const clampedValue = Utils.Clamp(this.currentValue, this.minValue, this.maxValue); - const clampedValueCursor = Utils.Clamp(this.currentValueCursor, this.minValue, this.maxValue); - let style = ""; - if ((this.dangerRange[0] != this.dangerRange[1]) && (clampedValue >= this.dangerRange[0]) && (clampedValue <= this.dangerRange[1])) { - style = "danger"; - } else if ((this.warningRange[0] != this.warningRange[1]) && (clampedValue >= this.warningRange[0]) && (clampedValue <= this.warningRange[1])) { - style = "warning"; - } else { - style = "active"; - } - if (this.cursor != null) { - const angle = this.valueToAngle(clampedValueCursor, false); - this.cursor.setAttribute("transform", "rotate(" + angle + ")"); - this.cursor.setAttribute("class", style); - } - if (this.currentValueText != null) { - let displayValue = this.currentValue; - if (this.roundDisplayValueToNearest) { - displayValue = Math.round(displayValue / this.roundDisplayValueToNearest) * this.roundDisplayValueToNearest; - } - const strValue = displayValue.toFixed(this.currentValuePrecision); - this.currentValueText.textContent = strValue; - this.currentValueText.setAttribute("class", style); - if (this.currentValuePrecision > 0) { - const strValueArray = strValue.split("."); - this.currentValueText.textContent = strValueArray[0]; - this.currentValueTextdecimal.textContent = strValueArray[1]; - this.currentValueTextdecimal.setAttribute("class", style + " decimal"); - this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("class", style + " decimalpoint"); - } - } - } - refreshOuterIndicator(_value, _force = false) { - if ((_value != this.outerIndicatorValue) || _force) { - this.outerIndicatorValue = _value; - if (this.outerIndicatorObject != null) { - const valueThrottlePosition = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - //const valueThrottlePosition = _value + this.cursorOffset; - const clampedValueThrottlePosition = Utils.Clamp(valueThrottlePosition , this.minValue, this.maxValue); - const angle = this.valueToAngle(clampedValueThrottlePosition, false); - this.outerIndicatorObject.setAttribute("transform", "rotate(" + angle + ")"); - } - } - } - refreshOuterDynamicArc(_start, _end, _force = false) { - if ((_start != this.outerDynamicArcCurrentValues[0]) || (_end != this.outerDynamicArcCurrentValues[1]) || _force) { - this.outerDynamicArcCurrentValues[0] = Utils.Clamp(_start, this.minValue, this.maxValue); - this.outerDynamicArcCurrentValues[1] = Utils.Clamp(_end, this.minValue, this.maxValue); - let d = ""; - if (this.outerDynamicArcCurrentValues[0] != this.outerDynamicArcCurrentValues[1]) { - const startAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[0], true); - const startX = this.center.x + (Math.cos(startAngle) * this.outerDynamicArcRadius); - const startY = this.center.y + (Math.sin(startAngle) * this.outerDynamicArcRadius); - const endAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[1], true); - const endX = this.center.x + (Math.cos(endAngle) * this.outerDynamicArcRadius); - const endY = this.center.y + (Math.sin(endAngle) * this.outerDynamicArcRadius); - const largeArcFlag = ((endAngle - startAngle) <= Math.PI) ? "0 0 0" : "0 1 0"; - d = [ - "M", endX, endY, - "A", this.outerDynamicArcRadius, this.outerDynamicArcRadius, largeArcFlag, startX, startY - ].join(" "); - } - this.outerDynamicArcObject.setAttribute("d", d); - } - } - } - A320_Neo_ECAM_Common.Gauge = Gauge; -})(A320_Neo_ECAM_Common || (A320_Neo_ECAM_Common = {})); -customElements.define('a320-neo-ecam-gauge', A320_Neo_ECAM_Common.Gauge); diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.css b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.css deleted file mode 100644 index 2b266424..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.css +++ /dev/null @@ -1,68 +0,0 @@ -@import url("/CSS/A319HS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; -} -#Electricity[state="off"] { - display: none; -} - -eicas-common-display { - display: block; - position: absolute; - bottom: 0%; - left: 0%; - width: 100%; - height: 25%; -} -eicas-common-display line { - stroke: var(--displayWhite) !important; - stroke-width: 3; -} -eicas-common-display text { - font-size: 20px; - font-family: "ECAMFontRegular"; -} -eicas-common-display text.Cyan { - fill: var(--displayCyan) !important; -} -eicas-common-display text.White { - fill: var(--displayWhite) !important; -} -eicas-common-display text.Value { - fill: var(--displayGreen) !important; -} -eicas-common-display text.Unit { - font-size: 15px !important; - fill: var(--displayCyan) !important; -} -eicas-common-display text.Warning { - fill: var(--displayAmber) !important; -} -eicas-common-display text.Small { - font-size: 18px !important; -} diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.html b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.html deleted file mode 100644 index 01e6cedc..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - diff --git a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.js b/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.js deleted file mode 100644 index e8c6916a..00000000 --- a/hsim-a319ceo/src/base/lvfr-horizonsim-airbus-a319-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a319-ceo/EICAS/EICAS_Common.js +++ /dev/null @@ -1,191 +0,0 @@ -class EICASCommonDisplay extends Airliners.EICASTemplateElement { - constructor() { - super(); - this.isInitialised = false; - } - get templateID() { - return "EICASCommonDisplayTemplate"; - } - connectedCallback() { - super.connectedCallback(); - TemplateElement.call(this, this.init.bind(this)); - } - init() { - this.tatText = this.querySelector("#TATValue"); - this.satText = this.querySelector("#SATValue"); - this.isaText = this.querySelector("#ISAValue"); - this.isaContainer = this.querySelector("#ISA"); - this.areAdirsAligned = null; - this.isSATVisible = null; - this.isTATVisible = null; - this.isISAVisible = null; - this.currentSeconds = 0; - this.currentMinutes = 0; - this.hoursText = this.querySelector("#HoursValue"); - this.minutesText = this.querySelector("#MinutesValue"); - this.loadFactorContainer = this.querySelector("#LoadFactor"); - this.loadFactorText = this.querySelector("#LoadFactorValue"); - this.loadFactorSet = new NXLogic_ConfirmNode(2); - this.loadFactorReset = new NXLogic_ConfirmNode(5); - this.loadFactorVisible = new NXLogic_MemoryNode(true); - this.gwUnit = this.querySelector("#GWUnit"); - this.gwValue = this.querySelector("#GWValue"); - this.refreshTAT(Arinc429Word.empty()); - this.refreshSAT(Arinc429Word.empty()); - this.refreshISA(Arinc429Word.empty()); - this.refreshClock(); - this.refreshGrossWeight(true); - this.isInitialised = true; - } - update(_deltaTime) { - if (!this.isInitialised) { - return; - } - - const airDataReferenceSource = this.getStatusAirDataReferenceSource(); - const inertialReferenceSource = this.getStatusInertialReferenceSource(); - const sat = Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_STATIC_AIR_TEMPERATURE`); - /* this.refreshTAT(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_TOTAL_AIR_TEMPERATURE`)); - this.refreshSAT(sat); - this.refreshISA(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_INTERNATIONAL_STANDARD_ATMOSPHERE_DELTA`), sat); */ - - this.refreshClock(); - this.refreshLoadFactor(_deltaTime, Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_IR_${inertialReferenceSource}_BODY_NORMAL_ACC`)); - this.refreshGrossWeight(); - this.refreshHomeCockpitMode(); - } - - getStatusAirDataReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_AIR_DATA_SWITCHING_KNOB', 'Enum')); - } - - getStatusInertialReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_ATT_HDG_SWITCHING_KNOB', 'Enum')); - } - - getStatusSupplier(knobValue) { - const adirs3ToCaptain = 0; - return knobValue === adirs3ToCaptain ? 3 : 1; - } - - refreshTAT(tat) { - if (!tat.isNormalOperation()) { - this.tatText.textContent = "XX"; - this.toggleWarning(true, this.tatText); - } else { - this.setValueOnTemperatureElement(Math.round(tat.value), this.tatText); - this.toggleWarning(false, this.tatText); - } - } - - refreshSAT(sat) { - if (!sat.isNormalOperation()) { - this.satText.textContent = "XX"; - this.toggleWarning(true, this.satText); - } else { - this.setValueOnTemperatureElement(Math.round(sat.value), this.satText); - this.toggleWarning(false, this.satText); - } - } - - refreshISA(isa, sat) { - const isInStdMode = Simplane.getPressureSelectedMode(Aircraft.A320_NEO) === "STD"; - // As ISA relates to SAT, we cannot present ISA when SAT is unavailable. We might want to move this into - // Rust ADIRS code itself. - const isaShouldBeVisible = isInStdMode && isa.isNormalOperation() && sat.isNormalOperation(); - this.isaContainer.setAttribute("visibility", isaShouldBeVisible ? "visible" : "hidden"); - - this.setValueOnTemperatureElement(Math.round(isa.value), this.isaText); - } - - setValueOnTemperatureElement(value, element) { - if (value > 0) { - element.textContent = "+" + value.toString().padStart(2); - } else { - element.textContent = (value < 0 ? "-" : "") + Math.abs(value).toString().padStart(2); - } - } - - toggleWarning(isWarning, element) { - element.classList.toggle("Warning", isWarning); - element.classList.toggle("Value", !isWarning); - } - - refreshLoadFactor(_deltaTime, n_z) { - const value = n_z.value; - const conditionsMet = value > 1.4 || value < 0.7; - const loadFactorSet = this.loadFactorSet.write(conditionsMet && n_z.isNormalOperation(), _deltaTime); - const loadFactorReset = this.loadFactorReset.write(!conditionsMet || !n_z.isNormalOperation(), _deltaTime); - const flightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - const isVisible = ( - flightPhase >= 4 && - flightPhase <= 8 && - this.loadFactorVisible.write(loadFactorSet, loadFactorReset) - ); - - if (this.loadFactorContainer) { - if (!isVisible) { - this.loadFactorContainer.setAttribute("visibility", "hidden"); - if (this.loadFactorText) { - this.loadFactorText.textContent = ""; - } - return; - } - this.loadFactorContainer.setAttribute("visibility", "visible"); - } - - if (this.loadFactorText) { - if (n_z.isNormalOperation()) { - const clamped = Math.min(Math.max(value, -3), 5); - this.loadFactorText.textContent = (clamped >= 0 ? "+" : "") + clamped.toFixed(1); - } else { - this.loadFactorText.textContent = 'XX'; - } - - } - } - refreshClock() { - const seconds = Math.floor(SimVar.GetGlobalVarValue("ZULU TIME", "seconds")); - if (seconds != this.currentSeconds) { - this.currentSeconds = seconds; - const hours = Math.floor(seconds / 3600); - const minutes = Math.floor((seconds - (hours * 3600)) / 60); - if (minutes != this.currentMinutes) { - this.currentMinutes = minutes; - if (this.hoursText != null) { - this.hoursText.textContent = hours.toString().padStart(2, "0"); - } - if (this.minutesText != null) { - this.minutesText.textContent = minutes.toString().padStart(2, "0"); - } - } - } - } - refreshGrossWeight(_force = false) { - const isOneEngineRunning = SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:1", "Number") >= 15 || SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:2", "Number") >= 15; //BASED ON IRL REFERENCE - const gw = Math.round(NXUnits.kgToUser(SimVar.GetSimVarValue("L:A32NX_FM_GROSS_WEIGHT", "number") * 1000)); - const gwUnit = NXUnits.userWeightUnit(); - if ((gw != this.currentGW) || (this.isOneEngineRunning != isOneEngineRunning) || _force) { - this.currentGW = gw; - this.isOneEngineRunning = isOneEngineRunning; - - if (isOneEngineRunning && this.currentGW != 0) { - // Lower EICAS displays GW in increments of 100 - this.gwValue.classList.add("Value"); - this.gwValue.classList.remove("Cyan"); - this.gwValue.textContent = (Math.floor(this.currentGW / 100) * 100).toString(); - } else { - this.gwValue.classList.remove("Value"); - this.gwValue.classList.add("Cyan"); - this.gwValue.textContent = "--"; - } - } - if (gwUnit != this.currentGwUnit) { - this.currentGwUnit = gwUnit; - if (this.gwUnit != null) { - this.gwUnit.textContent = gwUnit; - } - } - } -} -customElements.define("eicas-common-display", EICASCommonDisplay); diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.css b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.css deleted file mode 100644 index da0cf1cb..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.css +++ /dev/null @@ -1,256 +0,0 @@ -@import url("/CSS/A320HS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); -} -#Electricity[state="off"] { - display: none; -} - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); - height: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #RedArc { - fill: none; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 3; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder { - fill: none; - stroke: var(--displayGrey); - stroke-width: 3px; -} - -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: black; - stroke: var(--displayGrey); - stroke-width: 3px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none; -} - -a320-neo-eicas-element { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; -} -a320-neo-eicas-element #highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -a320-neo-eicas-element #Mainframe { - top: 0; - left: 0; - width: 100%; - height: 100%; - display: block; - position: relative; -} -a320-neo-eicas-element #Mainframe #TopScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); - transform: rotateX(0); - top: 0%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} -a320-neo-eicas-element #Mainframe #BottomScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 5, 1) 0%, - rgba(4, 4, 5, 1) 100% - ); - transform: rotateX(0); - top: 5%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} - -a320-neo-eicas-element[index="1"] #Mainframe #TopScreen { - display: block; -} -a320-neo-eicas-element[index="2"] #Mainframe #BottomScreen { - display: block; -} -.blue-text { - color: var(--displayCyan); -} -.SelfTestWrapper { - position: absolute; - left: 0%; - top: 0%; - width: 100%; - height: 100%; - border: none; - visibility: hidden; -} -#BottomScreen #door-video-wrapper { - position: absolute; - top: -5%; - width: 100%; - height: 82%; - z-index: 100; - visibility: hidden; - background-image: url(DoorVideoResources/empty.png); - background-size: cover; -} diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.html b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.html deleted file mode 100644 index 6b33d393..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.js b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.js deleted file mode 100644 index 7555c287..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS.js +++ /dev/null @@ -1,315 +0,0 @@ -class A320_Neo_EICAS extends Airliners.BaseEICAS { - get templateID() { - return "A320_Neo_EICAS"; - } - - // This js file has 2 intances at runtime, 1 upper screen and 1 lower - get isTopScreen() { - return this.urlConfig.index === 1; - } - - get isBottomScreen() { - return this.urlConfig.index === 2; - } - - // The following two functions can be called from anywhere on the EICAS - static isOnTopScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isTopScreen; - } - - static isOnBottomScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isBottomScreen; - } - - changePage(_pageName) { - let pageName = _pageName.toUpperCase(); - const isOnGround = SimVar.GetSimVarValue("GEAR IS ON GROUND","Bool"); - for (let i = 0; i < this.lowerScreenPages.length; i++) { - //skip CRZ and go back to ENG Page - if (this.lowerScreenPages[i].name == "CRZ" && isOnGround) { - pageName = "ENG"; - //The index of the ENG page is 0 so loop counter will point to correct index without triggering a new iteration. - i = 0; - } - if (this.lowerScreenPages[i].name == pageName) { - let pageIndex = i; - if (pageIndex == this.currentPage) { - pageName = this.pageNameWhenUnselected; - pageIndex = -1; - } - - this.currentPage = pageIndex; - break; - } - } - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, pageName); - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", this.currentPage); - } - - createLowerScreenPages() { - this.addIndependentElementContainer(new Airliners.EICASScreen("BottomScreenCommon", "BottomScreen", "eicas-common-display")); - this.createLowerScreenPage("ENG", "BottomScreen", "a32nx-eng-page-element"); - this.createLowerScreenPage("BLEED", "BottomScreen", "a32nx-bleed-page-element"); - this.createLowerScreenPage("PRESS", "BottomScreen", "a32nx-press-page-element"); - this.createLowerScreenPage("ELEC", "BottomScreen", "a32nx-elec-page-element"); - this.createLowerScreenPage("HYD", "BottomScreen", "a32nx-hyd-page-element"); - this.createLowerScreenPage("FUEL", "BottomScreen", "a32nx-fuel-page-element"); - this.createLowerScreenPage("APU", "BottomScreen", "a32nx-apu-page-element"); - this.createLowerScreenPage("COND", "BottomScreen", "a32nx-cond-page-element"); - this.createLowerScreenPage("DOOR", "BottomScreen", "a32nx-door-page-element"); - this.createLowerScreenPage("WHEEL", "BottomScreen", "a32nx-wheel-page-element"); - this.createLowerScreenPage("FTCL", "BottomScreen", "a32nx-fctl-page-element"); - this.createLowerScreenPage("STS", "BottomScreen", "a32nx-status-page-element"); - this.createLowerScreenPage("CRZ", "BottomScreen", "a32nx-crz-page-element"); - } - - getLowerScreenChangeEventNamePrefix() { - return "ECAM_CHANGE_PAGE_"; - } - - Init() { - super.Init(); - this.getDeltaTime = A32NX_Util.createDeltaTimeCalculator(this._lastTime); - this.currentPage = -1; - this.ecamAllButtonTimer = 1000; - this.ecamAllButtonTimerStarted = false; - - this.pageNameWhenUnselected = "DOOR"; - - this.ecamFCTLTimer = -1; - - this.changePage("FUEL"); // MODIFIED - - this.lastAPUMasterState = 0; // MODIFIED - this.ApuAboveThresholdTimer = -1; // MODIFIED - this.MainEngineStarterOffTimer = -1; - this.CrzCondTimer = 60; - this.PrevFailPage = -1; - - this.doorVideoWrapper = this.querySelector("#door-video-wrapper"); - - this.lowerEngTestDiv = this.querySelector("#Eicas2EngTest"); - this.lowerEngMaintDiv = this.querySelector("#Eicas2MaintMode"); - - this.doorVideoPressed = false; - this.doorVideoEnabled = false; - - // Using ternary in case the LVar is undefined - this.poweredDuringPreviousUpdate = SimVar.GetSimVarValue("L:A32NX_COLD_AND_DARK_SPAWN", "Bool") ? 0 : 1; - - this.changePage("DOOR"); // MODIFIED - this.changePage("DOOR"); // This should get the ECAM into the "unselected" state - - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:7", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:84", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:85", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:86", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:87", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:88", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:89", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:90", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:91", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:92", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:93", "number", 0.1); - - this.ecamAllButtonPrevState = false; - this.updateThrottler = new UpdateThrottler(500); - - this.displayUnit = new DisplayUnit( - this.querySelector("#Electricity"), - () => { - return SimVar.GetSimVarValue("L:A32NX_ELEC_AC_2_BUS_IS_POWERED", "Bool"); - }, - () => parseInt(NXDataStore.get("CONFIG_SELF_TEST_TIME", "15")), - 93, - this.querySelector("#BottomSelfTest") - ); - } - - onUpdate() { - let deltaTime = this.getDeltaTime(); - super.onUpdate(deltaTime); - - const ecamAllButtonBeingPushed = SimVar.GetSimVarValue("L:A32NX_ECAM_ALL_Push_IsDown", "Bool"); - - deltaTime = this.updateThrottler.canUpdate(deltaTime, this.displayUnit.isJustNowTurnedOn() || ecamAllButtonBeingPushed); - if (deltaTime === -1) { - return; - } - - this.displayUnit.update(deltaTime); - - this.updateDoorVideoState(); - - // Engineering self-tests - updateDisplayDMC("EICAS2", this.lowerEngTestDiv, this.lowerEngMaintDiv); - - //Determine displayed page when no button is selected - const prevPage = this.pageNameWhenUnselected; - - const fwcFlightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - - switch (fwcFlightPhase) { - case 10: - case 1: - this.CrzCondTimer = 60; - this.pageNameWhenUnselected = "DOOR"; - //TODO: Emergency Generator Test displays ELEC - //Needs system implementation (see A320_NEO_INTERIOR Component ID EMER_ELEC_PWR [LVar: L:A32NX_EMERELECPWR_GEN_TEST]) - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 2: - const sidestickPosX = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_X", "Number"); - const sidestickPosY = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_Y", "Number"); - const rudderPos = SimVar.GetSimVarValue("RUDDER PEDAL POSITION", "Position"); - const controlsMoved = Math.abs(sidestickPosX) > 0.05 || Math.abs(sidestickPosY) > 0.05 || Math.abs(rudderPos) > 0.2; - - this.pageNameWhenUnselected = "WHEEL"; - // When controls are moved > threshold, show FCTL page for 20s - if (controlsMoved) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer = 20; - } else if (this.ecamFCTLTimer >= 0) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer -= deltaTime / 1000; - } - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 3: - case 4: - case 5: - this.pageNameWhenUnselected = "ENG"; - break; - case 6: - case 7: - case 8: - case 9: - const isGearExtended = SimVar.GetSimVarValue("GEAR TOTAL PCT EXTENDED", "percent") > 0.95; - const ToPowerSet = Math.max(SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:1", "number"), SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:2", "number")) >= 35 && SimVar.GetSimVarValue("ENG N1 RPM:1", "Percent") > 15 && SimVar.GetSimVarValue("ENG N1 RPM:2", "Percent") > 15; - const spoilerOrFlapsDeployed = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "number") !== 0 || SimVar.GetSimVarValue("L:A32NX_SPOILERS_HANDLE_POSITION", "percent") !== 0; - - if (isGearExtended && (Simplane.getAltitude() < 16000)) { - this.pageNameWhenUnselected = "WHEEL"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - // Else check for CRZ - } - - if ((spoilerOrFlapsDeployed || ToPowerSet)) { - if (this.CrzCondTimer <= 0) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } else { - this.CrzCondTimer -= deltaTime / 1000; - } - } else if (!spoilerOrFlapsDeployed && !ToPowerSet) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } - break; - default: - // Sometimes happens when loading in, in which case we have to initialise pageNameWhenUnselected here. - this.pageNameWhenUnselected = "DOOR"; - break; - } - - const sFailPage = SimVar.GetSimVarValue("L:A32NX_ECAM_SFAIL", "Enum"); - - if (sFailPage != -1) { - this.pageNameWhenUnselected = this.lowerScreenPages[sFailPage].name; - - // Disable user selected page when new failure detected - if (this.PrevFailPage !== sFailPage) { - this.currentPage = -1; - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", -1); - } - } - - // switch page when desired page was changed, or new Failure detected - if ((this.pageNameWhenUnselected != prevPage && this.currentPage == -1) || (this.PrevFailPage !== sFailPage)) { - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, this.pageNameWhenUnselected); - } - - if (ecamAllButtonBeingPushed && !this.ecamAllButtonPrevState) { // button press - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - this.ecamCycleInterval = setInterval(() => { - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - }, 1000); - } else if (!ecamAllButtonBeingPushed && this.ecamAllButtonPrevState) { // button release - clearInterval(this.ecamCycleInterval); - } - - this.ecamAllButtonPrevState = ecamAllButtonBeingPushed; - this.PrevFailPage = sFailPage; - } - - checkEnginePage(deltaTime) { - const engModeSel = SimVar.GetSimVarValue("L:XMLVAR_ENG_MODE_SEL", "number"); - const eng1State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:1", "number"); - const eng2State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:2", "number"); - const oneEngOff = eng1State !== 1 || eng2State !== 1; - - if (engModeSel === 0 || (oneEngOff && engModeSel === 2) || this.MainEngineStarterOffTimer >= 0) { - // Show ENG until >10 seconds after both engines are fully started - if (engModeSel === 0 || (oneEngOff && engModeSel === 2)) { - this.MainEngineStarterOffTimer = 10; - } else if (this.MainEngineStarterOffTimer >= 0) { - this.MainEngineStarterOffTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "ENG"; - } - } - - checkApuPage(deltaTime) { - const currentAPUMasterState = SimVar.GetSimVarValue("L:A32NX_OVHD_APU_MASTER_SW_PB_IS_ON", "Bool"); - const apuRpm = Arinc429Word.fromSimVarValue("L:A32NX_APU_N"); - if (currentAPUMasterState && apuRpm.isNormalOperation() && (apuRpm.value <= 95 || this.ApuAboveThresholdTimer >= 0)) { - // Show APU on Lower ECAM until 15s after RPM > 95% - if (this.ApuAboveThresholdTimer <= 0 && apuRpm.value <= 95) { - this.ApuAboveThresholdTimer = 15; - } else if (apuRpm.value > 95) { - this.ApuAboveThresholdTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "APU"; - } - } - - updateDoorVideoState() { - const doorVideoEnabledNow = SimVar.GetSimVarValue("L:A32NX_OVHD_COCKPITDOORVIDEO_TOGGLE", "Bool") === 1; - const doorVideoPressedNow = SimVar.GetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool") === 1; - - if (this.doorVideoEnabled !== doorVideoEnabledNow || this.doorVideoPressed !== doorVideoPressedNow) { - this.doorVideoEnabled = doorVideoEnabledNow; - this.doorVideoPressed = doorVideoPressedNow; - - this.setDoorVideo(); - } - } - - setDoorVideo() { - this.doorVideoWrapper.style.visibility = this.doorVideoEnabled && this.doorVideoPressed ? "visible" : "hidden"; - } - - SwitchToPageName(_menu, _page) { - if (this.doorVideoPressed) { - SimVar.SetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool", 0); - } - - super.SwitchToPageName(_menu, _page); - } -} - -registerInstrument("a320-neo-eicas-element", A320_Neo_EICAS); diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_CFM_SL.html b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_CFM_SL.html deleted file mode 100644 index 4df30252..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_CFM_SL.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE.html b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE.html deleted file mode 100644 index cf0fbb33..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE_SL.html b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE_SL.html deleted file mode 100644 index 131b8209..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/A320_Neo_EICAS_IAE_SL.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/DoorVideoResources/empty.png b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/DoorVideoResources/empty.png deleted file mode 100644 index f35008acb166bc2754c26028bd43a83cb0e95e0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48821 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 LeYFM^+nE0kG0W-* diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css deleted file mode 100644 index 79103369..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.css +++ /dev/null @@ -1,172 +0,0 @@ -@import url("/CSS/A320HS_Display_Common.css"); - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: get-vh(640px); - height: get-vh(640px); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} - -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} - -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - fill: none; -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke-width: 1px !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .danger { - stroke-width: 1px !important; - stroke: var(--displayRed) !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .warning { - stroke-width: 1px !important; - stroke: var(--displayAmber) !important; -} -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - stroke-width: 2px; - fill: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); - stroke-width: 6px; -} -a320-neo-ecam-gauge #RootSVG #OuterIndicatorOffset { - stroke: var(--displayCyan) !important; - stroke-width: 1.5px !important; - fill: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 2; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 2px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; - font-size: 20px !important; - fill: var(--displayBackground); -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder, -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.active { - fill: none; - stroke: lightblue; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.inactive { - fill: none; - stroke: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.decimal { - font-size: 15px !important; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.gaugedecimalpoint { - fill: var(--displayGreen); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: var(--displayBackground); - stroke: lightblue; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text.amber { - fill: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .avail { - font-size: 19.2px !important; -} diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js deleted file mode 100644 index 7fbc8b5c..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/ECAM/A320_Neo_ECAMGauge.js +++ /dev/null @@ -1,549 +0,0 @@ -var A320_Neo_ECAM_Common; -(function (A320_Neo_ECAM_Common) { - const absoluteZeroThermodynamicTemperature = -273.15; - - function hasThermodynamicTemperatureValue(value) { - return value >= absoluteZeroThermodynamicTemperature; - } - - function isEngineDisplayActive(_index) { - return ((SimVar.GetSimVarValue("ENG N1 RPM:" + _index, "percent") >= 0.05) || (SimVar.GetSimVarValue("ENG N2 RPM:" + _index, "percent") >= 0.05)); - } - A320_Neo_ECAM_Common.isEngineDisplayActive = isEngineDisplayActive; - class GaugeDefinition { - constructor() { - this.startAngle = -225; - this.arcSize = 180; - this.cursorOffset = 0; - this.minValue = 0; - this.maxValue = 100; - this.minRedValue = 0; - this.maxRedValue = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.cursorLength = 1.0; - this.cursorMultiplier = 1.1; - this.currentValuePos = new Vec2(0.65, 0.65); - this.currentValueFunction = null; - this.currentValuePrecision = 0; - this.currentValueBorderWidth = 0; - this.outerIndicatorFunction = null; - this.outerDynamicArcFunction = null; - this.extraMessageFunction = null; - this.extraMessageStyleFunction = null; - this.outerDynamicMarkerFunction = null; - this.dangerMinDynamicFunction = null; - this.outerMarkerValue = null; - this.roundDisplayValueToNearest = null; - } - } - A320_Neo_ECAM_Common.GaugeDefinition = GaugeDefinition; - class Gauge extends HTMLElement { - constructor() { - super(...arguments); - this.viewBoxSize = new Vec2(100, 100); - this.startAngle = -225; - this.cursorOffset = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.outerDynamicArcCurrentValues = [0, 0]; - this.outerDynamicArcTargetValues = [0, 0]; - this.extraMessageString = ""; - this.extraMessageStyle = ""; - this.isActive = true; - this.extraMessagePosXMultiplier = 0; - this.extraMessagePosYMultiplier = 0; - this.extraMessageBorderPosXMultiplier = 0; - this.extraMessageBorderPosYMultiplier = 0; - this.extraMessageBorderWidthMultiplier = 0; - this.extraMessageBorderHeightMultiplier = 0; - this.cursorMultiplier = 1.1; - this.uppercam = false; - } - get mainArcRadius() { - return (this.viewBoxSize.x * 0.5 * 0.975); - } - get cursorArcRadius() { - return (this.mainArcRadius * this.cursorMultiplier); - } - get graduationInnerLineEndOffset() { - return (this.mainArcRadius * 0.9); - } - get graduationOuterLineEndOffset() { - return (this.mainArcRadius * 1.175); - } - get graduationTextOffset() { - return (this.mainArcRadius * 0.625); - } - get redArcInnerRadius() { - return (this.mainArcRadius * 1); - } - get outerIndicatorOffset() { - return (this.viewBoxSize.x * 0.03); - } - get outerIndicatorRadius() { - return (this.viewBoxSize.x * 0.03); - } - get outerDynamicArcRadius() { - return (this.mainArcRadius * 1.15); - } - get currentValueBorderHeight() { - return (this.viewBoxSize.y * 0.20); - } - get extraMessagePosX() { - return (this.center.x + (this.viewBoxSize.x * this.extraMessagePosXMultiplier)); - } - get extraMessagePosY() { - return (this.center.y - (this.viewBoxSize.y * this.extraMessagePosYMultiplier)); - } - get extraMessageBorderPosX() { - return (this.extraMessagePosX - (this.viewBoxSize.x * this.extraMessageBorderPosXMultiplier)); - } - get extraMessageBorderPosY() { - return (this.extraMessagePosY - (this.viewBoxSize.y * this.extraMessageBorderPosYMultiplier)); - } - get extraMessageBorderWidth() { - return (this.viewBoxSize.x * this.extraMessageBorderWidthMultiplier); - } - get extraMessageBorderHeight() { - return (this.viewBoxSize.y * this.extraMessageBorderHeightMultiplier); - } - set active(_isActive) { - if (this.isActive != _isActive) { - this.isActive = _isActive; - this.refreshActiveState(); - } - } - get active() { - return this.isActive; - } - polarToCartesian(_centerX, _centerY, _radius, _angleInDegrees) { - const angleInRadians = _angleInDegrees * (Math.PI / 180.0); - return new Vec2(_centerX + (_radius * Math.cos(angleInRadians)), _centerY + (_radius * Math.sin(angleInRadians))); - } - valueToAngle(_value, _radians) { - const valuePercentage = (_value - this.minValue) / (this.maxValue - this.minValue); - let angle = (this.startAngle + (valuePercentage * this.arcSize)); - if (_radians) { - angle *= (Math.PI / 180.0); - } - return angle; - } - valueToDir(_value) { - const angle = this.valueToAngle(_value, true); - return (new Vec2(Math.cos(angle), Math.sin(angle))); - } - init(_gaugeDefinition) { - this.cursorOffset = _gaugeDefinition.cursorOffset; - this.startAngle = _gaugeDefinition.startAngle; - this.arcSize = _gaugeDefinition.arcSize; - this.minValue = _gaugeDefinition.minValue; - this.maxValue = _gaugeDefinition.maxValue; - this.minRedValue = _gaugeDefinition.minRedValue; - this.previousUpdateMinRedValue = _gaugeDefinition.minRedValue; - this.maxRedValue = _gaugeDefinition.maxRedValue; - this.warningRange[0] = _gaugeDefinition.warningRange[0]; - this.warningRange[1] = _gaugeDefinition.warningRange[1]; - this.dangerRange[0] = _gaugeDefinition.dangerRange[0]; - this.dangerRange[1] = _gaugeDefinition.dangerRange[1]; - this.cursorMultiplier = _gaugeDefinition.cursorMultiplier; - this.currentValueFunction = _gaugeDefinition.currentValueFunction; - this.currentValuePrecision = _gaugeDefinition.currentValuePrecision; - this.outerIndicatorFunction = _gaugeDefinition.outerIndicatorFunction; - this.outerDynamicArcFunction = _gaugeDefinition.outerDynamicArcFunction; - this.extraMessageFunction = _gaugeDefinition.extraMessageFunction; - this.extraMessageStyleFunction = _gaugeDefinition.extraMessageStyleFunction; - this.roundDisplayValueToNearest = _gaugeDefinition.roundDisplayValueToNearest; - this.extraMessagePosXMultiplier = 0.025; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - this.outerDynamicMarkerFunction = _gaugeDefinition.outerDynamicMarkerFunction; - this.dangerMinDynamicFunction = _gaugeDefinition.dangerMinDynamicFunction; - this.uppercam = _gaugeDefinition.uppercam; - this.endAngle = this.startAngle + _gaugeDefinition.arcSize; - this.center = new Vec2(this.viewBoxSize.x * 0.5, this.viewBoxSize.y * 0.5); - this.rootSVG = document.createElementNS(Avionics.SVG.NS, "svg"); - this.rootSVG.id = "RootSVG"; - this.rootSVG.setAttribute("viewBox", "0 0 " + this.viewBoxSize.x + " " + this.viewBoxSize.y); - this.appendChild(this.rootSVG); - this.mainArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.mainArc.id = "MainArc"; - { - const startPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.endAngle); - const endPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.startAngle); - const largeArcFlag = ((this.endAngle - this.startAngle) <= 180) ? "0" : "1"; - var d = ["M", startPos.x, startPos.y, "A", this.mainArcRadius, this.mainArcRadius, 0, largeArcFlag, 0, endPos.x, endPos.y].join(" "); - this.mainArc.setAttribute("d", d); - } - this.rootSVG.appendChild(this.mainArc); - if (this.minRedValue != this.maxRedValue) { - this.redArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.redArc.id = "RedArc"; - - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.rootSVG.appendChild(this.redArc); - } - this.graduationsGroup = document.createElementNS(Avionics.SVG.NS, "g"); - this.graduationsGroup.id = "GraduationsGroup"; - this.rootSVG.appendChild(this.graduationsGroup); - const cursorGroup = document.createElementNS(Avionics.SVG.NS, "g"); - cursorGroup.id = "CursorGroup"; - this.cursor = document.createElementNS(Avionics.SVG.NS, "line"); - this.cursorArcRadiusChoice = this.cursorArcRadius; - if (this.outerDynamicArcFunction != null) { - this.cursorArcRadiusChoice = this.outerDynamicArcRadius; - } - this.cursor.setAttribute("x1", (this.cursorArcRadiusChoice * (1 - _gaugeDefinition.cursorLength)).toString()); - this.cursor.setAttribute("y1", "0"); - this.cursor.setAttribute("x2", this.cursorArcRadiusChoice.toString()); - this.cursor.setAttribute("y2", "0"); - cursorGroup.setAttribute("transform", "translate(" + this.center.x + ", " + this.center.y + ")"); - cursorGroup.appendChild(this.cursor); - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerDynamicArcObject.id = "OuterDynamicArcObject"; - this.rootSVG.appendChild(this.outerDynamicArcObject); - } - if (this.outerIndicatorFunction != null) { - this.outerIndicatorObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerIndicatorObject.id = "OuterIndicatorOffset"; - const radius = this.outerIndicatorRadius; - var d = [ - "M", (this.mainArcRadius + this.outerIndicatorOffset), "0", - "a", radius, radius, "0 1 0", (radius * 2), "0", - "a", radius, radius, "0 1 0", -(radius * 2), "0" - ].join(" "); - this.outerIndicatorObject.setAttribute("d", d); - cursorGroup.appendChild(this.outerIndicatorObject); - } - this.rootSVG.appendChild(cursorGroup); - const textPosX = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.x; - const textPosY = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.y; - const textPosXdec = (this.currentValuePrecision == 1) ? textPosX - 19 : textPosX; - const textPosYdec = (this.currentValuePrecision == 1) ? textPosY + 7 : textPosY; - this.currentValueText = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueText.id = "CurrentValue"; - this.currentValueText.setAttribute("x", textPosXdec.toString()); - this.currentValueText.setAttribute("y", textPosY.toString()); - this.currentValueText.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueText); - const textPosXdecimal = textPosX; - const textPosYdecimal = textPosYdec; - this.currentValueTextdecimal = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimal.id = "CurrentValue"; - this.currentValueTextdecimal.setAttribute("x", textPosXdecimal.toString()); - this.currentValueTextdecimal.setAttribute("y", textPosYdecimal.toString()); - this.currentValueTextdecimal.setAttribute("alignment-baseline", "text-bottom"); - this.rootSVG.appendChild(this.currentValueTextdecimal); - const textPosXdecP = textPosX - 9; - this.currentValueTextdecimalP = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimalP.id = "CurrentValue"; - this.currentValueTextdecimalP.setAttribute("x", textPosXdecP.toString()); - this.currentValueTextdecimalP.setAttribute("y", textPosY.toString()); - //this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueTextdecimalP); - if (_gaugeDefinition.currentValueBorderWidth > 0) { - const borderWidth = this.viewBoxSize.x * _gaugeDefinition.currentValueBorderWidth; - const borderHeight = this.currentValueBorderHeight * 1.2; - const borderPosX = textPosX - (borderWidth * 0.95); - const borderPosY = textPosY - (borderHeight * 0.55); - this.currentValueBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.currentValueBorder.id = "CurrentValueBorder"; - this.currentValueBorder.setAttribute("x", borderPosX.toString()); - this.currentValueBorder.setAttribute("y", borderPosY.toString()); - this.currentValueBorder.setAttribute("width", borderWidth.toString()); - this.currentValueBorder.setAttribute("height", borderHeight.toString()); - this.rootSVG.appendChild(this.currentValueBorder); - } - if (this.extraMessageFunction != null) { - const extraMessageGroup = document.createElementNS(Avionics.SVG.NS, "g"); - extraMessageGroup.id = "ExtraMessage"; - this.extraMessageBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageBorder.setAttribute("class", "inactive"); - extraMessageGroup.appendChild(this.extraMessageBorder); - this.extraMessageText = document.createElementNS(Avionics.SVG.NS, "text"); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageText.setAttribute("class", "active"); - extraMessageGroup.appendChild(this.extraMessageText); - this.rootSVG.appendChild(extraMessageGroup); - } - this.refreshMainValue(this.minValue, true); - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(0, true); - } - if (this.outerDynamicArcFunction != null) { - this.refreshOuterDynamicArc(0, 0); - } - this.refreshActiveState(); - } - - //accepts two more parameters to set custom ID for dynamic markers - addGraduation(_value, _showInnerMarker, _text = "", _showOuterMarker = false, _setid = false, _idName = "", _markerColour = "") { - const dir = this.valueToDir(_value + this.cursorOffset); - if (_showInnerMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationInnerLineEndOffset), this.center.y + (dir.y * this.graduationInnerLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - if (_setid) { - marker.setAttribute("id",_idName); - } - if (_markerColour != "") { - marker.setAttribute("class", "InnerMarker" + " " + _markerColour); - } else { - marker.setAttribute("class", "InnerMarker"); - } - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_showOuterMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - this.outerMarkerValue = _value; - marker.setAttribute("id", _idName); - marker.setAttribute("class", "OuterMarker"); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_text.length > 0) { - const pos = new Vec2(this.center.x + (dir.x * this.graduationTextOffset), this.center.y + (dir.y * this.graduationTextOffset)); - const text = document.createElementNS(Avionics.SVG.NS, "text"); - text.textContent = _text; - text.setAttribute("x", pos.x.toString()); - text.setAttribute("y", pos.y.toString()); - text.setAttribute("alignment-baseline", "central"); - this.graduationsGroup.appendChild(text); - } - } - refreshActiveState() { - const style = this.isActive ? "active" : "inactive"; - if (this.mainArc != null) { - this.mainArc.setAttribute("class", style); - } - if (this.redArc != null) { - this.redArc.setAttribute("class", style); - } - if (this.graduationsGroup != null) { - this.graduationsGroup.setAttribute("class", style); - } - if (this.cursor != null) { - this.cursor.setAttribute("class", style); - } - if (this.outerIndicatorObject != null) { - this.outerIndicatorObject.setAttribute("class", style); - } - if (this.outerDynamicArcObject != null) { - this.outerDynamicArcObject.setAttribute("class", style); - } - if (this.currentValueText != null) { - this.currentValueText.setAttribute("class", style); - if (this.uppercam) { - this.currentValueBorder.setAttribute('class', style); - } - if (!this.isActive) { - this.currentValueText.textContent = "XX"; - this.currentValueTextdecimal.textContent = ""; - this.currentValueTextdecimalP.textContent = ""; - } - } - } - update(_deltaTime) { - if (this.isActive) { - if (this.currentValueFunction != null) { - this.refreshMainValue(this.currentValueFunction()); - } - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(this.outerIndicatorFunction()); - } - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcFunction(this.outerDynamicArcTargetValues); - this.refreshOuterDynamicArc(this.outerDynamicArcTargetValues[0], this.outerDynamicArcTargetValues[1]); - } - if (this.outerDynamicMarkerFunction != null) { - this.refreshOuterMarkerFunction(this.outerDynamicMarkerFunction()); - } - if (this.dangerMinDynamicFunction != null) { - this.refreshDangerMinFunction(this.dangerMinDynamicFunction()); - } - if (this.previousUpdateMinRedValue != this.minRedValue) { - this.refreshRedArc(); - } - } - if ((this.extraMessageFunction != null) && (this.extraMessageText != null) && (this.extraMessageBorder != null)) { - const extraMessage = this.isActive ? this.extraMessageFunction().toString() : ""; - const extraMessageStyle = this.extraMessageStyleFunction().toString(); - - let style = ""; - - if (extraMessage != this.extraMessageString || extraMessageStyle != this.extraMessageStyle) { - if (this.extraMessageFunction().toString() == "AVAIL") { - this.extraMessagePosXMultiplier = 0.198; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.345; - this.extraMessageBorderPosYMultiplier = 0.125; - this.extraMessageBorderWidthMultiplier = 0.68; - this.extraMessageBorderHeightMultiplier = 0.25; - style = "avail "; - } else { - this.extraMessagePosXMultiplier = 0.05; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - } - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageString = extraMessage; - this.extraMessageStyle = extraMessageStyle; - style += (this.extraMessageString.length > 0) ? "active" : "inactive"; - style += extraMessageStyle; - this.extraMessageBorder.setAttribute("class", style); - this.extraMessageText.setAttribute("class", style); - this.extraMessageText.textContent = this.extraMessageString; - } - } - } - refreshRedArc() { - if (this.redArc) { - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.previousUpdateMinRedValue = this.minRedValue; - } - } - calculateRedArcD() { - const minRedDir = this.valueToDir(this.minRedValue + this.cursorOffset); - const maxRedDir = this.valueToDir(this.maxRedValue + this.cursorOffset); - const topRight = new Vec2(this.center.x + (maxRedDir.x * this.mainArcRadius), this.center.y + (maxRedDir.y * this.mainArcRadius)); - const topLeft = new Vec2(this.center.x + (minRedDir.x * this.mainArcRadius), this.center.y + (minRedDir.y * this.mainArcRadius)); - const bottomRight = new Vec2(this.center.x + (maxRedDir.x * this.redArcInnerRadius), this.center.y + (maxRedDir.y * this.redArcInnerRadius)); - const bottomLeft = new Vec2(this.center.x + (minRedDir.x * this.redArcInnerRadius), this.center.y + (minRedDir.y * this.redArcInnerRadius)); - return [ - "M", topRight.x, topRight.y, - "A", this.mainArcRadius, this.mainArcRadius, 0, "0", 0, topLeft.x, topLeft.y, - "L", bottomLeft.x, bottomLeft.y, - "M", topRight.x, topRight.y, - "L", bottomRight.x, bottomRight.y, - "A", this.redArcInnerRadius, this.redArcInnerRadius, 0, "0", 0, bottomLeft.x, bottomLeft.y - ].join(" "); - } - //accepts ID_EGT, _value[0] = _id, _value[1] = EGT - refreshOuterMarkerFunction(_value, _force = false) { - if (_value[1] != this.outerMarkerValue) { - this.outerMarkerValue = _value[1]; - const marker = document.getElementById(_value[0]); - marker.style.display = hasThermodynamicTemperatureValue(this.outerMarkerValue) ? "block" : "none"; - - if (marker.style.display === "block") { - const dir = this.valueToDir(_value[1]); - const start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - const end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - } - } - } - refreshDangerMinFunction(_value, _force = false) { - if (_value != this.dangerRange[0]) { - this.dangerRange[0] = _value; - } - } - refreshMainValue(_value, _force = false) { - this.currentValue = _value; - this.currentValueCursor = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - const clampedValue = Utils.Clamp(this.currentValue, this.minValue, this.maxValue); - const clampedValueCursor = Utils.Clamp(this.currentValueCursor, this.minValue, this.maxValue); - let style = ""; - if ((this.dangerRange[0] != this.dangerRange[1]) && (clampedValue >= this.dangerRange[0]) && (clampedValue <= this.dangerRange[1])) { - style = "danger"; - } else if ((this.warningRange[0] != this.warningRange[1]) && (clampedValue >= this.warningRange[0]) && (clampedValue <= this.warningRange[1])) { - style = "warning"; - } else { - style = "active"; - } - if (this.cursor != null) { - const angle = this.valueToAngle(clampedValueCursor, false); - this.cursor.setAttribute("transform", "rotate(" + angle + ")"); - this.cursor.setAttribute("class", style); - } - if (this.currentValueText != null) { - let displayValue = this.currentValue; - if (this.roundDisplayValueToNearest) { - displayValue = Math.round(displayValue / this.roundDisplayValueToNearest) * this.roundDisplayValueToNearest; - } - const strValue = displayValue.toFixed(this.currentValuePrecision); - this.currentValueText.textContent = strValue; - this.currentValueText.setAttribute("class", style); - if (this.currentValuePrecision > 0) { - const strValueArray = strValue.split("."); - this.currentValueText.textContent = strValueArray[0]; - this.currentValueTextdecimal.textContent = strValueArray[1]; - this.currentValueTextdecimal.setAttribute("class", style + " decimal"); - this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("class", style + " decimalpoint"); - } - } - } - refreshOuterIndicator(_value, _force = false) { - if ((_value != this.outerIndicatorValue) || _force) { - this.outerIndicatorValue = _value; - if (this.outerIndicatorObject != null) { - const valueThrottlePosition = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - //const valueThrottlePosition = _value + this.cursorOffset; - const clampedValueThrottlePosition = Utils.Clamp(valueThrottlePosition , this.minValue, this.maxValue); - const angle = this.valueToAngle(clampedValueThrottlePosition, false); - this.outerIndicatorObject.setAttribute("transform", "rotate(" + angle + ")"); - } - } - } - refreshOuterDynamicArc(_start, _end, _force = false) { - if ((_start != this.outerDynamicArcCurrentValues[0]) || (_end != this.outerDynamicArcCurrentValues[1]) || _force) { - this.outerDynamicArcCurrentValues[0] = Utils.Clamp(_start, this.minValue, this.maxValue); - this.outerDynamicArcCurrentValues[1] = Utils.Clamp(_end, this.minValue, this.maxValue); - let d = ""; - if (this.outerDynamicArcCurrentValues[0] != this.outerDynamicArcCurrentValues[1]) { - const startAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[0], true); - const startX = this.center.x + (Math.cos(startAngle) * this.outerDynamicArcRadius); - const startY = this.center.y + (Math.sin(startAngle) * this.outerDynamicArcRadius); - const endAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[1], true); - const endX = this.center.x + (Math.cos(endAngle) * this.outerDynamicArcRadius); - const endY = this.center.y + (Math.sin(endAngle) * this.outerDynamicArcRadius); - const largeArcFlag = ((endAngle - startAngle) <= Math.PI) ? "0 0 0" : "0 1 0"; - d = [ - "M", endX, endY, - "A", this.outerDynamicArcRadius, this.outerDynamicArcRadius, largeArcFlag, startX, startY - ].join(" "); - } - this.outerDynamicArcObject.setAttribute("d", d); - } - } - } - A320_Neo_ECAM_Common.Gauge = Gauge; -})(A320_Neo_ECAM_Common || (A320_Neo_ECAM_Common = {})); -customElements.define('a320-neo-ecam-gauge', A320_Neo_ECAM_Common.Gauge); diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.css b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.css deleted file mode 100644 index 4e08c315..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.css +++ /dev/null @@ -1,68 +0,0 @@ -@import url("/CSS/A320HS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; -} -#Electricity[state="off"] { - display: none; -} - -eicas-common-display { - display: block; - position: absolute; - bottom: 0%; - left: 0%; - width: 100%; - height: 25%; -} -eicas-common-display line { - stroke: var(--displayWhite) !important; - stroke-width: 3; -} -eicas-common-display text { - font-size: 20px; - font-family: "ECAMFontRegular"; -} -eicas-common-display text.Cyan { - fill: var(--displayCyan) !important; -} -eicas-common-display text.White { - fill: var(--displayWhite) !important; -} -eicas-common-display text.Value { - fill: var(--displayGreen) !important; -} -eicas-common-display text.Unit { - font-size: 15px !important; - fill: var(--displayCyan) !important; -} -eicas-common-display text.Warning { - fill: var(--displayAmber) !important; -} -eicas-common-display text.Small { - font-size: 18px !important; -} diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.html b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.html deleted file mode 100644 index 178cd620..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - diff --git a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.js b/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.js deleted file mode 100644 index e8c6916a..00000000 --- a/hsim-a320ceo/src/base/lvfr-horizonsim-airbus-a320-ceo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a320-ceo/EICAS/EICAS_Common.js +++ /dev/null @@ -1,191 +0,0 @@ -class EICASCommonDisplay extends Airliners.EICASTemplateElement { - constructor() { - super(); - this.isInitialised = false; - } - get templateID() { - return "EICASCommonDisplayTemplate"; - } - connectedCallback() { - super.connectedCallback(); - TemplateElement.call(this, this.init.bind(this)); - } - init() { - this.tatText = this.querySelector("#TATValue"); - this.satText = this.querySelector("#SATValue"); - this.isaText = this.querySelector("#ISAValue"); - this.isaContainer = this.querySelector("#ISA"); - this.areAdirsAligned = null; - this.isSATVisible = null; - this.isTATVisible = null; - this.isISAVisible = null; - this.currentSeconds = 0; - this.currentMinutes = 0; - this.hoursText = this.querySelector("#HoursValue"); - this.minutesText = this.querySelector("#MinutesValue"); - this.loadFactorContainer = this.querySelector("#LoadFactor"); - this.loadFactorText = this.querySelector("#LoadFactorValue"); - this.loadFactorSet = new NXLogic_ConfirmNode(2); - this.loadFactorReset = new NXLogic_ConfirmNode(5); - this.loadFactorVisible = new NXLogic_MemoryNode(true); - this.gwUnit = this.querySelector("#GWUnit"); - this.gwValue = this.querySelector("#GWValue"); - this.refreshTAT(Arinc429Word.empty()); - this.refreshSAT(Arinc429Word.empty()); - this.refreshISA(Arinc429Word.empty()); - this.refreshClock(); - this.refreshGrossWeight(true); - this.isInitialised = true; - } - update(_deltaTime) { - if (!this.isInitialised) { - return; - } - - const airDataReferenceSource = this.getStatusAirDataReferenceSource(); - const inertialReferenceSource = this.getStatusInertialReferenceSource(); - const sat = Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_STATIC_AIR_TEMPERATURE`); - /* this.refreshTAT(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_TOTAL_AIR_TEMPERATURE`)); - this.refreshSAT(sat); - this.refreshISA(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_INTERNATIONAL_STANDARD_ATMOSPHERE_DELTA`), sat); */ - - this.refreshClock(); - this.refreshLoadFactor(_deltaTime, Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_IR_${inertialReferenceSource}_BODY_NORMAL_ACC`)); - this.refreshGrossWeight(); - this.refreshHomeCockpitMode(); - } - - getStatusAirDataReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_AIR_DATA_SWITCHING_KNOB', 'Enum')); - } - - getStatusInertialReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_ATT_HDG_SWITCHING_KNOB', 'Enum')); - } - - getStatusSupplier(knobValue) { - const adirs3ToCaptain = 0; - return knobValue === adirs3ToCaptain ? 3 : 1; - } - - refreshTAT(tat) { - if (!tat.isNormalOperation()) { - this.tatText.textContent = "XX"; - this.toggleWarning(true, this.tatText); - } else { - this.setValueOnTemperatureElement(Math.round(tat.value), this.tatText); - this.toggleWarning(false, this.tatText); - } - } - - refreshSAT(sat) { - if (!sat.isNormalOperation()) { - this.satText.textContent = "XX"; - this.toggleWarning(true, this.satText); - } else { - this.setValueOnTemperatureElement(Math.round(sat.value), this.satText); - this.toggleWarning(false, this.satText); - } - } - - refreshISA(isa, sat) { - const isInStdMode = Simplane.getPressureSelectedMode(Aircraft.A320_NEO) === "STD"; - // As ISA relates to SAT, we cannot present ISA when SAT is unavailable. We might want to move this into - // Rust ADIRS code itself. - const isaShouldBeVisible = isInStdMode && isa.isNormalOperation() && sat.isNormalOperation(); - this.isaContainer.setAttribute("visibility", isaShouldBeVisible ? "visible" : "hidden"); - - this.setValueOnTemperatureElement(Math.round(isa.value), this.isaText); - } - - setValueOnTemperatureElement(value, element) { - if (value > 0) { - element.textContent = "+" + value.toString().padStart(2); - } else { - element.textContent = (value < 0 ? "-" : "") + Math.abs(value).toString().padStart(2); - } - } - - toggleWarning(isWarning, element) { - element.classList.toggle("Warning", isWarning); - element.classList.toggle("Value", !isWarning); - } - - refreshLoadFactor(_deltaTime, n_z) { - const value = n_z.value; - const conditionsMet = value > 1.4 || value < 0.7; - const loadFactorSet = this.loadFactorSet.write(conditionsMet && n_z.isNormalOperation(), _deltaTime); - const loadFactorReset = this.loadFactorReset.write(!conditionsMet || !n_z.isNormalOperation(), _deltaTime); - const flightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - const isVisible = ( - flightPhase >= 4 && - flightPhase <= 8 && - this.loadFactorVisible.write(loadFactorSet, loadFactorReset) - ); - - if (this.loadFactorContainer) { - if (!isVisible) { - this.loadFactorContainer.setAttribute("visibility", "hidden"); - if (this.loadFactorText) { - this.loadFactorText.textContent = ""; - } - return; - } - this.loadFactorContainer.setAttribute("visibility", "visible"); - } - - if (this.loadFactorText) { - if (n_z.isNormalOperation()) { - const clamped = Math.min(Math.max(value, -3), 5); - this.loadFactorText.textContent = (clamped >= 0 ? "+" : "") + clamped.toFixed(1); - } else { - this.loadFactorText.textContent = 'XX'; - } - - } - } - refreshClock() { - const seconds = Math.floor(SimVar.GetGlobalVarValue("ZULU TIME", "seconds")); - if (seconds != this.currentSeconds) { - this.currentSeconds = seconds; - const hours = Math.floor(seconds / 3600); - const minutes = Math.floor((seconds - (hours * 3600)) / 60); - if (minutes != this.currentMinutes) { - this.currentMinutes = minutes; - if (this.hoursText != null) { - this.hoursText.textContent = hours.toString().padStart(2, "0"); - } - if (this.minutesText != null) { - this.minutesText.textContent = minutes.toString().padStart(2, "0"); - } - } - } - } - refreshGrossWeight(_force = false) { - const isOneEngineRunning = SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:1", "Number") >= 15 || SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:2", "Number") >= 15; //BASED ON IRL REFERENCE - const gw = Math.round(NXUnits.kgToUser(SimVar.GetSimVarValue("L:A32NX_FM_GROSS_WEIGHT", "number") * 1000)); - const gwUnit = NXUnits.userWeightUnit(); - if ((gw != this.currentGW) || (this.isOneEngineRunning != isOneEngineRunning) || _force) { - this.currentGW = gw; - this.isOneEngineRunning = isOneEngineRunning; - - if (isOneEngineRunning && this.currentGW != 0) { - // Lower EICAS displays GW in increments of 100 - this.gwValue.classList.add("Value"); - this.gwValue.classList.remove("Cyan"); - this.gwValue.textContent = (Math.floor(this.currentGW / 100) * 100).toString(); - } else { - this.gwValue.classList.remove("Value"); - this.gwValue.classList.add("Cyan"); - this.gwValue.textContent = "--"; - } - } - if (gwUnit != this.currentGwUnit) { - this.currentGwUnit = gwUnit; - if (this.gwUnit != null) { - this.gwUnit.textContent = gwUnit; - } - } - } -} -customElements.define("eicas-common-display", EICASCommonDisplay); diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.css b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.css deleted file mode 100644 index 93d27833..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.css +++ /dev/null @@ -1,256 +0,0 @@ -@import url("/CSS/A21NHS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; - background: radial-gradient( - ellipse at center, - rgba(4, 4, 4, 1) 0%, - rgba(4, 4, 4, 1) 100% - ); -} -#Electricity[state="off"] { - display: none; -} - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); - height: calc( - var(--viewportHeightRatio) * (640px / 21.6) * var(--currentPageHeight) / 100 - ); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #RedArc { - fill: none; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 3; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder { - fill: none; - stroke: var(--displayGrey); - stroke-width: 3px; -} - -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: black; - stroke: var(--displayGrey); - stroke-width: 3px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none; -} - -a320-neo-eicas-element { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; -} -a320-neo-eicas-element #highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -a320-neo-eicas-element #Mainframe { - top: 0; - left: 0; - width: 100%; - height: 100%; - display: block; - position: relative; -} -a320-neo-eicas-element #Mainframe #TopScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 4, 1) 0%, - rgba(4, 4, 4, 1) 100% - ); - transform: rotateX(0); - top: 0%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} -a320-neo-eicas-element #Mainframe #BottomScreen { - background: radial-gradient( - ellipse at center, - rgba(4, 4, 4, 1) 0%, - rgba(4, 4, 4, 1) 100% - ); - transform: rotateX(0); - top: 5%; - left: 0%; - width: 100%; - height: 100%; - position: relative; - display: none; -} - -a320-neo-eicas-element[index="1"] #Mainframe #TopScreen { - display: block; -} -a320-neo-eicas-element[index="2"] #Mainframe #BottomScreen { - display: block; -} -.blue-text { - color: var(--displayCyan); -} -.SelfTestWrapper { - position: absolute; - left: 0%; - top: 0%; - width: 100%; - height: 100%; - border: none; - visibility: hidden; -} -#BottomScreen #door-video-wrapper { - position: absolute; - top: -5%; - width: 100%; - height: 82%; - z-index: 100; - visibility: hidden; - background-image: url(/Images/A21NHS/SD/door_camera.png); - background-size: cover; -} diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.html b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.html deleted file mode 100644 index 435c4337..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.js b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.js deleted file mode 100644 index 7555c287..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS.js +++ /dev/null @@ -1,315 +0,0 @@ -class A320_Neo_EICAS extends Airliners.BaseEICAS { - get templateID() { - return "A320_Neo_EICAS"; - } - - // This js file has 2 intances at runtime, 1 upper screen and 1 lower - get isTopScreen() { - return this.urlConfig.index === 1; - } - - get isBottomScreen() { - return this.urlConfig.index === 2; - } - - // The following two functions can be called from anywhere on the EICAS - static isOnTopScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isTopScreen; - } - - static isOnBottomScreen() { - const eicas = document.getElementsByTagName("a320-neo-eicas-element"); - if (!eicas.length) { - return false; - } - return eicas[0].isBottomScreen; - } - - changePage(_pageName) { - let pageName = _pageName.toUpperCase(); - const isOnGround = SimVar.GetSimVarValue("GEAR IS ON GROUND","Bool"); - for (let i = 0; i < this.lowerScreenPages.length; i++) { - //skip CRZ and go back to ENG Page - if (this.lowerScreenPages[i].name == "CRZ" && isOnGround) { - pageName = "ENG"; - //The index of the ENG page is 0 so loop counter will point to correct index without triggering a new iteration. - i = 0; - } - if (this.lowerScreenPages[i].name == pageName) { - let pageIndex = i; - if (pageIndex == this.currentPage) { - pageName = this.pageNameWhenUnselected; - pageIndex = -1; - } - - this.currentPage = pageIndex; - break; - } - } - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, pageName); - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", this.currentPage); - } - - createLowerScreenPages() { - this.addIndependentElementContainer(new Airliners.EICASScreen("BottomScreenCommon", "BottomScreen", "eicas-common-display")); - this.createLowerScreenPage("ENG", "BottomScreen", "a32nx-eng-page-element"); - this.createLowerScreenPage("BLEED", "BottomScreen", "a32nx-bleed-page-element"); - this.createLowerScreenPage("PRESS", "BottomScreen", "a32nx-press-page-element"); - this.createLowerScreenPage("ELEC", "BottomScreen", "a32nx-elec-page-element"); - this.createLowerScreenPage("HYD", "BottomScreen", "a32nx-hyd-page-element"); - this.createLowerScreenPage("FUEL", "BottomScreen", "a32nx-fuel-page-element"); - this.createLowerScreenPage("APU", "BottomScreen", "a32nx-apu-page-element"); - this.createLowerScreenPage("COND", "BottomScreen", "a32nx-cond-page-element"); - this.createLowerScreenPage("DOOR", "BottomScreen", "a32nx-door-page-element"); - this.createLowerScreenPage("WHEEL", "BottomScreen", "a32nx-wheel-page-element"); - this.createLowerScreenPage("FTCL", "BottomScreen", "a32nx-fctl-page-element"); - this.createLowerScreenPage("STS", "BottomScreen", "a32nx-status-page-element"); - this.createLowerScreenPage("CRZ", "BottomScreen", "a32nx-crz-page-element"); - } - - getLowerScreenChangeEventNamePrefix() { - return "ECAM_CHANGE_PAGE_"; - } - - Init() { - super.Init(); - this.getDeltaTime = A32NX_Util.createDeltaTimeCalculator(this._lastTime); - this.currentPage = -1; - this.ecamAllButtonTimer = 1000; - this.ecamAllButtonTimerStarted = false; - - this.pageNameWhenUnselected = "DOOR"; - - this.ecamFCTLTimer = -1; - - this.changePage("FUEL"); // MODIFIED - - this.lastAPUMasterState = 0; // MODIFIED - this.ApuAboveThresholdTimer = -1; // MODIFIED - this.MainEngineStarterOffTimer = -1; - this.CrzCondTimer = 60; - this.PrevFailPage = -1; - - this.doorVideoWrapper = this.querySelector("#door-video-wrapper"); - - this.lowerEngTestDiv = this.querySelector("#Eicas2EngTest"); - this.lowerEngMaintDiv = this.querySelector("#Eicas2MaintMode"); - - this.doorVideoPressed = false; - this.doorVideoEnabled = false; - - // Using ternary in case the LVar is undefined - this.poweredDuringPreviousUpdate = SimVar.GetSimVarValue("L:A32NX_COLD_AND_DARK_SPAWN", "Bool") ? 0 : 1; - - this.changePage("DOOR"); // MODIFIED - this.changePage("DOOR"); // This should get the ECAM into the "unselected" state - - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:7", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:84", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:85", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:86", "number", 0); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:87", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:88", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:89", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:90", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:91", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:92", "number", 0.1); - SimVar.SetSimVarValue("LIGHT POTENTIOMETER:93", "number", 0.1); - - this.ecamAllButtonPrevState = false; - this.updateThrottler = new UpdateThrottler(500); - - this.displayUnit = new DisplayUnit( - this.querySelector("#Electricity"), - () => { - return SimVar.GetSimVarValue("L:A32NX_ELEC_AC_2_BUS_IS_POWERED", "Bool"); - }, - () => parseInt(NXDataStore.get("CONFIG_SELF_TEST_TIME", "15")), - 93, - this.querySelector("#BottomSelfTest") - ); - } - - onUpdate() { - let deltaTime = this.getDeltaTime(); - super.onUpdate(deltaTime); - - const ecamAllButtonBeingPushed = SimVar.GetSimVarValue("L:A32NX_ECAM_ALL_Push_IsDown", "Bool"); - - deltaTime = this.updateThrottler.canUpdate(deltaTime, this.displayUnit.isJustNowTurnedOn() || ecamAllButtonBeingPushed); - if (deltaTime === -1) { - return; - } - - this.displayUnit.update(deltaTime); - - this.updateDoorVideoState(); - - // Engineering self-tests - updateDisplayDMC("EICAS2", this.lowerEngTestDiv, this.lowerEngMaintDiv); - - //Determine displayed page when no button is selected - const prevPage = this.pageNameWhenUnselected; - - const fwcFlightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - - switch (fwcFlightPhase) { - case 10: - case 1: - this.CrzCondTimer = 60; - this.pageNameWhenUnselected = "DOOR"; - //TODO: Emergency Generator Test displays ELEC - //Needs system implementation (see A320_NEO_INTERIOR Component ID EMER_ELEC_PWR [LVar: L:A32NX_EMERELECPWR_GEN_TEST]) - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 2: - const sidestickPosX = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_X", "Number"); - const sidestickPosY = SimVar.GetSimVarValue("L:A32NX_SIDESTICK_POSITION_Y", "Number"); - const rudderPos = SimVar.GetSimVarValue("RUDDER PEDAL POSITION", "Position"); - const controlsMoved = Math.abs(sidestickPosX) > 0.05 || Math.abs(sidestickPosY) > 0.05 || Math.abs(rudderPos) > 0.2; - - this.pageNameWhenUnselected = "WHEEL"; - // When controls are moved > threshold, show FCTL page for 20s - if (controlsMoved) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer = 20; - } else if (this.ecamFCTLTimer >= 0) { - this.pageNameWhenUnselected = "FTCL"; - this.ecamFCTLTimer -= deltaTime / 1000; - } - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - case 3: - case 4: - case 5: - this.pageNameWhenUnselected = "ENG"; - break; - case 6: - case 7: - case 8: - case 9: - const isGearExtended = SimVar.GetSimVarValue("GEAR TOTAL PCT EXTENDED", "percent") > 0.95; - const ToPowerSet = Math.max(SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:1", "number"), SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:2", "number")) >= 35 && SimVar.GetSimVarValue("ENG N1 RPM:1", "Percent") > 15 && SimVar.GetSimVarValue("ENG N1 RPM:2", "Percent") > 15; - const spoilerOrFlapsDeployed = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "number") !== 0 || SimVar.GetSimVarValue("L:A32NX_SPOILERS_HANDLE_POSITION", "percent") !== 0; - - if (isGearExtended && (Simplane.getAltitude() < 16000)) { - this.pageNameWhenUnselected = "WHEEL"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - break; - // Else check for CRZ - } - - if ((spoilerOrFlapsDeployed || ToPowerSet)) { - if (this.CrzCondTimer <= 0) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } else { - this.CrzCondTimer -= deltaTime / 1000; - } - } else if (!spoilerOrFlapsDeployed && !ToPowerSet) { - this.pageNameWhenUnselected = "CRZ"; - this.checkApuPage(deltaTime); - this.checkEnginePage(deltaTime); - } - break; - default: - // Sometimes happens when loading in, in which case we have to initialise pageNameWhenUnselected here. - this.pageNameWhenUnselected = "DOOR"; - break; - } - - const sFailPage = SimVar.GetSimVarValue("L:A32NX_ECAM_SFAIL", "Enum"); - - if (sFailPage != -1) { - this.pageNameWhenUnselected = this.lowerScreenPages[sFailPage].name; - - // Disable user selected page when new failure detected - if (this.PrevFailPage !== sFailPage) { - this.currentPage = -1; - //SimVar.SetSimVarValue("L:A32NX_ECAM_SD_CURRENT_PAGE_INDEX", "number", -1); - } - } - - // switch page when desired page was changed, or new Failure detected - if ((this.pageNameWhenUnselected != prevPage && this.currentPage == -1) || (this.PrevFailPage !== sFailPage)) { - this.SwitchToPageName(this.LOWER_SCREEN_GROUP_NAME, this.pageNameWhenUnselected); - } - - if (ecamAllButtonBeingPushed && !this.ecamAllButtonPrevState) { // button press - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - this.ecamCycleInterval = setInterval(() => { - this.changePage(this.lowerScreenPages[(this.currentPage + 1) % this.lowerScreenPages.length].name); - }, 1000); - } else if (!ecamAllButtonBeingPushed && this.ecamAllButtonPrevState) { // button release - clearInterval(this.ecamCycleInterval); - } - - this.ecamAllButtonPrevState = ecamAllButtonBeingPushed; - this.PrevFailPage = sFailPage; - } - - checkEnginePage(deltaTime) { - const engModeSel = SimVar.GetSimVarValue("L:XMLVAR_ENG_MODE_SEL", "number"); - const eng1State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:1", "number"); - const eng2State = SimVar.GetSimVarValue("L:A32NX_ENGINE_STATE:2", "number"); - const oneEngOff = eng1State !== 1 || eng2State !== 1; - - if (engModeSel === 0 || (oneEngOff && engModeSel === 2) || this.MainEngineStarterOffTimer >= 0) { - // Show ENG until >10 seconds after both engines are fully started - if (engModeSel === 0 || (oneEngOff && engModeSel === 2)) { - this.MainEngineStarterOffTimer = 10; - } else if (this.MainEngineStarterOffTimer >= 0) { - this.MainEngineStarterOffTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "ENG"; - } - } - - checkApuPage(deltaTime) { - const currentAPUMasterState = SimVar.GetSimVarValue("L:A32NX_OVHD_APU_MASTER_SW_PB_IS_ON", "Bool"); - const apuRpm = Arinc429Word.fromSimVarValue("L:A32NX_APU_N"); - if (currentAPUMasterState && apuRpm.isNormalOperation() && (apuRpm.value <= 95 || this.ApuAboveThresholdTimer >= 0)) { - // Show APU on Lower ECAM until 15s after RPM > 95% - if (this.ApuAboveThresholdTimer <= 0 && apuRpm.value <= 95) { - this.ApuAboveThresholdTimer = 15; - } else if (apuRpm.value > 95) { - this.ApuAboveThresholdTimer -= deltaTime / 1000; - } - this.pageNameWhenUnselected = "APU"; - } - } - - updateDoorVideoState() { - const doorVideoEnabledNow = SimVar.GetSimVarValue("L:A32NX_OVHD_COCKPITDOORVIDEO_TOGGLE", "Bool") === 1; - const doorVideoPressedNow = SimVar.GetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool") === 1; - - if (this.doorVideoEnabled !== doorVideoEnabledNow || this.doorVideoPressed !== doorVideoPressedNow) { - this.doorVideoEnabled = doorVideoEnabledNow; - this.doorVideoPressed = doorVideoPressedNow; - - this.setDoorVideo(); - } - } - - setDoorVideo() { - this.doorVideoWrapper.style.visibility = this.doorVideoEnabled && this.doorVideoPressed ? "visible" : "hidden"; - } - - SwitchToPageName(_menu, _page) { - if (this.doorVideoPressed) { - SimVar.SetSimVarValue("L:PUSH_DOORPANEL_VIDEO", "Bool", 0); - } - - super.SwitchToPageName(_menu, _page); - } -} - -registerInstrument("a320-neo-eicas-element", A320_Neo_EICAS); diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS_PW.html b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS_PW.html deleted file mode 100644 index 4930058e..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/A320_Neo_EICAS_PW.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.css b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.css deleted file mode 100644 index 269b8f52..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.css +++ /dev/null @@ -1,172 +0,0 @@ -@import url("/CSS/A21NHS_Display_Common.css"); - -a320-neo-ecam-gauge { - display: inline-block; - margin-left: 15%; - width: get-vh(640px); - height: get-vh(640px); -} -a320-neo-ecam-gauge text { - fill: var(--displayWhite); - font-size: 12px; - text-align: center; - text-anchor: middle; -} -a320-neo-ecam-gauge #RootSVG { - overflow: visible; - width: 100%; - height: 100%; -} - -a320-neo-ecam-gauge #RootSVG #MainArc { - fill: none; -} -a320-neo-ecam-gauge #RootSVG #MainArc.active { - stroke: var(--displayWhite); -} -a320-neo-ecam-gauge #RootSVG #MainArc.inactive { - stroke: var(--displayAmber); -} - -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - fill: none; -} -a320-neo-ecam-gauge #RootSVG #RedArc.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #RedArc.inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.InnerMarker { - stroke-width: 1px !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .danger { - stroke-width: 1px !important; - stroke: var(--displayRed) !important; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup .warning { - stroke-width: 1px !important; - stroke: var(--displayAmber) !important; -} -a320-neo-ecam-gauge #RootSVG #RedArc { - stroke: var(--displayRed); - stroke-width: 2px; - fill: none; -} -a320-neo-ecam-gauge #RootSVG #GraduationsGroup line.OuterMarker { - stroke: var(--displayAmber); - stroke-width: 6px; -} -a320-neo-ecam-gauge #RootSVG #OuterIndicatorOffset { - stroke: var(--displayCyan) !important; - stroke-width: 1.5px !important; - fill: none; -} - -a320-neo-ecam-gauge #RootSVG #CursorGroup { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup line { - stroke: var(--displayGreen); - stroke-width: 2; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup path { - fill: none; - stroke: var(--displayWhite); - stroke-width: 2px; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .warning { - display: block; - stroke: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .danger { - display: block; - stroke: var(--displayRed); -} -a320-neo-ecam-gauge #RootSVG #CursorGroup .inactive { - display: none; -} - -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject { - fill: none; - stroke: var(--displayGreen); - stroke-width: 4px; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.active { - display: block; -} -a320-neo-ecam-gauge #RootSVG #OuterDynamicArcObject.inactive { - display: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue { - text-align: right; - text-anchor: end; - font-size: 20px !important; - fill: var(--displayBackground); -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.active { - fill: var(--displayGreen); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.warning { - fill: var(--displayAmber); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.danger { - fill: var(--displayRed); - font-size: 20px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.inactive { - fill: var(--displayAmber); - font-size: 20px; - letter-spacing: 5px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder, -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.active { - fill: none; - stroke: sky; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #CurrentValueBorder.inactive { - fill: none; - stroke: none; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.decimal { - font-size: 15px !important; -} -a320-neo-ecam-gauge #RootSVG #CurrentValue.gaugedecimalpoint { - fill: var(--displayGreen); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage { - width: 100%; - height: 100%; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage rect { - fill: var(--displayBackground); - stroke: sky; - stroke-width: 1px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text { - text-align: center; - text-anchor: middle; - fill: var(--displayGreen); - font-size: 15px; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage text.amber { - fill: var(--displayAmber); -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .active { - display: block !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .inactive { - display: none !important; -} -a320-neo-ecam-gauge #RootSVG #ExtraMessage .avail { - font-size: 19.2px !important; -} diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.js b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.js deleted file mode 100644 index 7fbc8b5c..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/ECAM/A320_Neo_ECAMGauge.js +++ /dev/null @@ -1,549 +0,0 @@ -var A320_Neo_ECAM_Common; -(function (A320_Neo_ECAM_Common) { - const absoluteZeroThermodynamicTemperature = -273.15; - - function hasThermodynamicTemperatureValue(value) { - return value >= absoluteZeroThermodynamicTemperature; - } - - function isEngineDisplayActive(_index) { - return ((SimVar.GetSimVarValue("ENG N1 RPM:" + _index, "percent") >= 0.05) || (SimVar.GetSimVarValue("ENG N2 RPM:" + _index, "percent") >= 0.05)); - } - A320_Neo_ECAM_Common.isEngineDisplayActive = isEngineDisplayActive; - class GaugeDefinition { - constructor() { - this.startAngle = -225; - this.arcSize = 180; - this.cursorOffset = 0; - this.minValue = 0; - this.maxValue = 100; - this.minRedValue = 0; - this.maxRedValue = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.cursorLength = 1.0; - this.cursorMultiplier = 1.1; - this.currentValuePos = new Vec2(0.65, 0.65); - this.currentValueFunction = null; - this.currentValuePrecision = 0; - this.currentValueBorderWidth = 0; - this.outerIndicatorFunction = null; - this.outerDynamicArcFunction = null; - this.extraMessageFunction = null; - this.extraMessageStyleFunction = null; - this.outerDynamicMarkerFunction = null; - this.dangerMinDynamicFunction = null; - this.outerMarkerValue = null; - this.roundDisplayValueToNearest = null; - } - } - A320_Neo_ECAM_Common.GaugeDefinition = GaugeDefinition; - class Gauge extends HTMLElement { - constructor() { - super(...arguments); - this.viewBoxSize = new Vec2(100, 100); - this.startAngle = -225; - this.cursorOffset = 0; - this.warningRange = [0, 0]; - this.dangerRange = [0, 0]; - this.outerDynamicArcCurrentValues = [0, 0]; - this.outerDynamicArcTargetValues = [0, 0]; - this.extraMessageString = ""; - this.extraMessageStyle = ""; - this.isActive = true; - this.extraMessagePosXMultiplier = 0; - this.extraMessagePosYMultiplier = 0; - this.extraMessageBorderPosXMultiplier = 0; - this.extraMessageBorderPosYMultiplier = 0; - this.extraMessageBorderWidthMultiplier = 0; - this.extraMessageBorderHeightMultiplier = 0; - this.cursorMultiplier = 1.1; - this.uppercam = false; - } - get mainArcRadius() { - return (this.viewBoxSize.x * 0.5 * 0.975); - } - get cursorArcRadius() { - return (this.mainArcRadius * this.cursorMultiplier); - } - get graduationInnerLineEndOffset() { - return (this.mainArcRadius * 0.9); - } - get graduationOuterLineEndOffset() { - return (this.mainArcRadius * 1.175); - } - get graduationTextOffset() { - return (this.mainArcRadius * 0.625); - } - get redArcInnerRadius() { - return (this.mainArcRadius * 1); - } - get outerIndicatorOffset() { - return (this.viewBoxSize.x * 0.03); - } - get outerIndicatorRadius() { - return (this.viewBoxSize.x * 0.03); - } - get outerDynamicArcRadius() { - return (this.mainArcRadius * 1.15); - } - get currentValueBorderHeight() { - return (this.viewBoxSize.y * 0.20); - } - get extraMessagePosX() { - return (this.center.x + (this.viewBoxSize.x * this.extraMessagePosXMultiplier)); - } - get extraMessagePosY() { - return (this.center.y - (this.viewBoxSize.y * this.extraMessagePosYMultiplier)); - } - get extraMessageBorderPosX() { - return (this.extraMessagePosX - (this.viewBoxSize.x * this.extraMessageBorderPosXMultiplier)); - } - get extraMessageBorderPosY() { - return (this.extraMessagePosY - (this.viewBoxSize.y * this.extraMessageBorderPosYMultiplier)); - } - get extraMessageBorderWidth() { - return (this.viewBoxSize.x * this.extraMessageBorderWidthMultiplier); - } - get extraMessageBorderHeight() { - return (this.viewBoxSize.y * this.extraMessageBorderHeightMultiplier); - } - set active(_isActive) { - if (this.isActive != _isActive) { - this.isActive = _isActive; - this.refreshActiveState(); - } - } - get active() { - return this.isActive; - } - polarToCartesian(_centerX, _centerY, _radius, _angleInDegrees) { - const angleInRadians = _angleInDegrees * (Math.PI / 180.0); - return new Vec2(_centerX + (_radius * Math.cos(angleInRadians)), _centerY + (_radius * Math.sin(angleInRadians))); - } - valueToAngle(_value, _radians) { - const valuePercentage = (_value - this.minValue) / (this.maxValue - this.minValue); - let angle = (this.startAngle + (valuePercentage * this.arcSize)); - if (_radians) { - angle *= (Math.PI / 180.0); - } - return angle; - } - valueToDir(_value) { - const angle = this.valueToAngle(_value, true); - return (new Vec2(Math.cos(angle), Math.sin(angle))); - } - init(_gaugeDefinition) { - this.cursorOffset = _gaugeDefinition.cursorOffset; - this.startAngle = _gaugeDefinition.startAngle; - this.arcSize = _gaugeDefinition.arcSize; - this.minValue = _gaugeDefinition.minValue; - this.maxValue = _gaugeDefinition.maxValue; - this.minRedValue = _gaugeDefinition.minRedValue; - this.previousUpdateMinRedValue = _gaugeDefinition.minRedValue; - this.maxRedValue = _gaugeDefinition.maxRedValue; - this.warningRange[0] = _gaugeDefinition.warningRange[0]; - this.warningRange[1] = _gaugeDefinition.warningRange[1]; - this.dangerRange[0] = _gaugeDefinition.dangerRange[0]; - this.dangerRange[1] = _gaugeDefinition.dangerRange[1]; - this.cursorMultiplier = _gaugeDefinition.cursorMultiplier; - this.currentValueFunction = _gaugeDefinition.currentValueFunction; - this.currentValuePrecision = _gaugeDefinition.currentValuePrecision; - this.outerIndicatorFunction = _gaugeDefinition.outerIndicatorFunction; - this.outerDynamicArcFunction = _gaugeDefinition.outerDynamicArcFunction; - this.extraMessageFunction = _gaugeDefinition.extraMessageFunction; - this.extraMessageStyleFunction = _gaugeDefinition.extraMessageStyleFunction; - this.roundDisplayValueToNearest = _gaugeDefinition.roundDisplayValueToNearest; - this.extraMessagePosXMultiplier = 0.025; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - this.outerDynamicMarkerFunction = _gaugeDefinition.outerDynamicMarkerFunction; - this.dangerMinDynamicFunction = _gaugeDefinition.dangerMinDynamicFunction; - this.uppercam = _gaugeDefinition.uppercam; - this.endAngle = this.startAngle + _gaugeDefinition.arcSize; - this.center = new Vec2(this.viewBoxSize.x * 0.5, this.viewBoxSize.y * 0.5); - this.rootSVG = document.createElementNS(Avionics.SVG.NS, "svg"); - this.rootSVG.id = "RootSVG"; - this.rootSVG.setAttribute("viewBox", "0 0 " + this.viewBoxSize.x + " " + this.viewBoxSize.y); - this.appendChild(this.rootSVG); - this.mainArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.mainArc.id = "MainArc"; - { - const startPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.endAngle); - const endPos = this.polarToCartesian(this.center.x, this.center.y, this.mainArcRadius, this.startAngle); - const largeArcFlag = ((this.endAngle - this.startAngle) <= 180) ? "0" : "1"; - var d = ["M", startPos.x, startPos.y, "A", this.mainArcRadius, this.mainArcRadius, 0, largeArcFlag, 0, endPos.x, endPos.y].join(" "); - this.mainArc.setAttribute("d", d); - } - this.rootSVG.appendChild(this.mainArc); - if (this.minRedValue != this.maxRedValue) { - this.redArc = document.createElementNS(Avionics.SVG.NS, "path"); - this.redArc.id = "RedArc"; - - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.rootSVG.appendChild(this.redArc); - } - this.graduationsGroup = document.createElementNS(Avionics.SVG.NS, "g"); - this.graduationsGroup.id = "GraduationsGroup"; - this.rootSVG.appendChild(this.graduationsGroup); - const cursorGroup = document.createElementNS(Avionics.SVG.NS, "g"); - cursorGroup.id = "CursorGroup"; - this.cursor = document.createElementNS(Avionics.SVG.NS, "line"); - this.cursorArcRadiusChoice = this.cursorArcRadius; - if (this.outerDynamicArcFunction != null) { - this.cursorArcRadiusChoice = this.outerDynamicArcRadius; - } - this.cursor.setAttribute("x1", (this.cursorArcRadiusChoice * (1 - _gaugeDefinition.cursorLength)).toString()); - this.cursor.setAttribute("y1", "0"); - this.cursor.setAttribute("x2", this.cursorArcRadiusChoice.toString()); - this.cursor.setAttribute("y2", "0"); - cursorGroup.setAttribute("transform", "translate(" + this.center.x + ", " + this.center.y + ")"); - cursorGroup.appendChild(this.cursor); - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerDynamicArcObject.id = "OuterDynamicArcObject"; - this.rootSVG.appendChild(this.outerDynamicArcObject); - } - if (this.outerIndicatorFunction != null) { - this.outerIndicatorObject = document.createElementNS(Avionics.SVG.NS, "path"); - this.outerIndicatorObject.id = "OuterIndicatorOffset"; - const radius = this.outerIndicatorRadius; - var d = [ - "M", (this.mainArcRadius + this.outerIndicatorOffset), "0", - "a", radius, radius, "0 1 0", (radius * 2), "0", - "a", radius, radius, "0 1 0", -(radius * 2), "0" - ].join(" "); - this.outerIndicatorObject.setAttribute("d", d); - cursorGroup.appendChild(this.outerIndicatorObject); - } - this.rootSVG.appendChild(cursorGroup); - const textPosX = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.x; - const textPosY = this.viewBoxSize.x * _gaugeDefinition.currentValuePos.y; - const textPosXdec = (this.currentValuePrecision == 1) ? textPosX - 19 : textPosX; - const textPosYdec = (this.currentValuePrecision == 1) ? textPosY + 7 : textPosY; - this.currentValueText = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueText.id = "CurrentValue"; - this.currentValueText.setAttribute("x", textPosXdec.toString()); - this.currentValueText.setAttribute("y", textPosY.toString()); - this.currentValueText.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueText); - const textPosXdecimal = textPosX; - const textPosYdecimal = textPosYdec; - this.currentValueTextdecimal = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimal.id = "CurrentValue"; - this.currentValueTextdecimal.setAttribute("x", textPosXdecimal.toString()); - this.currentValueTextdecimal.setAttribute("y", textPosYdecimal.toString()); - this.currentValueTextdecimal.setAttribute("alignment-baseline", "text-bottom"); - this.rootSVG.appendChild(this.currentValueTextdecimal); - const textPosXdecP = textPosX - 9; - this.currentValueTextdecimalP = document.createElementNS(Avionics.SVG.NS, "text"); - this.currentValueTextdecimalP.id = "CurrentValue"; - this.currentValueTextdecimalP.setAttribute("x", textPosXdecP.toString()); - this.currentValueTextdecimalP.setAttribute("y", textPosY.toString()); - //this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("alignment-baseline", "central"); - this.rootSVG.appendChild(this.currentValueTextdecimalP); - if (_gaugeDefinition.currentValueBorderWidth > 0) { - const borderWidth = this.viewBoxSize.x * _gaugeDefinition.currentValueBorderWidth; - const borderHeight = this.currentValueBorderHeight * 1.2; - const borderPosX = textPosX - (borderWidth * 0.95); - const borderPosY = textPosY - (borderHeight * 0.55); - this.currentValueBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.currentValueBorder.id = "CurrentValueBorder"; - this.currentValueBorder.setAttribute("x", borderPosX.toString()); - this.currentValueBorder.setAttribute("y", borderPosY.toString()); - this.currentValueBorder.setAttribute("width", borderWidth.toString()); - this.currentValueBorder.setAttribute("height", borderHeight.toString()); - this.rootSVG.appendChild(this.currentValueBorder); - } - if (this.extraMessageFunction != null) { - const extraMessageGroup = document.createElementNS(Avionics.SVG.NS, "g"); - extraMessageGroup.id = "ExtraMessage"; - this.extraMessageBorder = document.createElementNS(Avionics.SVG.NS, "rect"); - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageBorder.setAttribute("class", "inactive"); - extraMessageGroup.appendChild(this.extraMessageBorder); - this.extraMessageText = document.createElementNS(Avionics.SVG.NS, "text"); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageText.setAttribute("class", "active"); - extraMessageGroup.appendChild(this.extraMessageText); - this.rootSVG.appendChild(extraMessageGroup); - } - this.refreshMainValue(this.minValue, true); - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(0, true); - } - if (this.outerDynamicArcFunction != null) { - this.refreshOuterDynamicArc(0, 0); - } - this.refreshActiveState(); - } - - //accepts two more parameters to set custom ID for dynamic markers - addGraduation(_value, _showInnerMarker, _text = "", _showOuterMarker = false, _setid = false, _idName = "", _markerColour = "") { - const dir = this.valueToDir(_value + this.cursorOffset); - if (_showInnerMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationInnerLineEndOffset), this.center.y + (dir.y * this.graduationInnerLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - if (_setid) { - marker.setAttribute("id",_idName); - } - if (_markerColour != "") { - marker.setAttribute("class", "InnerMarker" + " " + _markerColour); - } else { - marker.setAttribute("class", "InnerMarker"); - } - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_showOuterMarker) { - var start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - var end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - var marker = document.createElementNS(Avionics.SVG.NS, "line"); - this.outerMarkerValue = _value; - marker.setAttribute("id", _idName); - marker.setAttribute("class", "OuterMarker"); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - this.graduationsGroup.appendChild(marker); - } - if (_text.length > 0) { - const pos = new Vec2(this.center.x + (dir.x * this.graduationTextOffset), this.center.y + (dir.y * this.graduationTextOffset)); - const text = document.createElementNS(Avionics.SVG.NS, "text"); - text.textContent = _text; - text.setAttribute("x", pos.x.toString()); - text.setAttribute("y", pos.y.toString()); - text.setAttribute("alignment-baseline", "central"); - this.graduationsGroup.appendChild(text); - } - } - refreshActiveState() { - const style = this.isActive ? "active" : "inactive"; - if (this.mainArc != null) { - this.mainArc.setAttribute("class", style); - } - if (this.redArc != null) { - this.redArc.setAttribute("class", style); - } - if (this.graduationsGroup != null) { - this.graduationsGroup.setAttribute("class", style); - } - if (this.cursor != null) { - this.cursor.setAttribute("class", style); - } - if (this.outerIndicatorObject != null) { - this.outerIndicatorObject.setAttribute("class", style); - } - if (this.outerDynamicArcObject != null) { - this.outerDynamicArcObject.setAttribute("class", style); - } - if (this.currentValueText != null) { - this.currentValueText.setAttribute("class", style); - if (this.uppercam) { - this.currentValueBorder.setAttribute('class', style); - } - if (!this.isActive) { - this.currentValueText.textContent = "XX"; - this.currentValueTextdecimal.textContent = ""; - this.currentValueTextdecimalP.textContent = ""; - } - } - } - update(_deltaTime) { - if (this.isActive) { - if (this.currentValueFunction != null) { - this.refreshMainValue(this.currentValueFunction()); - } - if (this.outerIndicatorFunction != null) { - this.refreshOuterIndicator(this.outerIndicatorFunction()); - } - if (this.outerDynamicArcFunction != null) { - this.outerDynamicArcFunction(this.outerDynamicArcTargetValues); - this.refreshOuterDynamicArc(this.outerDynamicArcTargetValues[0], this.outerDynamicArcTargetValues[1]); - } - if (this.outerDynamicMarkerFunction != null) { - this.refreshOuterMarkerFunction(this.outerDynamicMarkerFunction()); - } - if (this.dangerMinDynamicFunction != null) { - this.refreshDangerMinFunction(this.dangerMinDynamicFunction()); - } - if (this.previousUpdateMinRedValue != this.minRedValue) { - this.refreshRedArc(); - } - } - if ((this.extraMessageFunction != null) && (this.extraMessageText != null) && (this.extraMessageBorder != null)) { - const extraMessage = this.isActive ? this.extraMessageFunction().toString() : ""; - const extraMessageStyle = this.extraMessageStyleFunction().toString(); - - let style = ""; - - if (extraMessage != this.extraMessageString || extraMessageStyle != this.extraMessageStyle) { - if (this.extraMessageFunction().toString() == "AVAIL") { - this.extraMessagePosXMultiplier = 0.198; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.345; - this.extraMessageBorderPosYMultiplier = 0.125; - this.extraMessageBorderWidthMultiplier = 0.68; - this.extraMessageBorderHeightMultiplier = 0.25; - style = "avail "; - } else { - this.extraMessagePosXMultiplier = 0.05; - this.extraMessagePosYMultiplier = 0.025; - this.extraMessageBorderPosXMultiplier = 0.2; - this.extraMessageBorderPosYMultiplier = 0.09; - this.extraMessageBorderWidthMultiplier = 0.4; - this.extraMessageBorderHeightMultiplier = 0.2; - } - this.extraMessageBorder.setAttribute("x", this.extraMessageBorderPosX.toString()); - this.extraMessageBorder.setAttribute("y", this.extraMessageBorderPosY.toString()); - this.extraMessageBorder.setAttribute("width", this.extraMessageBorderWidth.toString()); - this.extraMessageBorder.setAttribute("height", this.extraMessageBorderHeight.toString()); - this.extraMessageText.setAttribute("x", this.extraMessagePosX.toString()); - this.extraMessageText.setAttribute("y", this.extraMessagePosY.toString()); - this.extraMessageText.setAttribute("alignment-baseline", "central"); - this.extraMessageString = extraMessage; - this.extraMessageStyle = extraMessageStyle; - style += (this.extraMessageString.length > 0) ? "active" : "inactive"; - style += extraMessageStyle; - this.extraMessageBorder.setAttribute("class", style); - this.extraMessageText.setAttribute("class", style); - this.extraMessageText.textContent = this.extraMessageString; - } - } - } - refreshRedArc() { - if (this.redArc) { - const d = hasThermodynamicTemperatureValue(this.minRedValue) ? this.calculateRedArcD() : ""; - this.redArc.setAttribute("d", d); - - this.previousUpdateMinRedValue = this.minRedValue; - } - } - calculateRedArcD() { - const minRedDir = this.valueToDir(this.minRedValue + this.cursorOffset); - const maxRedDir = this.valueToDir(this.maxRedValue + this.cursorOffset); - const topRight = new Vec2(this.center.x + (maxRedDir.x * this.mainArcRadius), this.center.y + (maxRedDir.y * this.mainArcRadius)); - const topLeft = new Vec2(this.center.x + (minRedDir.x * this.mainArcRadius), this.center.y + (minRedDir.y * this.mainArcRadius)); - const bottomRight = new Vec2(this.center.x + (maxRedDir.x * this.redArcInnerRadius), this.center.y + (maxRedDir.y * this.redArcInnerRadius)); - const bottomLeft = new Vec2(this.center.x + (minRedDir.x * this.redArcInnerRadius), this.center.y + (minRedDir.y * this.redArcInnerRadius)); - return [ - "M", topRight.x, topRight.y, - "A", this.mainArcRadius, this.mainArcRadius, 0, "0", 0, topLeft.x, topLeft.y, - "L", bottomLeft.x, bottomLeft.y, - "M", topRight.x, topRight.y, - "L", bottomRight.x, bottomRight.y, - "A", this.redArcInnerRadius, this.redArcInnerRadius, 0, "0", 0, bottomLeft.x, bottomLeft.y - ].join(" "); - } - //accepts ID_EGT, _value[0] = _id, _value[1] = EGT - refreshOuterMarkerFunction(_value, _force = false) { - if (_value[1] != this.outerMarkerValue) { - this.outerMarkerValue = _value[1]; - const marker = document.getElementById(_value[0]); - marker.style.display = hasThermodynamicTemperatureValue(this.outerMarkerValue) ? "block" : "none"; - - if (marker.style.display === "block") { - const dir = this.valueToDir(_value[1]); - const start = new Vec2(this.center.x + (dir.x * this.mainArcRadius), this.center.y + (dir.y * this.mainArcRadius)); - const end = new Vec2(this.center.x + (dir.x * this.graduationOuterLineEndOffset), this.center.y + (dir.y * this.graduationOuterLineEndOffset)); - marker.setAttribute("x1", start.x.toString()); - marker.setAttribute("y1", start.y.toString()); - marker.setAttribute("x2", end.x.toString()); - marker.setAttribute("y2", end.y.toString()); - } - } - } - refreshDangerMinFunction(_value, _force = false) { - if (_value != this.dangerRange[0]) { - this.dangerRange[0] = _value; - } - } - refreshMainValue(_value, _force = false) { - this.currentValue = _value; - this.currentValueCursor = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - const clampedValue = Utils.Clamp(this.currentValue, this.minValue, this.maxValue); - const clampedValueCursor = Utils.Clamp(this.currentValueCursor, this.minValue, this.maxValue); - let style = ""; - if ((this.dangerRange[0] != this.dangerRange[1]) && (clampedValue >= this.dangerRange[0]) && (clampedValue <= this.dangerRange[1])) { - style = "danger"; - } else if ((this.warningRange[0] != this.warningRange[1]) && (clampedValue >= this.warningRange[0]) && (clampedValue <= this.warningRange[1])) { - style = "warning"; - } else { - style = "active"; - } - if (this.cursor != null) { - const angle = this.valueToAngle(clampedValueCursor, false); - this.cursor.setAttribute("transform", "rotate(" + angle + ")"); - this.cursor.setAttribute("class", style); - } - if (this.currentValueText != null) { - let displayValue = this.currentValue; - if (this.roundDisplayValueToNearest) { - displayValue = Math.round(displayValue / this.roundDisplayValueToNearest) * this.roundDisplayValueToNearest; - } - const strValue = displayValue.toFixed(this.currentValuePrecision); - this.currentValueText.textContent = strValue; - this.currentValueText.setAttribute("class", style); - if (this.currentValuePrecision > 0) { - const strValueArray = strValue.split("."); - this.currentValueText.textContent = strValueArray[0]; - this.currentValueTextdecimal.textContent = strValueArray[1]; - this.currentValueTextdecimal.setAttribute("class", style + " decimal"); - this.currentValueTextdecimalP.textContent = "."; - this.currentValueTextdecimalP.setAttribute("class", style + " decimalpoint"); - } - } - } - refreshOuterIndicator(_value, _force = false) { - if ((_value != this.outerIndicatorValue) || _force) { - this.outerIndicatorValue = _value; - if (this.outerIndicatorObject != null) { - const valueThrottlePosition = (_value <= this.minValue) ? this.cursorOffset + this.minValue : _value + this.cursorOffset; - //const valueThrottlePosition = _value + this.cursorOffset; - const clampedValueThrottlePosition = Utils.Clamp(valueThrottlePosition , this.minValue, this.maxValue); - const angle = this.valueToAngle(clampedValueThrottlePosition, false); - this.outerIndicatorObject.setAttribute("transform", "rotate(" + angle + ")"); - } - } - } - refreshOuterDynamicArc(_start, _end, _force = false) { - if ((_start != this.outerDynamicArcCurrentValues[0]) || (_end != this.outerDynamicArcCurrentValues[1]) || _force) { - this.outerDynamicArcCurrentValues[0] = Utils.Clamp(_start, this.minValue, this.maxValue); - this.outerDynamicArcCurrentValues[1] = Utils.Clamp(_end, this.minValue, this.maxValue); - let d = ""; - if (this.outerDynamicArcCurrentValues[0] != this.outerDynamicArcCurrentValues[1]) { - const startAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[0], true); - const startX = this.center.x + (Math.cos(startAngle) * this.outerDynamicArcRadius); - const startY = this.center.y + (Math.sin(startAngle) * this.outerDynamicArcRadius); - const endAngle = this.valueToAngle(this.outerDynamicArcCurrentValues[1], true); - const endX = this.center.x + (Math.cos(endAngle) * this.outerDynamicArcRadius); - const endY = this.center.y + (Math.sin(endAngle) * this.outerDynamicArcRadius); - const largeArcFlag = ((endAngle - startAngle) <= Math.PI) ? "0 0 0" : "0 1 0"; - d = [ - "M", endX, endY, - "A", this.outerDynamicArcRadius, this.outerDynamicArcRadius, largeArcFlag, startX, startY - ].join(" "); - } - this.outerDynamicArcObject.setAttribute("d", d); - } - } - } - A320_Neo_ECAM_Common.Gauge = Gauge; -})(A320_Neo_ECAM_Common || (A320_Neo_ECAM_Common = {})); -customElements.define('a320-neo-ecam-gauge', A320_Neo_ECAM_Common.Gauge); diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.css b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.css deleted file mode 100644 index c850dbb3..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.css +++ /dev/null @@ -1,68 +0,0 @@ -@import url("/CSS/A21NHS_Display_Common.css"); - -:root { - --bodyHeightScale: 1; -} - -@keyframes TemporaryShow { - 0%, - 100% { - visibility: visible; - } -} -@keyframes TemporaryHide { - 0%, - 100% { - visibility: hidden; - } -} - -#highlight { - position: absolute; - height: 100%; - width: 100%; - z-index: 10; -} -#Electricity { - width: 100%; - height: 100%; -} -#Electricity[state="off"] { - display: none; -} - -eicas-common-display { - display: block; - position: absolute; - bottom: 0%; - left: 0%; - width: 100%; - height: 25%; -} -eicas-common-display line { - stroke: var(--displayWhite) !important; - stroke-width: 3; -} -eicas-common-display text { - font-size: 20px; - font-family: "ECAMFontRegular"; -} -eicas-common-display text.Cyan { - fill: var(--displayCyan) !important; -} -eicas-common-display text.White { - fill: var(--displayWhite) !important; -} -eicas-common-display text.Value { - fill: var(--displayGreen) !important; -} -eicas-common-display text.Unit { - font-size: 15px !important; - fill: var(--displayCyan) !important; -} -eicas-common-display text.Warning { - fill: var(--displayAmber) !important; -} -eicas-common-display text.Small { - font-size: 18px !important; -} diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.html b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.html deleted file mode 100644 index d434f72f..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - diff --git a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.js b/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.js deleted file mode 100644 index e8c6916a..00000000 --- a/hsim-a321neo/src/base/lvfr-horizonsim-airbus-a321-neo/html_ui/Pages/VCockpit/Instruments/Airliners/lvfr-horizonsim-airbus-a321-neo/EICAS/EICAS_Common.js +++ /dev/null @@ -1,191 +0,0 @@ -class EICASCommonDisplay extends Airliners.EICASTemplateElement { - constructor() { - super(); - this.isInitialised = false; - } - get templateID() { - return "EICASCommonDisplayTemplate"; - } - connectedCallback() { - super.connectedCallback(); - TemplateElement.call(this, this.init.bind(this)); - } - init() { - this.tatText = this.querySelector("#TATValue"); - this.satText = this.querySelector("#SATValue"); - this.isaText = this.querySelector("#ISAValue"); - this.isaContainer = this.querySelector("#ISA"); - this.areAdirsAligned = null; - this.isSATVisible = null; - this.isTATVisible = null; - this.isISAVisible = null; - this.currentSeconds = 0; - this.currentMinutes = 0; - this.hoursText = this.querySelector("#HoursValue"); - this.minutesText = this.querySelector("#MinutesValue"); - this.loadFactorContainer = this.querySelector("#LoadFactor"); - this.loadFactorText = this.querySelector("#LoadFactorValue"); - this.loadFactorSet = new NXLogic_ConfirmNode(2); - this.loadFactorReset = new NXLogic_ConfirmNode(5); - this.loadFactorVisible = new NXLogic_MemoryNode(true); - this.gwUnit = this.querySelector("#GWUnit"); - this.gwValue = this.querySelector("#GWValue"); - this.refreshTAT(Arinc429Word.empty()); - this.refreshSAT(Arinc429Word.empty()); - this.refreshISA(Arinc429Word.empty()); - this.refreshClock(); - this.refreshGrossWeight(true); - this.isInitialised = true; - } - update(_deltaTime) { - if (!this.isInitialised) { - return; - } - - const airDataReferenceSource = this.getStatusAirDataReferenceSource(); - const inertialReferenceSource = this.getStatusInertialReferenceSource(); - const sat = Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_STATIC_AIR_TEMPERATURE`); - /* this.refreshTAT(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_TOTAL_AIR_TEMPERATURE`)); - this.refreshSAT(sat); - this.refreshISA(Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_${airDataReferenceSource}_INTERNATIONAL_STANDARD_ATMOSPHERE_DELTA`), sat); */ - - this.refreshClock(); - this.refreshLoadFactor(_deltaTime, Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_IR_${inertialReferenceSource}_BODY_NORMAL_ACC`)); - this.refreshGrossWeight(); - this.refreshHomeCockpitMode(); - } - - getStatusAirDataReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_AIR_DATA_SWITCHING_KNOB', 'Enum')); - } - - getStatusInertialReferenceSource() { - return this.getStatusSupplier(SimVar.GetSimVarValue('L:A32NX_ATT_HDG_SWITCHING_KNOB', 'Enum')); - } - - getStatusSupplier(knobValue) { - const adirs3ToCaptain = 0; - return knobValue === adirs3ToCaptain ? 3 : 1; - } - - refreshTAT(tat) { - if (!tat.isNormalOperation()) { - this.tatText.textContent = "XX"; - this.toggleWarning(true, this.tatText); - } else { - this.setValueOnTemperatureElement(Math.round(tat.value), this.tatText); - this.toggleWarning(false, this.tatText); - } - } - - refreshSAT(sat) { - if (!sat.isNormalOperation()) { - this.satText.textContent = "XX"; - this.toggleWarning(true, this.satText); - } else { - this.setValueOnTemperatureElement(Math.round(sat.value), this.satText); - this.toggleWarning(false, this.satText); - } - } - - refreshISA(isa, sat) { - const isInStdMode = Simplane.getPressureSelectedMode(Aircraft.A320_NEO) === "STD"; - // As ISA relates to SAT, we cannot present ISA when SAT is unavailable. We might want to move this into - // Rust ADIRS code itself. - const isaShouldBeVisible = isInStdMode && isa.isNormalOperation() && sat.isNormalOperation(); - this.isaContainer.setAttribute("visibility", isaShouldBeVisible ? "visible" : "hidden"); - - this.setValueOnTemperatureElement(Math.round(isa.value), this.isaText); - } - - setValueOnTemperatureElement(value, element) { - if (value > 0) { - element.textContent = "+" + value.toString().padStart(2); - } else { - element.textContent = (value < 0 ? "-" : "") + Math.abs(value).toString().padStart(2); - } - } - - toggleWarning(isWarning, element) { - element.classList.toggle("Warning", isWarning); - element.classList.toggle("Value", !isWarning); - } - - refreshLoadFactor(_deltaTime, n_z) { - const value = n_z.value; - const conditionsMet = value > 1.4 || value < 0.7; - const loadFactorSet = this.loadFactorSet.write(conditionsMet && n_z.isNormalOperation(), _deltaTime); - const loadFactorReset = this.loadFactorReset.write(!conditionsMet || !n_z.isNormalOperation(), _deltaTime); - const flightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum"); - const isVisible = ( - flightPhase >= 4 && - flightPhase <= 8 && - this.loadFactorVisible.write(loadFactorSet, loadFactorReset) - ); - - if (this.loadFactorContainer) { - if (!isVisible) { - this.loadFactorContainer.setAttribute("visibility", "hidden"); - if (this.loadFactorText) { - this.loadFactorText.textContent = ""; - } - return; - } - this.loadFactorContainer.setAttribute("visibility", "visible"); - } - - if (this.loadFactorText) { - if (n_z.isNormalOperation()) { - const clamped = Math.min(Math.max(value, -3), 5); - this.loadFactorText.textContent = (clamped >= 0 ? "+" : "") + clamped.toFixed(1); - } else { - this.loadFactorText.textContent = 'XX'; - } - - } - } - refreshClock() { - const seconds = Math.floor(SimVar.GetGlobalVarValue("ZULU TIME", "seconds")); - if (seconds != this.currentSeconds) { - this.currentSeconds = seconds; - const hours = Math.floor(seconds / 3600); - const minutes = Math.floor((seconds - (hours * 3600)) / 60); - if (minutes != this.currentMinutes) { - this.currentMinutes = minutes; - if (this.hoursText != null) { - this.hoursText.textContent = hours.toString().padStart(2, "0"); - } - if (this.minutesText != null) { - this.minutesText.textContent = minutes.toString().padStart(2, "0"); - } - } - } - } - refreshGrossWeight(_force = false) { - const isOneEngineRunning = SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:1", "Number") >= 15 || SimVar.GetSimVarValue("L:A32NX_ENGINE_N1:2", "Number") >= 15; //BASED ON IRL REFERENCE - const gw = Math.round(NXUnits.kgToUser(SimVar.GetSimVarValue("L:A32NX_FM_GROSS_WEIGHT", "number") * 1000)); - const gwUnit = NXUnits.userWeightUnit(); - if ((gw != this.currentGW) || (this.isOneEngineRunning != isOneEngineRunning) || _force) { - this.currentGW = gw; - this.isOneEngineRunning = isOneEngineRunning; - - if (isOneEngineRunning && this.currentGW != 0) { - // Lower EICAS displays GW in increments of 100 - this.gwValue.classList.add("Value"); - this.gwValue.classList.remove("Cyan"); - this.gwValue.textContent = (Math.floor(this.currentGW / 100) * 100).toString(); - } else { - this.gwValue.classList.remove("Value"); - this.gwValue.classList.add("Cyan"); - this.gwValue.textContent = "--"; - } - } - if (gwUnit != this.currentGwUnit) { - this.currentGwUnit = gwUnit; - if (this.gwUnit != null) { - this.gwUnit.textContent = gwUnit; - } - } - } -} -customElements.define("eicas-common-display", EICASCommonDisplay); From e83f98b80f138cacfca25e1a255427c147723202 Mon Sep 17 00:00:00 2001 From: markszutor Date: Tue, 27 Feb 2024 20:48:25 +0200 Subject: [PATCH 15/16] refactor: Move flyPad to fbw-common (#8473) - part 1 --- .../src/systems/sentry-client/src/index.ts | 8 +- .../src/systems/sentry-client/src/index.ts | 8 +- .../src/systems/sentry-client/src/index.ts | 8 +- .../src/systems/sentry-client/src/index.ts | 8 +- .../src/systems/instruments/src/EFB/index.tsx | 89 +++---------------- 5 files changed, 34 insertions(+), 87 deletions(-) diff --git a/hsim-a318ceo/src/systems/sentry-client/src/index.ts b/hsim-a318ceo/src/systems/sentry-client/src/index.ts index bdc000fd..1e8c9738 100644 --- a/hsim-a318ceo/src/systems/sentry-client/src/index.ts +++ b/hsim-a318ceo/src/systems/sentry-client/src/index.ts @@ -1,10 +1,14 @@ -import { FbwAircraftSentryClient } from './FbwAircraftSentryClient'; +// Copyright (c) 2021-2023 FlyByWire Simulations +// +// SPDX-License-Identifier: GPL-3.0 + +import { FbwAircraftSentryClient } from '@flybywiresim/fbw-sdk'; declare const process: any; new FbwAircraftSentryClient().onInstrumentLoaded({ dsn: process.env.SENTRY_DSN, - buildInfoFilePrefix: 'A318HS', + buildInfoFilePrefix: 'a318hs', root: false, enableTracing: false, }); diff --git a/hsim-a319ceo/src/systems/sentry-client/src/index.ts b/hsim-a319ceo/src/systems/sentry-client/src/index.ts index e92743d6..45ad10eb 100644 --- a/hsim-a319ceo/src/systems/sentry-client/src/index.ts +++ b/hsim-a319ceo/src/systems/sentry-client/src/index.ts @@ -1,10 +1,14 @@ -import { FbwAircraftSentryClient } from './FbwAircraftSentryClient'; +// Copyright (c) 2021-2023 FlyByWire Simulations +// +// SPDX-License-Identifier: GPL-3.0 + +import { FbwAircraftSentryClient } from '@flybywiresim/fbw-sdk'; declare const process: any; new FbwAircraftSentryClient().onInstrumentLoaded({ dsn: process.env.SENTRY_DSN, - buildInfoFilePrefix: 'A319HS', + buildInfoFilePrefix: 'a319hs', root: false, enableTracing: false, }); diff --git a/hsim-a320ceo/src/systems/sentry-client/src/index.ts b/hsim-a320ceo/src/systems/sentry-client/src/index.ts index 1f7d17ab..a0fa6bff 100644 --- a/hsim-a320ceo/src/systems/sentry-client/src/index.ts +++ b/hsim-a320ceo/src/systems/sentry-client/src/index.ts @@ -1,10 +1,14 @@ -import { FbwAircraftSentryClient } from './FbwAircraftSentryClient'; +// Copyright (c) 2021-2023 FlyByWire Simulations +// +// SPDX-License-Identifier: GPL-3.0 + +import { FbwAircraftSentryClient } from '@flybywiresim/fbw-sdk'; declare const process: any; new FbwAircraftSentryClient().onInstrumentLoaded({ dsn: process.env.SENTRY_DSN, - buildInfoFilePrefix: 'A320HS', + buildInfoFilePrefix: 'a320hs', root: false, enableTracing: false, }); diff --git a/hsim-a321neo/src/systems/sentry-client/src/index.ts b/hsim-a321neo/src/systems/sentry-client/src/index.ts index 3cd4deab..eaa72df1 100644 --- a/hsim-a321neo/src/systems/sentry-client/src/index.ts +++ b/hsim-a321neo/src/systems/sentry-client/src/index.ts @@ -1,10 +1,14 @@ -import { FbwAircraftSentryClient } from './FbwAircraftSentryClient'; +// Copyright (c) 2021-2023 FlyByWire Simulations +// +// SPDX-License-Identifier: GPL-3.0 + +import { FbwAircraftSentryClient } from '@flybywiresim/fbw-sdk'; declare const process: any; new FbwAircraftSentryClient().onInstrumentLoaded({ dsn: process.env.SENTRY_DSN, - buildInfoFilePrefix: 'A21NHS', + buildInfoFilePrefix: 'a21nhs', root: false, enableTracing: false, }); diff --git a/hsim-common/src/systems/instruments/src/EFB/index.tsx b/hsim-common/src/systems/instruments/src/EFB/index.tsx index 7ddf15ea..e7874b97 100644 --- a/hsim-common/src/systems/instruments/src/EFB/index.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/index.tsx @@ -1,85 +1,15 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 -/* eslint-disable max-len */ -import React, { useState, useEffect } from 'react'; -import { MemoryRouter as Router } from 'react-router-dom'; +import React from 'react'; +import { NXDataStore } from '@flybywiresim/fbw-sdk'; + import { customAlphabet } from 'nanoid'; -import { NXDataStore, usePersistentProperty } from '@flybywiresim/fbw-sdk'; -import { Provider } from 'react-redux'; import { render } from '@instruments/common/index'; -import { ErrorBoundary } from 'react-error-boundary'; -import { SentryConsentState, SENTRY_CONSENT_KEY } from '@sentry/FbwAircraftSentryClient'; -import { ModalProvider } from './UtilComponents/Modals/Modals'; -import { FailuresOrchestratorProvider } from './failures-orchestrator-provider'; -import Efb from './Efb'; - -import './Assets/Efb.scss'; -import './Assets/Theme.css'; -import './Assets/Slider.scss'; -import { readSettingsFromPersistentStorage } from './Settings/sync'; -import { migrateSettings } from './Settings/Migration'; -import { store } from './Store/store'; -import { Error } from './Assets/Error'; - -const EFBLoad = () => { - const [, setSessionId] = usePersistentProperty('A32NX_SENTRY_SESSION_ID'); - - useEffect( - () => () => setSessionId(''), [], - ); +import { readSettingsFromPersistentStorage, migrateSettings, EfbInstrument } from '@flybywiresim/flypad'; +import { A320FailureDefinitions } from '@failures'; - const [err, setErr] = useState(false); - - return ( - setErr(false)} resetKeys={[err]}> - - - - - - - - - ); -}; - -interface ErrorFallbackProps { - resetErrorBoundary: (...args: Array) => void; -} - -export const ErrorFallback = ({ resetErrorBoundary }: ErrorFallbackProps) => { - const [sessionId] = usePersistentProperty('A32NX_SENTRY_SESSION_ID'); - const [sentryEnabled] = usePersistentProperty(SENTRY_CONSENT_KEY, SentryConsentState.Refused); - - return ( -
-
- -
-

A critical error has been encountered.

- -

You are able to reset this tablet to recover from this error.

- - {sentryEnabled === SentryConsentState.Given && ( - <> -

- You have opted into anonymous error reporting and this issue has been relayed to us. If you want immediate support, please share the following code to a member of staff in the #support channel on the FlyByWire Discord server: -

- -

{sessionId}

- - )} - -
-

Reset Display

-
-
-
-
- ); -}; +// TODO move all of this to fbw-common somehow const setSessionId = () => { const ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; @@ -108,6 +38,7 @@ if (process.env.VITE_BUILD) { } render( - , - true, true, + , + true, + true, ); From 79d4f3aff93e30d70cd53a3ec554305ea95b0bd3 Mon Sep 17 00:00:00 2001 From: Robin Breitfeld Date: Tue, 27 Feb 2024 22:08:36 +0100 Subject: [PATCH 16/16] refactor: Refactor pushback for multi aircraft and tune for A320/A380 (#8465), fix(EFB): Missing translation function calls --- .github/workflows/dev.yml | 16 +- .github/workflows/eval.yml | 16 +- .github/workflows/main.yml | 16 +- .github/workflows/release.yml | 16 +- CMakeLists.txt | 4 +- Cargo.toml | 6 +- Cargo_a321.toml | 2 +- hsim-a21n-common/src/systems/tsconfig.json | 13 +- hsim-a318-common/src/systems/tsconfig.json | 13 +- hsim-a318ceo/mach.config.js | 2 +- .../wasm/extra-backend-a32nx/CMakeLists.txt | 8 +- hsim-a319-common/src/systems/tsconfig.json | 13 +- hsim-a319ceo/mach.config.js | 2 +- .../wasm/extra-backend-a32nx/CMakeLists.txt | 8 +- hsim-a320-common/src/systems/tsconfig.json | 13 +- hsim-a320ceo/mach.config.js | 2 +- .../wasm/extra-backend-a32nx/CMakeLists.txt | 8 +- .../wasm/systems/a320_systems/src/fuel/mod.rs | 1 + hsim-a321neo/mach.config.js | 2 +- .../wasm/extra-backend-a32nx/CMakeLists.txt | 8 +- .../wasm/systems/a320_systems/src/fuel/mod.rs | 1 + .../src/EFB/Assets/GroundServiceOutline.tsx | 403 +++++++++ .../src/systems/instruments/src/EFB/Efb.tsx | 148 +++- .../instruments/src/EFB/Ground/Ground.tsx | 28 +- .../Pages/Payload/A21N_251N/A21NPayload.tsx | 49 +- .../Pages/Payload/A21N_251NX/A21NPayload.tsx | 49 +- .../Payload/A21N_251N_LR/A21NPayload.tsx | 49 +- .../Pages/Payload/A21N_271N/A21NPayload.tsx | 49 +- .../Pages/Payload/A21N_271NX/A21NPayload.tsx | 49 +- .../Payload/A21N_271N_LR/A21NPayload.tsx | 19 +- .../Pages/Payload/A318_115/A318Payload.tsx | 49 +- .../Pages/Payload/A318_ACJ/A318Payload.tsx | 49 +- .../Pages/Payload/A318_BAW/A318Payload.tsx | 49 +- .../Pages/Payload/A319_115/A319Payload.tsx | 49 +- .../Payload/A319_115_ACJ/A319Payload.tsx | 49 +- .../Pages/Payload/A319_133/A319Payload.tsx | 49 +- .../Payload/A319_133_ACJ/A319Payload.tsx | 49 +- .../Pages/Payload/A320_214/A320Payload.tsx | 49 +- .../Pages/Payload/A320_214_SL/A320Payload.tsx | 49 +- .../Pages/Payload/A320_232/A320Payload.tsx | 49 +- .../Pages/Payload/A320_232_SL/A320Payload.tsx | 49 +- .../Ground/Pages/Payload/PayloadElements.tsx | 80 +- .../src/EFB/Ground/Pages/PushbackMap.tsx | 118 +-- .../src/EFB/Ground/Pages/PushbackPage.tsx | 185 ++--- .../Pages/Services/A318_100/A318Services.tsx | 38 +- .../Pages/Services/A319_100/A319Services.tsx | 38 +- .../Pages/Services/A320_200/A320Services.tsx | 39 +- .../Pages/Services/A321_200/A321Services.tsx | 38 +- .../Calculators/CommonCalculations.ts | 11 - .../Calculators/LandingCalculator.ts | 772 ------------------ .../src/EFB/Performance/Performance.tsx | 11 +- .../EFB/Performance/Widgets/LandingWidget.tsx | 748 ----------------- .../Widgets/RunwayVisualizationWidget.tsx | 184 ----- .../src/EFB/Settings/Pages/AboutPage.tsx | 18 +- .../Pages/AircraftOptionsPinProgramsPage.tsx | 221 ----- .../src/EFB/Settings/Pages/FlyPadPage.tsx | 190 ----- .../src/EFB/Settings/Pages/SimOptionsPage.tsx | 11 +- .../instruments/src/EFB/Settings/sync.ts | 64 -- .../src/EFB/StatusBar/StatusBar.tsx | 174 ---- .../instruments/src/EFB/ToolBar/ToolBar.tsx | 19 +- .../src/systems/instruments/src/EFB/index.tsx | 44 - .../shared/src/AircraftVersionChecker.ts | 279 +++++++ .../systems/shared/src/aircraftTypeCheck.ts | 23 + jsconfig.json | 5 +- package.json | 10 +- 65 files changed, 1652 insertions(+), 3220 deletions(-) delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/CommonCalculations.ts delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/LandingCalculator.ts delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/LandingWidget.tsx delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/RunwayVisualizationWidget.tsx delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AircraftOptionsPinProgramsPage.tsx delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Settings/Pages/FlyPadPage.tsx delete mode 100644 hsim-common/src/systems/instruments/src/EFB/Settings/sync.ts delete mode 100644 hsim-common/src/systems/instruments/src/EFB/StatusBar/StatusBar.tsx delete mode 100644 hsim-common/src/systems/instruments/src/EFB/index.tsx create mode 100644 hsim-common/src/systems/shared/src/AircraftVersionChecker.ts create mode 100644 hsim-common/src/systems/shared/src/aircraftTypeCheck.ts diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 75ada8d2..8466dab0 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -11,7 +11,7 @@ jobs: build-a318: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vdev @@ -38,7 +38,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a318ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a318ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a318ceo/.env @@ -84,7 +84,7 @@ jobs: build-a319: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vdev @@ -111,7 +111,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a319ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a319ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a319ceo/.env @@ -157,7 +157,7 @@ jobs: build-a320: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vdev @@ -184,7 +184,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a320ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a320ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a320ceo/.env @@ -230,7 +230,7 @@ jobs: build-a321: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vdev @@ -257,7 +257,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a321neo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a321neo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a321neo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a321neo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a321neo/.env diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index a778ca18..35eb1b31 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -8,7 +8,7 @@ jobs: build-a318: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -33,7 +33,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a318ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a318ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a318ceo/.env @@ -76,7 +76,7 @@ jobs: build-a319: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -101,7 +101,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a319ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a319ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a319ceo/.env @@ -144,7 +144,7 @@ jobs: build-a320: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -169,7 +169,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a320ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a320ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a320ceo/.env @@ -212,7 +212,7 @@ jobs: build-a321: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -237,7 +237,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a321neo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a321neo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a321neo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a321neo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a321neo/.env diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 46d54af5..610df296 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: build-a318: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -35,7 +35,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a318ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a318ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a318ceo/.env @@ -86,7 +86,7 @@ jobs: build-a319: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -113,7 +113,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a319ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a319ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a319ceo/.env @@ -164,7 +164,7 @@ jobs: build-a320: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -191,7 +191,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a320ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a320ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a320ceo/.env @@ -242,7 +242,7 @@ jobs: build-a321: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vmain @@ -269,7 +269,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a321neo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a321neo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a321neo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a321neo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a321neo/.env diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4ed34639..8fa381fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: build-a318: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vstable @@ -38,7 +38,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a318ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a318ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a318ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a318ceo/.env @@ -84,7 +84,7 @@ jobs: build-a319: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vstable @@ -111,7 +111,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a319ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a319ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a319ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a319ceo/.env @@ -157,7 +157,7 @@ jobs: build-a320: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vstable @@ -184,7 +184,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a320ceo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a320ceo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a320ceo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a320ceo/.env @@ -230,7 +230,7 @@ jobs: build-a321: runs-on: ubuntu-latest env: - A32NX_PRODUCTION_BUILD: 1 + FBW_PRODUCTION_BUILD: 1 A32NX_INSTRUMENTS_BUILD_WORKERS: 2 PRE_RELEASE_ID: 64125785 PRE_RELEASE_TAG: vstable @@ -257,7 +257,7 @@ jobs: run: echo "BUILT_DATE_TIME=$(date -u -Iseconds)" >> $GITHUB_ENV - name: Create .env file run: | - echo A32NX_PRODUCTION_BUILD=1 >> hsim-a321neo/.env + echo FBW_PRODUCTION_BUILD=1 >> hsim-a321neo/.env echo CLIENT_ID=\"${{ secrets.NAVIGRAPH_CLIENT_ID }}\" >> hsim-a321neo/.env echo CLIENT_SECRET=\"${{ secrets.NAVIGRAPH_CLIENT_SECRET }}\" >> hsim-a321neo/.env echo SENTRY_DSN=\"${{ secrets.SENTRY_DSN }}\" >> hsim-a321neo/.env diff --git a/CMakeLists.txt b/CMakeLists.txt index c6952106..3022c6f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,5 +52,5 @@ add_definitions( # add the common components add_subdirectory(fbw-common/src/wasm) -# add the A318 components -add_subdirectory(build-a318ceo/src/wasm) +# add the A321 components +add_subdirectory(build-a321neo/src/wasm) diff --git a/Cargo.toml b/Cargo.toml index 21b46ebf..95eab9f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,9 @@ resolver = "2" exclude = ["a32nx"] members = [ - "build-a318ceo/src/wasm/systems/a320_systems", - "build-a318ceo/src/wasm/systems/a320_systems_wasm", - "build-a318ceo/src/wasm/systems/a320_hydraulic_simulation_graphs", + "build-a321neo/src/wasm/systems/a320_systems", + "build-a321neo/src/wasm/systems/a320_systems_wasm", + "build-a321neo/src/wasm/systems/a320_hydraulic_simulation_graphs", "fbw-common/src/wasm/systems/systems", "fbw-common/src/wasm/systems/systems_wasm", ] diff --git a/Cargo_a321.toml b/Cargo_a321.toml index 95eab9f2..1377daed 100644 --- a/Cargo_a321.toml +++ b/Cargo_a321.toml @@ -20,4 +20,4 @@ strip = true opt-level=1 lto = false debug-assertions=true -debug=true \ No newline at end of file +debug=true diff --git a/hsim-a21n-common/src/systems/tsconfig.json b/hsim-a21n-common/src/systems/tsconfig.json index 6ba5e014..5f5a1615 100644 --- a/hsim-a21n-common/src/systems/tsconfig.json +++ b/hsim-a21n-common/src/systems/tsconfig.json @@ -11,14 +11,15 @@ "jsx": "react", "skipLibCheck": true, "paths": { - "@datalink/aoc": ["datalink/aoc/src/index.ts"], - "@datalink/atc": ["datalink/atc/src/index.ts"], - "@datalink/common": ["datalink/common/src/index.ts"], - "@datalink/router": ["datalink/router/src/index.ts"], +// "@datalink/aoc": ["datalink/aoc/src/index.ts"], +// "@datalink/atc": ["datalink/atc/src/index.ts"], +// "@datalink/common": ["datalink/common/src/index.ts"], +// "@datalink/router": ["datalink/router/src/index.ts"], "@fmgc/*": ["../../../build-a321neo/src/systems/fmgc/src/*"], "@shared/*": ["../../../build-a321neo/src/systems/shared/src/*"], "@typings/*": ["../typings/*"], - "@flybywiresim/fbw-sdk": ["./index.ts"] + "@flybywiresim/fbw-sdk": ["./index.ts"], + "@flybywiresim/flypad": ["./instruments/src/EFB/index.ts"] } } -} \ No newline at end of file +} diff --git a/hsim-a318-common/src/systems/tsconfig.json b/hsim-a318-common/src/systems/tsconfig.json index 8783fed5..71e5196e 100644 --- a/hsim-a318-common/src/systems/tsconfig.json +++ b/hsim-a318-common/src/systems/tsconfig.json @@ -11,14 +11,15 @@ "jsx": "react", "skipLibCheck": true, "paths": { - "@datalink/aoc": ["datalink/aoc/src/index.ts"], - "@datalink/atc": ["datalink/atc/src/index.ts"], - "@datalink/common": ["datalink/common/src/index.ts"], - "@datalink/router": ["datalink/router/src/index.ts"], +// "@datalink/aoc": ["datalink/aoc/src/index.ts"], +// "@datalink/atc": ["datalink/atc/src/index.ts"], +// "@datalink/common": ["datalink/common/src/index.ts"], +// "@datalink/router": ["datalink/router/src/index.ts"], "@fmgc/*": ["../../../build-a318ceo/src/systems/fmgc/src/*"], "@shared/*": ["../../../build-a318ceo/src/systems/shared/src/*"], "@typings/*": ["../typings/*"], - "@flybywiresim/fbw-sdk": ["./index.ts"] + "@flybywiresim/fbw-sdk": ["./index.ts"], + "@flybywiresim/flypad": ["./instruments/src/EFB/index.ts"] } } -} \ No newline at end of file +} diff --git a/hsim-a318ceo/mach.config.js b/hsim-a318ceo/mach.config.js index 8861241d..7a0a5da6 100644 --- a/hsim-a318ceo/mach.config.js +++ b/hsim-a318ceo/mach.config.js @@ -17,7 +17,7 @@ module.exports = { extract: true, postcss: { plugins: [ - tailwind('src/systems/instruments/src/EFB/tailwind.config.js'), + tailwind('../fbw-common/src/systems/instruments/src/EFB/tailwind.config.js'), // transform: hsl(x y z / alpha) -> hsl(x, y, z, alpha) postCssColorFunctionalNotation(), diff --git a/hsim-a318ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt b/hsim-a318ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt index df486a56..99ef239a 100644 --- a/hsim-a318ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt +++ b/hsim-a318ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback ${FBW_COMMON}/cpp-msfs-framework/ ${FBW_COMMON}/extra-backend/ ) @@ -16,14 +17,17 @@ include_directories( set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Gauge_Extra_Backend.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.cpp ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.cpp ${FBW_COMMON}/extra-backend/Pushback/Pushback.cpp ${FBW_COMMON}/extra-backend/AircraftPresets/AircraftPresets.cpp ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.cpp - ) +) + set(INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets/AircraftPresetProcedures_A32NX.h ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.h ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.h ${FBW_COMMON}/cpp-msfs-framework/Example/longtext.h ${FBW_COMMON}/extra-backend/Pushback/InertialDampener.hpp @@ -32,7 +36,7 @@ set(INCLUDE_FILES ${FBW_COMMON}/extra-backend/AircraftPresets/PresetProcedures.h ${FBW_COMMON}/extra-backend/AircraftPresets/ProcedureStep.h ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.h - ) +) # create the targets add_library(extra-backend-a32nx OBJECT ${SOURCE_FILES} ${INCLUDE_FILES}) diff --git a/hsim-a319-common/src/systems/tsconfig.json b/hsim-a319-common/src/systems/tsconfig.json index d374a6da..a246d9e3 100644 --- a/hsim-a319-common/src/systems/tsconfig.json +++ b/hsim-a319-common/src/systems/tsconfig.json @@ -11,14 +11,15 @@ "jsx": "react", "skipLibCheck": true, "paths": { - "@datalink/aoc": ["datalink/aoc/src/index.ts"], - "@datalink/atc": ["datalink/atc/src/index.ts"], - "@datalink/common": ["datalink/common/src/index.ts"], - "@datalink/router": ["datalink/router/src/index.ts"], +// "@datalink/aoc": ["datalink/aoc/src/index.ts"], +// "@datalink/atc": ["datalink/atc/src/index.ts"], +// "@datalink/common": ["datalink/common/src/index.ts"], +// "@datalink/router": ["datalink/router/src/index.ts"], "@fmgc/*": ["../../../build-a319ceo/src/systems/fmgc/src/*"], "@shared/*": ["../../../build-a319ceo/src/systems/shared/src/*"], "@typings/*": ["../typings/*"], - "@flybywiresim/fbw-sdk": ["./index.ts"] + "@flybywiresim/fbw-sdk": ["./index.ts"], + "@flybywiresim/flypad": ["./instruments/src/EFB/index.ts"] } } -} \ No newline at end of file +} diff --git a/hsim-a319ceo/mach.config.js b/hsim-a319ceo/mach.config.js index 6df2b07d..f082dfdb 100644 --- a/hsim-a319ceo/mach.config.js +++ b/hsim-a319ceo/mach.config.js @@ -17,7 +17,7 @@ module.exports = { extract: true, postcss: { plugins: [ - tailwind('src/systems/instruments/src/EFB/tailwind.config.js'), + tailwind('../fbw-common/src/systems/instruments/src/EFB/tailwind.config.js'), // transform: hsl(x y z / alpha) -> hsl(x, y, z, alpha) postCssColorFunctionalNotation(), diff --git a/hsim-a319ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt b/hsim-a319ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt index df486a56..99ef239a 100644 --- a/hsim-a319ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt +++ b/hsim-a319ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback ${FBW_COMMON}/cpp-msfs-framework/ ${FBW_COMMON}/extra-backend/ ) @@ -16,14 +17,17 @@ include_directories( set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Gauge_Extra_Backend.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.cpp ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.cpp ${FBW_COMMON}/extra-backend/Pushback/Pushback.cpp ${FBW_COMMON}/extra-backend/AircraftPresets/AircraftPresets.cpp ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.cpp - ) +) + set(INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets/AircraftPresetProcedures_A32NX.h ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.h ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.h ${FBW_COMMON}/cpp-msfs-framework/Example/longtext.h ${FBW_COMMON}/extra-backend/Pushback/InertialDampener.hpp @@ -32,7 +36,7 @@ set(INCLUDE_FILES ${FBW_COMMON}/extra-backend/AircraftPresets/PresetProcedures.h ${FBW_COMMON}/extra-backend/AircraftPresets/ProcedureStep.h ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.h - ) +) # create the targets add_library(extra-backend-a32nx OBJECT ${SOURCE_FILES} ${INCLUDE_FILES}) diff --git a/hsim-a320-common/src/systems/tsconfig.json b/hsim-a320-common/src/systems/tsconfig.json index c79ebe25..3db3356d 100644 --- a/hsim-a320-common/src/systems/tsconfig.json +++ b/hsim-a320-common/src/systems/tsconfig.json @@ -11,14 +11,15 @@ "jsx": "react", "skipLibCheck": true, "paths": { - "@datalink/aoc": ["datalink/aoc/src/index.ts"], - "@datalink/atc": ["datalink/atc/src/index.ts"], - "@datalink/common": ["datalink/common/src/index.ts"], - "@datalink/router": ["datalink/router/src/index.ts"], +// "@datalink/aoc": ["datalink/aoc/src/index.ts"], +// "@datalink/atc": ["datalink/atc/src/index.ts"], +// "@datalink/common": ["datalink/common/src/index.ts"], +// "@datalink/router": ["datalink/router/src/index.ts"], "@fmgc/*": ["../../../build-a320ceo/src/systems/fmgc/src/*"], "@shared/*": ["../../../build-a320ceo/src/systems/shared/src/*"], "@typings/*": ["../typings/*"], - "@flybywiresim/fbw-sdk": ["./index.ts"] + "@flybywiresim/fbw-sdk": ["./index.ts"], + "@flybywiresim/flypad": ["./instruments/src/EFB/index.ts"] } } -} \ No newline at end of file +} diff --git a/hsim-a320ceo/mach.config.js b/hsim-a320ceo/mach.config.js index 864c2ec8..cb47bee0 100644 --- a/hsim-a320ceo/mach.config.js +++ b/hsim-a320ceo/mach.config.js @@ -17,7 +17,7 @@ module.exports = { extract: true, postcss: { plugins: [ - tailwind('src/systems/instruments/src/EFB/tailwind.config.js'), + tailwind('../fbw-common/src/systems/instruments/src/EFB/tailwind.config.js'), // transform: hsl(x y z / alpha) -> hsl(x, y, z, alpha) postCssColorFunctionalNotation(), diff --git a/hsim-a320ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt b/hsim-a320ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt index df486a56..99ef239a 100644 --- a/hsim-a320ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt +++ b/hsim-a320ceo/src/wasm/extra-backend-a32nx/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback ${FBW_COMMON}/cpp-msfs-framework/ ${FBW_COMMON}/extra-backend/ ) @@ -16,14 +17,17 @@ include_directories( set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Gauge_Extra_Backend.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.cpp ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.cpp ${FBW_COMMON}/extra-backend/Pushback/Pushback.cpp ${FBW_COMMON}/extra-backend/AircraftPresets/AircraftPresets.cpp ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.cpp - ) +) + set(INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets/AircraftPresetProcedures_A32NX.h ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.h ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.h ${FBW_COMMON}/cpp-msfs-framework/Example/longtext.h ${FBW_COMMON}/extra-backend/Pushback/InertialDampener.hpp @@ -32,7 +36,7 @@ set(INCLUDE_FILES ${FBW_COMMON}/extra-backend/AircraftPresets/PresetProcedures.h ${FBW_COMMON}/extra-backend/AircraftPresets/ProcedureStep.h ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.h - ) +) # create the targets add_library(extra-backend-a32nx OBJECT ${SOURCE_FILES} ${INCLUDE_FILES}) diff --git a/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs b/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs index d07a22ad..5d95b398 100644 --- a/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs +++ b/hsim-a320ceo/src/wasm/systems/a320_systems/src/fuel/mod.rs @@ -82,6 +82,7 @@ impl A320Fuel { context, f.fuel_tank_id, Vector3::new(f.position.0, f.position.1, f.position.2), + false, ) }); A320Fuel { diff --git a/hsim-a321neo/mach.config.js b/hsim-a321neo/mach.config.js index 102fe215..235bd054 100644 --- a/hsim-a321neo/mach.config.js +++ b/hsim-a321neo/mach.config.js @@ -17,7 +17,7 @@ module.exports = { extract: true, postcss: { plugins: [ - tailwind('src/systems/instruments/src/EFB/tailwind.config.js'), + tailwind('../fbw-common/src/systems/instruments/src/EFB/tailwind.config.js'), // transform: hsl(x y z / alpha) -> hsl(x, y, z, alpha) postCssColorFunctionalNotation(), diff --git a/hsim-a321neo/src/wasm/extra-backend-a32nx/CMakeLists.txt b/hsim-a321neo/src/wasm/extra-backend-a32nx/CMakeLists.txt index df486a56..99ef239a 100644 --- a/hsim-a321neo/src/wasm/extra-backend-a32nx/CMakeLists.txt +++ b/hsim-a321neo/src/wasm/extra-backend-a32nx/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback ${FBW_COMMON}/cpp-msfs-framework/ ${FBW_COMMON}/extra-backend/ ) @@ -16,14 +17,17 @@ include_directories( set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Gauge_Extra_Backend.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.cpp ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.cpp ${FBW_COMMON}/extra-backend/Pushback/Pushback.cpp ${FBW_COMMON}/extra-backend/AircraftPresets/AircraftPresets.cpp ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.cpp - ) +) + set(INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/AircraftPresets/AircraftPresetProcedures_A32NX.h ${CMAKE_CURRENT_SOURCE_DIR}/src/LightingPresets/LightingPresets_A32NX.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.h ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.h ${FBW_COMMON}/cpp-msfs-framework/Example/longtext.h ${FBW_COMMON}/extra-backend/Pushback/InertialDampener.hpp @@ -32,7 +36,7 @@ set(INCLUDE_FILES ${FBW_COMMON}/extra-backend/AircraftPresets/PresetProcedures.h ${FBW_COMMON}/extra-backend/AircraftPresets/ProcedureStep.h ${FBW_COMMON}/extra-backend/LightingPresets/LightingPresets.h - ) +) # create the targets add_library(extra-backend-a32nx OBJECT ${SOURCE_FILES} ${INCLUDE_FILES}) diff --git a/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs b/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs index 264e2dea..55f12c32 100644 --- a/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs +++ b/hsim-a321neo/src/wasm/systems/a320_systems/src/fuel/mod.rs @@ -82,6 +82,7 @@ impl A320Fuel { context, f.fuel_tank_id, Vector3::new(f.position.0, f.position.1, f.position.2), + false, ) }); A320Fuel { diff --git a/hsim-common/src/systems/instruments/src/EFB/Assets/GroundServiceOutline.tsx b/hsim-common/src/systems/instruments/src/EFB/Assets/GroundServiceOutline.tsx index cd23bd54..234ad694 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Assets/GroundServiceOutline.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Assets/GroundServiceOutline.tsx @@ -1,3 +1,6 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + /* eslint-disable max-len */ import * as React from 'react'; // viewBox="0 0 777 814" @@ -620,3 +623,403 @@ export const GroundServiceOutline = ({ className, cabinLeftStatus, cabinRightSta ); + +export const A380GroundServiceOutline = ({ className, main1LeftStatus, main2LeftStatus, main4RightStatus, upper1LeftStatus }: {className: string, main1LeftStatus: boolean, main2LeftStatus: boolean, main4RightStatus: boolean, upper1LeftStatus: boolean}) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/hsim-common/src/systems/instruments/src/EFB/Efb.tsx b/hsim-common/src/systems/instruments/src/EFB/Efb.tsx index 1860495b..174d9ca7 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Efb.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Efb.tsx @@ -1,33 +1,52 @@ -// Copyright (c) 2022 FlyByWire Simulations +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 +import { + FailureDefinition, + NavigraphClient, + SENTRY_CONSENT_KEY, + SentryConsentState, + useInteractionEvent, + useInterval, + usePersistentNumberProperty, usePersistentProperty, + useSimVar, +} from '@flybywiresim/fbw-sdk'; +import { distanceTo } from 'msfs-geo'; import React, { useEffect, useState } from 'react'; -import { useSimVar, useInterval, useInteractionEvent, usePersistentNumberProperty, usePersistentProperty, NavigraphClient } from '@flybywiresim/fbw-sdk'; -import { Redirect, Route, Switch, useHistory } from 'react-router-dom'; import { Battery } from 'react-bootstrap-icons'; -import { ToastContainer } from 'react-toastify'; -import { distanceTo } from 'msfs-geo'; -import { Tooltip } from './UtilComponents/TooltipWrapper'; -import { HSLogo } from './UtilComponents/HSLogo'; -import { AlertModal, ModalContainer, useModals } from './UtilComponents/Modals/Modals'; +import { ErrorBoundary } from 'react-error-boundary'; +import { Provider } from 'react-redux'; +import { MemoryRouter as Router } from 'react-router'; +import { Redirect, Route, Switch, useHistory } from 'react-router-dom'; +import { ToastContainer, toast } from 'react-toastify'; +import { ATC } from './ATC/ATC'; import { NavigraphContext } from './Apis/Navigraph/Navigraph'; -import { StatusBar } from './StatusBar/StatusBar'; -import { ToolBar } from './ToolBar/ToolBar'; +import { Error as ErrorIcon } from './Assets/Error'; +import { Checklists, setAutomaticItemStates } from './Checklists/Checklists'; +import { CHECKLISTS } from './Checklists/Lists'; import { Dashboard } from './Dashboard/Dashboard'; import { Dispatch } from './Dispatch/Dispatch'; +import { Failures } from './Failures/Failures'; import { Ground } from './Ground/Ground'; -import { Performance } from './Performance/Performance'; import { Navigation } from './Navigation/Navigation'; -import { ATC } from './ATC/ATC'; -import { Settings } from './Settings/Settings'; -import { Failures } from './Failures/Failures'; +import { Performance } from './Performance/Performance'; import { Presets } from './Presets/Presets'; -import { clearEfbState, useAppDispatch, useAppSelector } from './Store/store'; -import { setFlightPlanProgress } from './Store/features/flightProgress'; -import { Checklists, setAutomaticItemStates } from './Checklists/Checklists'; -import { CHECKLISTS } from './Checklists/Lists'; -import { setChecklistItems } from './Store/features/checklists'; import { FlyPadPage } from './Settings/Pages/FlyPadPage'; +import { Settings } from './Settings/Settings'; +import { StatusBar } from './StatusBar/StatusBar'; +import { setChecklistItems } from './Store/features/checklists'; +import { setFlightPlanProgress } from './Store/features/flightProgress'; +import { fetchSimbriefDataAction, isSimbriefDataLoaded } from './Store/features/simBrief'; +import { clearEfbState, store, useAppDispatch, useAppSelector } from './Store/store'; +import { ToolBar } from './ToolBar/ToolBar'; +import { HSLogo } from './UtilComponents/HSLogo'; +import { AlertModal, ModalContainer, ModalProvider, useModals } from './UtilComponents/Modals/Modals'; +import { Tooltip } from './UtilComponents/TooltipWrapper'; +import { FailuresOrchestratorProvider } from './failures-orchestrator-provider'; + +import './Assets/Efb.scss'; +import './Assets/Slider.scss'; +import './Assets/Theme.css'; import 'react-toastify/dist/ReactToastify.css'; import './toast.css'; @@ -36,13 +55,13 @@ const BATTERY_DURATION_CHARGE_MIN = 180; const BATTERY_DURATION_DISCHARGE_MIN = 540; const LoadingScreen = () => ( -
+
); const EmptyBatteryScreen = () => ( -
+
); @@ -71,9 +90,12 @@ interface BatteryStatus { export const usePower = () => React.useContext(PowerContext); -export const getAirframeType = () => new URL(document.querySelectorAll('vcockpit-panel > *')[0].getAttribute('url')).searchParams.get('Airframe'); +// this returns either `A380_842` or `A320_251N` depending on the aircraft +export const getAirframeType = () => new URL( + document.querySelectorAll('vcockpit-panel > *')[0].getAttribute('url'), +).searchParams.get('Airframe'); -const Efb = () => { +export const Efb = () => { const [powerState, setPowerState] = useState(PowerStates.SHUTOFF); const [absoluteTime] = useSimVar('E:ABSOLUTE TIME', 'seconds', 5000); const [, setBrightness] = useSimVar('L:A32NX_EFB_BRIGHTNESS', 'number'); @@ -84,6 +106,10 @@ const Efb = () => { const [navigraph] = useState(() => new NavigraphClient()); const dispatch = useAppDispatch(); + const simbriefData = useAppSelector((state) => state.simbrief.data); + const [navigraphUsername] = usePersistentProperty('NAVIGRAPH_USERNAME'); + const [overrideSimBriefUserID] = usePersistentProperty('CONFIG_OVERRIDE_SIMBRIEF_USERID'); + const [autoSimbriefImport] = usePersistentProperty('CONFIG_AUTO_SIMBRIEF_IMPORT'); const [dc2BusIsPowered] = useSimVar('L:A32NX_ELEC_DC_2_BUS_IS_POWERED', 'bool'); const [batteryLevel, setBatteryLevel] = useState({ @@ -193,6 +219,14 @@ const Efb = () => { })); }); } + + if ((!simbriefData || !isSimbriefDataLoaded()) && autoSimbriefImport === 'ENABLED') { + fetchSimbriefDataAction(navigraphUsername ?? '', overrideSimBriefUserID ?? '').then((action) => { + dispatch(action); + }).catch((e) => { + toast.error(e.message); + }); + } } }, [powerState]); @@ -343,4 +377,70 @@ const Efb = () => { } }; -export default Efb; +interface ErrorFallbackProps { + resetErrorBoundary: (...args: Array) => void; +} + +export const ErrorFallback = ({ resetErrorBoundary }: ErrorFallbackProps) => { + const [sessionId] = usePersistentProperty('A32NX_SENTRY_SESSION_ID'); + const [sentryEnabled] = usePersistentProperty(SENTRY_CONSENT_KEY, SentryConsentState.Refused); + + return ( +
+
+ +
+

A critical error has been encountered.

+ +

You are able to reset this tablet to recover from this error.

+ + {sentryEnabled === SentryConsentState.Given && ( + <> +

+ You have opted into anonymous error reporting and this issue has been relayed to us. If you want immediate support, + please share the following code to a member of staff in the #support channel on the FlyByWire Discord server: +

+ +

{sessionId}

+ + )} + +
+

Reset Display

+
+
+
+
+ ); +}; + +export interface EfbInstrumentProps { + failures: FailureDefinition[], +} + +export const EfbInstrument: React.FC = ({ failures }) => { + const [, setSessionId] = usePersistentProperty('A32NX_SENTRY_SESSION_ID'); + + useEffect( + () => () => setSessionId(''), [], + ); + + const [err, setErr] = useState(false); + + return ( + + setErr(false)} resetKeys={[err]}> + + + + + + + + + + ); +}; diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Ground.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Ground.tsx index 1b3ec288..eb17a7fd 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Ground.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Ground.tsx @@ -1,24 +1,18 @@ -import React from 'react'; -import { t } from '../translation'; -import { PageLink, PageRedirect, TabRoutes } from '../Utils/routing'; -import { Navbar } from '../UtilComponents/Navbar'; -import { ServicesPage } from './Pages/ServicesPage'; -import { PushbackPage } from './Pages/PushbackPage'; -import { FuelPage } from './Pages/FuelPage'; -import { Payload } from './Pages/Payload/Payload'; +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 -export interface StatefulButton { - id: string, - state: string, - callBack, - value: number, -} +import { Navbar, PageLink, PageRedirect, TabRoutes, t } from '@flybywiresim/flypad'; +import React from 'react'; +import { Fuel } from './Pages/Fuel/Fuel'; +import { PayloadPage } from './Pages/Payload/PayloadPage'; +import { PushbackPage } from './Pages/Pushback/PushbackPage'; +import { ServicesPage } from './Pages/Services/ServicesPage'; export const Ground = () => { const tabs: PageLink[] = [ { name: 'Services', alias: t('Ground.Services.Title'), component: }, - { name: 'Fuel', alias: t('Ground.Fuel.Title'), component: }, - { name: 'Payload', alias: t('Ground.Payload.Title'), component: }, + { name: 'Fuel', alias: t('Ground.Fuel.Title'), component: }, + { name: 'Payload', alias: t('Ground.Payload.Title'), component: }, { name: 'Pushback', alias: t('Ground.Pushback.Title'), component: }, ]; @@ -27,7 +21,7 @@ export const Ground = () => {

{t('Ground.Title')}

diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Payload/A21N_251N/A21NPayload.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Payload/A21N_251N/A21NPayload.tsx index bdbb1840..7d590f24 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Payload/A21N_251N/A21NPayload.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Payload/A21N_251N/A21NPayload.tsx @@ -1,19 +1,20 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + /* eslint-disable max-len */ +import { SeatFlags, Units, usePersistentNumberProperty, usePersistentProperty, useSeatFlags, useSimVar } from '@flybywiresim/fbw-sdk'; +import { Card, PromptModal, SelectGroup, SelectItem, TooltipWrapper, t, useModals } from '@flybywiresim/flypad'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { CloudArrowDown } from 'react-bootstrap-icons'; -import { SeatFlags, Units, usePersistentNumberProperty, usePersistentProperty, useSeatFlags, useSimVar } from '@flybywiresim/fbw-sdk'; -import { SeatOutlineBg } from 'instruments/src/EFB/Assets/SeatOutlineBg'; -import { BoardingInput, MiscParamsInput, PayloadInputTable } from '../PayloadElements'; -import { CargoWidget } from './CargoWidget'; +import { SeatOutlineBg } from '../../../../Assets/SeatOutlineBg'; import { ChartWidget } from '../Chart/ChartWidget'; +import { BoardingInput, MiscParamsInput, PayloadInputTable } from '../PayloadElements'; import { CargoStationInfo, PaxStationInfo } from '../Seating/Constants'; -import { t } from '../../../../translation'; -import { TooltipWrapper } from '../../../../UtilComponents/TooltipWrapper'; +import { CargoWidget } from './CargoWidget'; + import Loadsheet from './a21nwv071.json'; -import Card from '../../../../UtilComponents/Card/Card'; -import { SelectGroup, SelectItem } from '../../../../UtilComponents/Form/Select'; + import { SeatMapWidget } from './SeatMapWidget'; -import { PromptModal, useModals } from '../../../../UtilComponents/Modals/Modals'; interface A320Props { simbriefUnits: string, @@ -493,17 +494,17 @@ export const A21NLEAPPayload: React.FC = ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -567,12 +568,12 @@ export const A21NLEAPPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -616,12 +617,12 @@ export const A21NLEAPPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -567,12 +568,12 @@ export const A21NLEAPFLEXPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -616,12 +617,12 @@ export const A21NLEAPFLEXPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -567,12 +568,12 @@ export const A21NLEAPLRPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -616,12 +617,12 @@ export const A21NLEAPLRPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -567,12 +568,12 @@ export const A21NPWPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -616,12 +617,12 @@ export const A21NPWPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -567,12 +568,12 @@ export const A21NPWFLEXPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -616,12 +617,12 @@ export const A21NPWFLEXPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const A318Payload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const A318Payload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const ACJPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const ACJPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const BAWPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const BAWPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const A319CFMPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const A319CFMPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const A319CFMACJPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const A319CFMACJPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const A319IAEPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const A319IAEPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -559,12 +560,12 @@ export const A319IAEACJPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -608,12 +609,12 @@ export const A319IAEACJPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -565,12 +566,12 @@ export const A320CFMPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -614,12 +615,12 @@ export const A320CFMPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -565,12 +566,12 @@ export const A320CFMSLPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -614,12 +615,12 @@ export const A320CFMSLPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -565,12 +566,12 @@ export const A320IAEPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -614,12 +615,12 @@ export const A320IAEPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({
-
+
-
-
-
- +
+
+
+ = ({ setDisplayZfw={setDisplayZfw} />
-
+
= ({ && (
@@ -565,12 +566,12 @@ export const A320IAESLPayload: React.FC = ({ )}
{(gsxPayloadSyncEnabled !== 1) && ( -
- -
+
+ +
{t('Ground.Payload.BoardingTime')} - + ( {remainingTimeString()} ) @@ -614,12 +615,12 @@ export const A320IAESLPayload: React.FC = ({
)} {gsxPayloadSyncEnabled === 1 && ( -
+
{t('Ground.Payload.GSXPayloadSyncEnabled')}
)}
-
+
= ({ min, max, value, onBlur, unit, disabled }) => (
= ({ min, max, value={value.toFixed(0)} onBlur={onBlur} /> -
{unit}
+
{unit}
); @@ -70,7 +70,7 @@ interface CargoBarProps { export const CargoBar: React.FC = ({ cargoId, cargo, cargoDesired, cargoMap, onClickCargo }) => ( <> -
+
onClickCargo(cargoId, e)}> = ({ }) => ( <> -
+
= ({ if (!Number.isNaN(parseInt(x)) || parseInt(x) === 0) setPaxWeight(Units.userToKilogram(parseInt(x))); }} /> -
{massUnitForDisplay}
+
{massUnitForDisplay}
-
+
= ({ if (!Number.isNaN(parseInt(x)) || parseInt(x) === 0) setBagWeight(Units.userToKilogram(parseInt(x))); }} /> -
{massUnitForDisplay}
+
{massUnitForDisplay}
@@ -168,7 +168,7 @@ export const BoardingInput: React.FC = ({ boardingStatusClas @@ -216,7 +216,7 @@ export const PayloadValueUnitDisplay: React.FC = ({ valu return ( - + {'0'.repeat(leadingZeroCount)} {fixedValue} @@ -231,7 +231,7 @@ export const PayloadPercentUnitDisplay: React.FC<{value: number}> = ({ value }) return ( - + {fixedValue} {' '} @@ -284,15 +284,15 @@ export const PayloadInputTable: React.FC = ( }, ) => ( - + - - - @@ -301,12 +301,12 @@ export const PayloadInputTable: React.FC = ( - - - - - - - - diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackMap.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackMap.tsx index c7123365..26c0160f 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackMap.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackMap.tsx @@ -1,29 +1,25 @@ -// Copyright (c) 2022 FlyByWire Simulations +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 /* eslint-disable max-len */ -import React, { useEffect, useState } from 'react'; -import { useSimVar, MathUtils } from '@flybywiresim/fbw-sdk'; -import { ZoomIn, ZoomOut } from 'react-bootstrap-icons'; +import { MathUtils, useSimVar } from '@flybywiresim/fbw-sdk'; +import { BingMap, TooltipWrapper, t, useAppDispatch, useAppSelector } from '@flybywiresim/flypad'; import { IconPlane } from '@tabler/icons'; -import { Coordinates } from 'msfs-geo'; -import { getAirframeType } from '../../Efb'; -import { AicraftLength } from './Pushback/Constants'; import { computeDestinationPoint, getGreatCircleBearing } from 'geolib'; import getDistance from 'geolib/es/getPreciseDistance'; import { GeolibInputCoordinates } from 'geolib/es/types'; -import { BingMap } from '../../UtilComponents/BingMap'; -import { t } from '../../translation'; -import { TooltipWrapper } from '../../UtilComponents/TooltipWrapper'; -import { useAppDispatch, useAppSelector } from '../../Store/store'; +import { Coordinates } from 'msfs-geo'; +import React, { useEffect, useState } from 'react'; +import { ZoomIn, ZoomOut } from 'react-bootstrap-icons'; +import { getAirframeType } from '../../../Efb'; import { + TScreenCoordinates, setActualMapLatLon, setAircraftIconPosition, setCenterPlaneMode, setMapRange, - TScreenCoordinates, -} from '../../Store/features/pushback'; - +} from '../../../Store/features/pushback'; +import { AicraftLength } from './Pushback/Constants'; interface TurningRadiusIndicatorProps { turningRadius: number; } @@ -46,20 +42,26 @@ const describeArc = (x: number, y: number, radius: number, startAngle: number, e ].join(' '); }; -const TurningRadiusIndicator = ({ turningRadius }: TurningRadiusIndicatorProps) => ( - - - -); +const TurningRadiusIndicator = ({ turningRadius }: TurningRadiusIndicatorProps) => { + // 19 seems to be an arbitrary number to make the arc look good - initial developer did not document this + const magicNumber = 45 + 45 * (19 / turningRadius); + return ( + + + + ); +}; export const PushbackMap = () => { const dispatch = useAppDispatch(); @@ -73,9 +75,14 @@ export const PushbackMap = () => { const [tugCmdHdgFactor] = useSimVar('L:A32NX_PUSHBACK_HDG_FACTOR', 'bool', 50); const [tugCmdSpdFactor] = useSimVar('L:A32NX_PUSHBACK_SPD_FACTOR', 'bool', 50); - // This constant has been determined via testing - needs more "thought" - // It describes the ratio between the map and real distance - const someConstant = 0.48596; + // Tuning-factor for the turning radius indicator - as there is not relly an easy way to calculate the curvature + // of the turning indicator, this factor is used to "tune" the indicator to match the actual turning radius + const [turnIndicatorTuningFactor, setTurnIndicatorTuningFactor] = useSimVar( + 'L:A32NX_PUSHBACK_TURN_INDICATOR_TUNING_FACTOR', + 'number', + 250, + ); + const turnIndicatorTuningDefault = 1.35; // determined by testing // Reducer state for pushback const { @@ -85,6 +92,16 @@ export const PushbackMap = () => { aircraftIconPosition, } = useAppSelector((state) => state.pushback.pushbackState); + // This constant has been determined via testing - needs more "thought" + // It describes the ratio between the map and real distance + const someConstant = 0.48596; + + // Aircraft wheelbase in meters + // Source: https://www.airbus.com/sites/g/files/jlcbta136/files/2021-11/Airbus-Commercial-Aircraft-AC-A320.pdf + // Source: https://www.airbus.com/sites/g/files/jlcbta136/files/2022-02/Airbus-A380-Facts-and-Figures-February-2022.pdf + const aircraftWheelBase = getAirframeType() === 12.64; + const aircraftLengthMeter = AicraftLength[airframe]; + // Map const [mouseDown, setMouseDown] = useState(false); const [dragging, setDragging] = useState(false); @@ -111,11 +128,10 @@ export const PushbackMap = () => { dispatch(setCenterPlaneMode(!centerPlaneMode)); }; - // Calculates the size in pixels based on the real A321 length and the current zoom - const IconSize = (mapRange) => { + // Calculates the size in pixels based on the real A320 length and the current zoom + const aircraftIconSize = (mapRange: number) => { const pixelPerMeter = someConstant * 10; // at 0.1 range - const LengthMeter = (airframe !== null ? AicraftLength[airframe] : 37.57); - return MathUtils.clamp(LengthMeter * pixelPerMeter * (0.1 / mapRange), 15, 1000); + return MathUtils.clamp(aircraftLengthMeter * pixelPerMeter * (0.1 / mapRange), 15, 1000); }; // Calculates turning radius for the Turning prediction arc @@ -123,8 +139,11 @@ export const PushbackMap = () => { const tanDeg = Math.tan(turnAngle * Math.PI / 180); return wheelBase / tanDeg; }; + const mapRangeCompensationScalar = mapRange / someConstant; + const radius = calculateTurningRadius(aircraftWheelBase, Math.abs(tugCmdHdgFactor * 90)); + const turningRadius = (radius / mapRangeCompensationScalar) * turnIndicatorTuningFactor; - // Computes the offset from geo coordinates (Lat, Lon) and a delta of screen coordinates into + // Computes the offset from geo coordinates (Lat, Lon) and a delta of screen coordinates into // a destination set of geo coordinates. const computeOffset: (latLon: Coordinates, d: TScreenCoordinates) => Coordinates = ( latLon: Coordinates, d: TScreenCoordinates, @@ -160,6 +179,9 @@ export const PushbackMap = () => { // called once when loading and unloading the page useEffect(() => { + // set the tuning factor to a value determined by testing + setTurnIndicatorTuningFactor(turnIndicatorTuningDefault); + let timeOutID: any = 0; if (centerPlaneMode) { // setTimeout required because when loading on runway it did not @@ -199,14 +221,12 @@ export const PushbackMap = () => { } }, [dragging, mouseDown, mouseCoords]); - const mapRangeCompensationScalar = mapRange / someConstant; - const turningRadius = calculateTurningRadius(13, Math.abs(tugCmdHdgFactor * 90)) / mapRangeCompensationScalar * (Math.abs(tugCmdSpdFactor) / 0.2); return ( <> {/* Map Container */}
{ setMouseDown(true); setDragStartCoords({ x: e.pageX, y: e.pageY }); @@ -238,16 +258,16 @@ export const PushbackMap = () => { )} {/* Aircraft and Turning Radius Indicator */} -
+
{centerPlaneMode && !Number.isNaN(turningRadius) && Number.isFinite(turningRadius) && (
= 0 ? 1 : -1}) - scaleY(${tugCmdHdgFactor >= 0 ? 1 : -1}) - translateY(${turningRadius}px)`, + scaleX(${tugCmdSpdFactor >= 0 ? 1 : -1}) + scaleY(${tugCmdHdgFactor >= 0 ? 1 : -1}) + translateY(${turningRadius}px)`, }} > @@ -256,22 +276,22 @@ export const PushbackMap = () => {
{/* Map Controls */} -
+
@@ -290,7 +310,7 @@ export const PushbackMap = () => { diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackPage.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackPage.tsx index a12f9a72..b362a704 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackPage.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/PushbackPage.tsx @@ -1,29 +1,32 @@ -// Copyright (c) 2022 FlyByWire Simulations +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 /* eslint-disable max-len */ +import { MathUtils, usePersistentNumberProperty, useSimVar, useSplitSimVar } from '@flybywiresim/fbw-sdk'; +import { PromptModal, Toggle, TooltipWrapper, t, useModals } from '@flybywiresim/flypad'; +import Slider from 'rc-slider'; import React, { useEffect, useRef } from 'react'; -import { useSimVar, useSplitSimVar, MathUtils, usePersistentNumberProperty } from '@flybywiresim/fbw-sdk'; import { ArrowDown, ArrowLeft, - ArrowRight, ArrowsAngleContract, ArrowsAngleExpand, + ArrowRight, ArrowUp, + ArrowsAngleContract, + ArrowsAngleExpand, ChevronDoubleDown, ChevronDoubleUp, ChevronLeft, - ChevronRight, DashCircle, DashCircleFill, + ChevronRight, + DashCircle, + DashCircleFill, PauseCircleFill, - PlayCircleFill, ToggleOff, ToggleOn, + PlayCircleFill, + ToggleOff, + ToggleOn, TruckFlatbed, } from 'react-bootstrap-icons'; -import Slider from 'rc-slider'; import { toast } from 'react-toastify'; -import { t } from '../../translation'; -import { TooltipWrapper } from '../../UtilComponents/TooltipWrapper'; -import { PromptModal, useModals } from '../../UtilComponents/Modals/Modals'; import { PushbackMap } from './PushbackMap'; -import { Toggle } from '../../UtilComponents/Form/Toggle'; export const PushbackPage = () => { const { showModal } = useModals(); @@ -32,24 +35,22 @@ export const PushbackPage = () => { const [flightPhase] = useSimVar('L:A32NX_FMGC_FLIGHT_PHASE', 'enum', 250); // This is used to completely turn off the pushback for compatibility with other - // pushback add-ons. Only watching sim variables like PUSHBACK STATE or - // Pushback Available leads to conflicts as other add-on also read/write them. + // pushback add-ons. Only watching sim variables like 'PUSHBACK STATE' or + // 'PUSHBACK AVAILABLE' leads to conflicts as other add-on also read/write them. // It is implemented as a LVAR to allow 3rd parties to see that the a32nx pushback is active // and to be able to deactivate themselves or the a32nx pushback system if required. const [pushbackSystemEnabled, setPushbackSystemEnabled] = useSimVar('L:A32NX_PUSHBACK_SYSTEM_ENABLED', 'bool', 100); const [pushbackState, setPushbackState] = useSplitSimVar('PUSHBACK STATE', 'enum', 'K:TOGGLE_PUSHBACK', 'bool', 100); - const [pushbackWait, setPushbackWait] = useSimVar('Pushback Wait', 'bool', 100); - const [pushbackAttached] = useSimVar('Pushback Attached', 'bool', 100); - const [pushbackAngle] = useSimVar('PUSHBACK ANGLE', 'Radians', 100); + const [pushbackWait, setPushbackWait] = useSimVar('PUSHBACK WAIT', 'bool', 100); + const [pushbackAttached] = useSimVar('PUSHBACK ATTACHED', 'bool', 100); + const [pushbackAngle] = useSimVar('PUSHBACK ANGLE', 'Degrees', 100); const [useControllerInput, setUseControllerInput] = usePersistentNumberProperty('PUSHBACK_USE_CONTROLLER_INPUT', 1); const [rudderPosition] = useSimVar('L:A32NX_RUDDER_PEDAL_POSITION', 'number', 50); const [elevatorPosition] = useSimVar('L:A32NX_SIDESTICK_POSITION_Y', 'number', 50); const [planeGroundSpeed] = useSimVar('GROUND VELOCITY', 'Knots', 100); - const [planeHeadingTrue] = useSimVar('PLANE HEADING DEGREES TRUE', 'degrees', 100); - const [planeHeadingMagnetic] = useSimVar('PLANE HEADING DEGREES MAGNETIC', 'degrees', 100); const [parkingBrakeEngaged, setParkingBrakeEngaged] = useSimVar('L:A32NX_PARK_BRAKE_LEVER_POS', 'Bool', 250); const [nwStrgDisc] = useSimVar('L:A32NX_HYD_NW_STRG_DISC_ECAM_MEMO', 'Bool', 250); @@ -57,11 +58,6 @@ export const PushbackPage = () => { const [tugCmdHdgFactor, setCmdHdgFactor] = useSimVar('L:A32NX_PUSHBACK_HDG_FACTOR', 'number', 100); const [tugCmdSpdFactor, setCmdSpdFactor] = useSimVar('L:A32NX_PUSHBACK_SPD_FACTOR', 'number', 100); - // debug info only - can be removed eventually - const [tugCmdHdg] = useSimVar('L:A32NX_PUSHBACK_HDG', 'number', 100); - const [tugCmdSpd] = useSimVar('L:A32NX_PUSHBACK_SPD', 'number', 100); - const [tugInertiaSpeed] = useSimVar('L:A32NX_PUSHBACK_INERTIA_SPD', 'number', 100); - const [updateDeltaTime] = useSimVar('L:A32NX_PUSHBACK_UPDT_DELTA', 'number', 0); const [showDebugInfo, setShowDebugInfo] = useSimVar('L:A32NX_PUSHBACK_DEBUG', 'bool', 100); // Required so these can be used inside the useEffect return callback @@ -133,14 +129,6 @@ export const PushbackPage = () => { setCmdSpdFactor(MathUtils.clamp(speed, -1, 1)); }; - const handleTugDirectionLeft = () => { - handleTugDirection(tugCmdHdgFactor - 0.1); - }; - - const handleTugDirectionRight = () => { - handleTugDirection(tugCmdHdgFactor + 0.1); - }; - const handleTugDirection = (value: number) => { setCmdHdgFactor(MathUtils.clamp(value, -1, 1)); }; @@ -164,7 +152,7 @@ export const PushbackPage = () => { }); }, []); - // Update commanded heading from rudder input + // Update commanded heading and speed from input useEffect(() => { if (!pushbackActive || !useControllerInput) { return; @@ -172,23 +160,16 @@ export const PushbackPage = () => { // create deadzone if (rudderPosition > -0.05 && rudderPosition < 0.05) { setCmdHdgFactor(0); - return; - } - setCmdHdgFactor(rudderPosition / 100); - }, [rudderPosition]); - - // Update commanded speed from elevator input - useEffect(() => { - if (!pushbackActive || !useControllerInput) { - return; + } else { + setCmdHdgFactor(rudderPosition / 100); } // create deadzone if (elevatorPosition > -0.05 && elevatorPosition < 0.05) { setCmdSpdFactor(0); - return; + } else { + setCmdSpdFactor(-elevatorPosition); } - setCmdSpdFactor(-elevatorPosition); - }, [elevatorPosition]); + }, [rudderPosition, elevatorPosition]); // Make sure to deactivate the pushback system completely when leaving ground useEffect(() => { @@ -199,15 +180,15 @@ export const PushbackPage = () => { // Debug info for pushback movement - can be removed eventually const debugInformation = () => ( -
-
+
+
pushbackSystemEnabled: {' '} {pushbackSystemEnabled}
deltaTime: {' '} - {updateDeltaTime.toFixed(4)} + {MathUtils.round(SimVar.GetSimVarValue('L:A32NX_PUSHBACK_UPDT_DELTA', 'number'), 3).toFixed(3)}
pushBackWait: {' '} @@ -232,9 +213,6 @@ export const PushbackPage = () => { tugAngle: {' '} {pushbackAngle.toFixed(3)} - {' ('} - {(pushbackAngle * (180 / Math.PI)).toFixed(3)} - °)
NW STRG DISC MEMO {' '} @@ -248,14 +226,14 @@ export const PushbackPage = () => { {' '} {MathUtils.round(SimVar.GetSimVarValue('GEAR STEER ANGLE PCT:0', 'Percent Over 100'), 3).toFixed(3)}
-
+
Heading (True): {' '} - {planeHeadingTrue.toFixed(4)} + {MathUtils.round(SimVar.GetSimVarValue('PLANE HEADING DEGREES TRUE', 'degrees'), 3).toFixed(3)}
Heading (Magnetic): {' '} - {planeHeadingMagnetic.toFixed(4)} + {MathUtils.round(SimVar.GetSimVarValue('PLANE HEADING DEGREES MAGNETIC', 'degrees'), 3).toFixed(3)}
tCHeadingF: {' '} @@ -263,15 +241,15 @@ export const PushbackPage = () => {
tCHeading : {' '} - {tugCmdHdg.toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('L:A32NX_PUSHBACK_HDG', 'degrees'), 3).toFixed(3)}
Rotation Velocity X: {' '} - {MathUtils.round(SimVar.GetSimVarValue('ROTATION VELOCITY BODY Y', 'Number'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('ROTATION VELOCITY BODY X', 'Number'), 3).toFixed(3)}
Rotation Velocity Y: {' '} - {MathUtils.round(SimVar.GetSimVarValue('ROTATION VELOCITY BODY X', 'Number'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('ROTATION VELOCITY BODY Y', 'Number'), 3).toFixed(3)}
{' '} Rotation Velocity Z: @@ -281,19 +259,30 @@ export const PushbackPage = () => { {' '} Rot. Accel. X: {' '} - {MathUtils.round(SimVar.GetSimVarValue('ROTATION ACCELERATION BODY X', 'radians per second squared'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('ROTATION ACCELERATION BODY X', 'feet per second squared'), 3).toFixed(3)}
{' '} Rot. Accel. Y: {' '} - {MathUtils.round(SimVar.GetSimVarValue('ROTATION ACCELERATION BODY Y', 'radians per second squared'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('ROTATION ACCELERATION BODY Y', 'feet per second squared'), 3).toFixed(3)}
{' '} Rot. Accel Z: {' '} - {MathUtils.round(SimVar.GetSimVarValue('ROTATION ACCELERATION BODY Z', 'radians per second squared'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('ROTATION ACCELERATION BODY Z', 'feet per second squared'), 3).toFixed(3)} +
+ {' '} + Counter Rot. Accel X: + {' '} + {MathUtils.round(SimVar.GetSimVarValue('L:A32NX_PUSHBACK_R_X_OUT', 'feet per second squared'), 3).toFixed(3)} + {' '} +
+ {' '} + Pitch: + {' '} + {MathUtils.round(SimVar.GetSimVarValue('PLANE PITCH DEGREES', 'degrees'), 3).toFixed(3)}
-
+
acGroundSpeed: {' '} {planeGroundSpeed.toFixed(3)} @@ -308,23 +297,23 @@ export const PushbackPage = () => {
tCSpeed: {' '} - {tugCmdSpd.toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('L:A32NX_PUSHBACK_SPD', 'feet per second'), 3).toFixed(3)}
tInertiaSpeed: {' '} - {tugInertiaSpeed.toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('L:A32NX_PUSHBACK_INERTIA_SPD', 'feet per second'), 3).toFixed(3)}
Velocity X: {' '} - {MathUtils.round(SimVar.GetSimVarValue('VELOCITY BODY Y', 'Number'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('VELOCITY BODY X', 'feet per second'), 3).toFixed(3)}
Velocity Y: {' '} - {MathUtils.round(SimVar.GetSimVarValue('VELOCITY BODY X', 'Number'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('VELOCITY BODY Y', 'feet per second'), 3).toFixed(3)}
Velocity Z: {' '} - {MathUtils.round(SimVar.GetSimVarValue('VELOCITY BODY Z', 'Number'), 3).toFixed(3)} + {MathUtils.round(SimVar.GetSimVarValue('VELOCITY BODY Z', 'feet per second'), 3).toFixed(3)}
{' '} Accel. X: @@ -340,6 +329,12 @@ export const PushbackPage = () => { Accel Z: {' '} {MathUtils.round(SimVar.GetSimVarValue('ACCELERATION BODY Z', 'feet per second squared'), 3).toFixed(3)} +
+ {' '} + Rel. Wind Z: + {' '} + {MathUtils.round(SimVar.GetSimVarValue('RELATIVE WIND VELOCITY BODY Z', 'meter per second'), 3).toFixed(3)} + m/s
); @@ -363,14 +358,14 @@ export const PushbackPage = () => { return ( <> -
+
{/* Map Container */} -
+
-
+
{showDebugInfo ? debugInformation() : <>}
@@ -382,7 +377,7 @@ export const PushbackPage = () => { )} {/* Manual Pushback Controls */} -
+
{/* Pushback System enabled On/Off */} @@ -390,7 +385,7 @@ export const PushbackPage = () => {

setShowDebugInfo((old) => !old)} + onDoubleClick={() => setShowDebugInfo((old: any) => !old)} > {t('Pushback.SystemEnabledOn')}

@@ -398,7 +393,7 @@ export const PushbackPage = () => { @@ -408,7 +403,7 @@ export const PushbackPage = () => {

setShowDebugInfo((old) => !old)} + onDoubleClick={() => setShowDebugInfo((old: any) => !old)} > {t('Pushback.SystemEnabledOff')}

@@ -416,7 +411,7 @@ export const PushbackPage = () => { @@ -425,7 +420,7 @@ export const PushbackPage = () => { )} {/* Call Tug */} -
+

{callTugLabel()}

@@ -433,7 +428,7 @@ export const PushbackPage = () => {
-
+
{/* Backward Button */}
@@ -479,7 +474,7 @@ export const PushbackPage = () => { @@ -547,8 +542,8 @@ export const PushbackPage = () => { @@ -557,13 +552,13 @@ export const PushbackPage = () => {
{/* Direction Slider */} -
+

{t('Pushback.TugDirection')}

-

+

handleTugDirection(value)} @@ -574,30 +569,30 @@ export const PushbackPage = () => { value={tugCmdHdgFactor} startPoint={0} /> -

+

{/* Speed Slider */} -
+

{t('Pushback.TugSpeed')}

-

+

handleTugSpeed(value)} onAfterChange={() => speedSliderRef.current.blur()} min={-1} - step={0.1} + step={0.01} max={1} value={tugCmdSpdFactor} startPoint={0} /> -

+

@@ -605,7 +600,7 @@ export const PushbackPage = () => {
-
+
{t('Pushback.UseControllerInput')}
diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A318_100/A318Services.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A318_100/A318Services.tsx index 4e841b4b..8ab702d9 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A318_100/A318Services.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A318_100/A318Services.tsx @@ -2,37 +2,33 @@ // SPDX-License-Identifier: GPL-3.0 /* eslint-disable no-console */ -import React, { FC, useEffect, useRef } from 'react'; import { useSimVar } from '@flybywiresim/fbw-sdk'; import { - ArchiveFill, - ConeStriped, - DoorClosedFill, - HandbagFill, - PersonPlusFill, - PlugFill, - TriangleFill as Chock, - Truck, - VinylFill as Wheel, - Fan, -} from 'react-bootstrap-icons'; -import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; -import { t } from '../../../../translation'; -import { GroundServiceOutline } from '../../../../Assets/A318GroundServiceOutline'; -import { useAppDispatch, useAppSelector } from '../../../../Store/store'; -import { + setAsuButtonState, + setBaggageButtonState, setBoarding1DoorButtonState, setBoarding2DoorButtonState, setBoarding3DoorButtonState, - setServiceDoorButtonState, setCargo1DoorButtonState, - setBaggageButtonState, setCateringButtonState, setFuelTruckButtonState, setGpuButtonState, setJetWayButtonState, - setAsuButtonState, -} from '../../../../Store/features/groundServicePage'; + setServiceDoorButtonState, + t, useAppDispatch, useAppSelector, +} from '@flybywiresim/flypad'; +import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; +import React, { FC, useEffect, useRef } from 'react'; +import { + ArchiveFill, + DoorClosedFill, + Fan, + HandbagFill, + PersonPlusFill, + PlugFill, + Truck +} from 'react-bootstrap-icons'; +import { GroundServiceOutline } from '../../../../Assets/A318GroundServiceOutline'; interface ServiceButtonWrapperProps { className?: string, diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A319_100/A319Services.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A319_100/A319Services.tsx index 7ec7d697..693bb007 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A319_100/A319Services.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A319_100/A319Services.tsx @@ -2,37 +2,33 @@ // SPDX-License-Identifier: GPL-3.0 /* eslint-disable no-console */ -import React, { FC, useEffect, useRef } from 'react'; import { useSimVar } from '@flybywiresim/fbw-sdk'; import { - ArchiveFill, - ConeStriped, - DoorClosedFill, - HandbagFill, - PersonPlusFill, - PlugFill, - TriangleFill as Chock, - Truck, - VinylFill as Wheel, - Fan, -} from 'react-bootstrap-icons'; -import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; -import { t } from '../../../../translation'; -import { GroundServiceOutline } from '../../../../Assets/A319GroundServiceOutline'; -import { useAppDispatch, useAppSelector } from '../../../../Store/store'; -import { + setAsuButtonState, + setBaggageButtonState, setBoarding1DoorButtonState, setBoarding2DoorButtonState, setBoarding3DoorButtonState, - setServiceDoorButtonState, setCargo1DoorButtonState, - setBaggageButtonState, setCateringButtonState, setFuelTruckButtonState, setGpuButtonState, setJetWayButtonState, - setAsuButtonState, -} from '../../../../Store/features/groundServicePage'; + setServiceDoorButtonState, + t, useAppDispatch, useAppSelector, +} from '@flybywiresim/flypad'; +import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; +import React, { FC, useEffect, useRef } from 'react'; +import { + ArchiveFill, + DoorClosedFill, + Fan, + HandbagFill, + PersonPlusFill, + PlugFill, + Truck +} from 'react-bootstrap-icons'; +import { GroundServiceOutline } from '../../../../Assets/A319GroundServiceOutline'; interface ServiceButtonWrapperProps { className?: string, diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A320_200/A320Services.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A320_200/A320Services.tsx index 9b64d67f..36ade441 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A320_200/A320Services.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A320_200/A320Services.tsx @@ -2,37 +2,33 @@ // SPDX-License-Identifier: GPL-3.0 /* eslint-disable no-console */ -import React, { FC, useEffect, useRef } from 'react'; import { useSimVar } from '@flybywiresim/fbw-sdk'; import { - ArchiveFill, - ConeStriped, - DoorClosedFill, - HandbagFill, - PersonPlusFill, - PlugFill, - TriangleFill as Chock, - Truck, - VinylFill as Wheel, - Fan, -} from 'react-bootstrap-icons'; -import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; -import { t } from '../../../../translation'; -import { GroundServiceOutline } from '../../../../Assets/GroundServiceOutline'; -import { useAppDispatch, useAppSelector } from '../../../../Store/store'; -import { + setAsuButtonState, + setBaggageButtonState, setBoarding1DoorButtonState, setBoarding2DoorButtonState, setBoarding3DoorButtonState, - setServiceDoorButtonState, setCargo1DoorButtonState, - setBaggageButtonState, setCateringButtonState, setFuelTruckButtonState, setGpuButtonState, setJetWayButtonState, - setAsuButtonState, -} from '../../../../Store/features/groundServicePage'; + setServiceDoorButtonState, + t, useAppDispatch, useAppSelector, +} from '@flybywiresim/flypad'; +import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; +import React, { FC, useEffect, useRef } from 'react'; +import { + ArchiveFill, + DoorClosedFill, + Fan, + HandbagFill, + PersonPlusFill, + PlugFill, + Truck +} from 'react-bootstrap-icons'; +import { GroundServiceOutline } from '../../../../Assets/A320GroundServiceOutline'; interface ServiceButtonWrapperProps { className?: string, @@ -112,7 +108,6 @@ const GroundServiceButton: React.FC = ({ children, nam export const A320Services: React.FC = () => { const dispatch = useAppDispatch(); - // Flight state const [simOnGround] = useSimVar('SIM ON GROUND', 'bool', 250); const [aircraftIsStationary] = useSimVar('L:A32NX_IS_STATIONARY', 'bool', 250); diff --git a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A321_200/A321Services.tsx b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A321_200/A321Services.tsx index adc50531..c47a2e68 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A321_200/A321Services.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Ground/Pages/Services/A321_200/A321Services.tsx @@ -2,37 +2,33 @@ // SPDX-License-Identifier: GPL-3.0 /* eslint-disable no-console */ -import React, { FC, useEffect, useRef } from 'react'; import { useSimVar } from '@flybywiresim/fbw-sdk'; import { - ArchiveFill, - ConeStriped, - DoorClosedFill, - HandbagFill, - PersonPlusFill, - PlugFill, - TriangleFill as Chock, - Truck, - VinylFill as Wheel, - Fan, -} from 'react-bootstrap-icons'; -import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; -import { t } from '../../../../translation'; -import { GroundServiceOutline } from '../../../../Assets/A321GroundServiceOutline'; -import { useAppDispatch, useAppSelector } from '../../../../Store/store'; -import { + setAsuButtonState, + setBaggageButtonState, setBoarding1DoorButtonState, setBoarding2DoorButtonState, setBoarding3DoorButtonState, - setServiceDoorButtonState, setCargo1DoorButtonState, - setBaggageButtonState, setCateringButtonState, setFuelTruckButtonState, setGpuButtonState, setJetWayButtonState, - setAsuButtonState, -} from '../../../../Store/features/groundServicePage'; + setServiceDoorButtonState, + t, useAppDispatch, useAppSelector, +} from '@flybywiresim/flypad'; +import { ActionCreatorWithOptionalPayload } from '@reduxjs/toolkit'; +import React, { FC, useEffect, useRef } from 'react'; +import { + ArchiveFill, + DoorClosedFill, + Fan, + HandbagFill, + PersonPlusFill, + PlugFill, + Truck +} from 'react-bootstrap-icons'; +import { GroundServiceOutline } from '../../../../Assets/A321GroundServiceOutline'; interface ServiceButtonWrapperProps { className?: string, diff --git a/hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/CommonCalculations.ts b/hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/CommonCalculations.ts deleted file mode 100644 index 139827b7..00000000 --- a/hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/CommonCalculations.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function getTailWind(windDirection: number, windMagnitude: number, runwayHeading: number): number { - const windDirectionRelativeToRwy = windDirection - runwayHeading; - const windDirectionRelativeToRwyRadians = toRadians(windDirectionRelativeToRwy); - - const tailWind = Math.cos(Math.PI - windDirectionRelativeToRwyRadians) * windMagnitude; - return tailWind; -} - -export function toRadians(degrees: number): number { - return degrees * (Math.PI / 180); -} diff --git a/hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/LandingCalculator.ts b/hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/LandingCalculator.ts deleted file mode 100644 index c2251881..00000000 --- a/hsim-common/src/systems/instruments/src/EFB/Performance/Calculators/LandingCalculator.ts +++ /dev/null @@ -1,772 +0,0 @@ -/* - * A32NX - * Copyright (C) 2020-2021 FlyByWire Simulations and its contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// Data and calculations obtained from Quick Reference Handbook (In Flight Procedures, Landing Performance Assessment/Landing Distance) - -import { getTailWind } from './CommonCalculations'; - -export enum LandingRunwayConditions { - Dry, - Good, - GoodMedium, - Medium, - MediumPoor, - Poor, -} - -export enum LandingFlapsConfig { - Conf3, - Full -} - -export enum AutobrakeMode { - Low, - Medium, - Max // Manual brake is the same as max auto -} - -/** - * Landing data for a specific aircraft configuration with a specific runway condition - */ -type LandingData = { - refDistance: number, - weightCorrectionAbove: number, // per 1T above 68T - weightCorrectionBelow: number, // per 1T below 68T - speedCorrection: number, // Per 5kt - altitudeCorrection: number, // Per 1000ft ASL - windCorrection: number, // Per 5KT tail wind - tempCorrection: number, // Per 10 deg C above ISA - slopeCorrection: number, // Per 1% down slope - reverserCorrection: number, // Per thrust reverser operative - overweightProcedureCorrection: number // If overweight procedure applied -}; - -type FlapsConfigLandingData = { - [flapsConfig in LandingFlapsConfig]: LandingData -}; - -type AutobrakeConfigLandingData = { - [autobrakeConfig in AutobrakeMode]: FlapsConfigLandingData -} - -type RunwayConditionLandingData = { - [runwayCondition in LandingRunwayConditions]: AutobrakeConfigLandingData; -} - -const dryRunwayLandingData: AutobrakeConfigLandingData = { - [AutobrakeMode.Max]: { - [LandingFlapsConfig.Full]: { - refDistance: 1060, - weightCorrectionAbove: 50, - weightCorrectionBelow: -10, - speedCorrection: 70, - altitudeCorrection: 40, - windCorrection: 130, - tempCorrection: 30, - slopeCorrection: 20, - reverserCorrection: 0, - overweightProcedureCorrection: 910, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 1210, - weightCorrectionAbove: 50, - weightCorrectionBelow: -10, - speedCorrection: 80, - altitudeCorrection: 50, - windCorrection: 130, - tempCorrection: 40, - slopeCorrection: 30, - reverserCorrection: -10, - overweightProcedureCorrection: 1080, - }, - }, - [AutobrakeMode.Medium]: { - [LandingFlapsConfig.Full]: { - refDistance: 1330, - weightCorrectionAbove: 30, - weightCorrectionBelow: -10, - speedCorrection: 90, - altitudeCorrection: 50, - windCorrection: 140, - tempCorrection: 40, - slopeCorrection: 10, - reverserCorrection: 0, - overweightProcedureCorrection: 220, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 1510, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 100, - altitudeCorrection: 50, - windCorrection: 140, - tempCorrection: 50, - slopeCorrection: 10, - reverserCorrection: 0, - overweightProcedureCorrection: 230, - }, - }, - [AutobrakeMode.Low]: { - [LandingFlapsConfig.Full]: { - refDistance: 1860, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 130, - altitudeCorrection: 70, - windCorrection: 200, - tempCorrection: 70, - slopeCorrection: 30, - reverserCorrection: 0, - overweightProcedureCorrection: 210, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2160, - weightCorrectionAbove: 50, - weightCorrectionBelow: -10, - speedCorrection: 140, - altitudeCorrection: 80, - windCorrection: 220, - tempCorrection: 70, - slopeCorrection: 30, - reverserCorrection: -10, - overweightProcedureCorrection: 230, - }, - }, -}; - -const goodRunwayLandingData: AutobrakeConfigLandingData = { - [AutobrakeMode.Max]: { - [LandingFlapsConfig.Full]: { - refDistance: 1320, - weightCorrectionAbove: 50, - weightCorrectionBelow: -10, - speedCorrection: 110, - altitudeCorrection: 70, - windCorrection: 200, - tempCorrection: 60, - slopeCorrection: 50, - reverserCorrection: -20, - overweightProcedureCorrection: 710, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 1570, - weightCorrectionAbove: 60, - weightCorrectionBelow: -20, - speedCorrection: 120, - altitudeCorrection: 80, - windCorrection: 230, - tempCorrection: 70, - slopeCorrection: 60, - reverserCorrection: -30, - overweightProcedureCorrection: 810, - }, - }, - [AutobrakeMode.Medium]: { - [LandingFlapsConfig.Full]: { - refDistance: 1380, - weightCorrectionAbove: 50, - weightCorrectionBelow: -10, - speedCorrection: 110, - altitudeCorrection: 70, - windCorrection: 200, - tempCorrection: 60, - slopeCorrection: 50, - reverserCorrection: 0, - overweightProcedureCorrection: 200, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 1630, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 120, - altitudeCorrection: 80, - windCorrection: 230, - tempCorrection: 70, - slopeCorrection: 60, - reverserCorrection: -20, - overweightProcedureCorrection: 290, - }, - }, - [AutobrakeMode.Low]: { - [LandingFlapsConfig.Full]: { - refDistance: 1860, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 130, - altitudeCorrection: 70, - windCorrection: 200, - tempCorrection: 70, - slopeCorrection: 30, - reverserCorrection: 0, - overweightProcedureCorrection: 210, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2160, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 140, - altitudeCorrection: 80, - windCorrection: 220, - tempCorrection: 70, - slopeCorrection: 30, - reverserCorrection: -10, - overweightProcedureCorrection: 230, - }, - }, -}; - -const goodMediumRunwayLandingData: AutobrakeConfigLandingData = { - [AutobrakeMode.Max]: { - [LandingFlapsConfig.Full]: { - refDistance: 1570, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 100, - altitudeCorrection: 60, - windCorrection: 190, - tempCorrection: 60, - slopeCorrection: 70, - reverserCorrection: -50, - overweightProcedureCorrection: 800, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 1820, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 100, - altitudeCorrection: 70, - windCorrection: 200, - tempCorrection: 70, - slopeCorrection: 80, - reverserCorrection: -80, - overweightProcedureCorrection: 930, - }, - }, - [AutobrakeMode.Medium]: { - [LandingFlapsConfig.Full]: { - refDistance: 1620, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 100, - altitudeCorrection: 60, - windCorrection: 190, - tempCorrection: 60, - slopeCorrection: 80, - reverserCorrection: -60, - overweightProcedureCorrection: 200, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 1870, - weightCorrectionAbove: 40, - weightCorrectionBelow: -20, - speedCorrection: 100, - altitudeCorrection: 70, - windCorrection: 200, - tempCorrection: 70, - slopeCorrection: 90, - reverserCorrection: -90, - overweightProcedureCorrection: 280, - }, - }, - [AutobrakeMode.Low]: { - [LandingFlapsConfig.Full]: { - refDistance: 1880, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 130, - altitudeCorrection: 70, - windCorrection: 210, - tempCorrection: 60, - slopeCorrection: 50, - reverserCorrection: -10, - overweightProcedureCorrection: 210, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2170, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 140, - altitudeCorrection: 80, - windCorrection: 220, - tempCorrection: 80, - slopeCorrection: 60, - reverserCorrection: -30, - overweightProcedureCorrection: 230, - }, - }, -}; - -const mediumRunwayLandingData: AutobrakeConfigLandingData = { - [AutobrakeMode.Max]: { - [LandingFlapsConfig.Full]: { - refDistance: 1760, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 100, - altitudeCorrection: 70, - windCorrection: 220, - tempCorrection: 60, - slopeCorrection: 110, - reverserCorrection: -90, - overweightProcedureCorrection: 750, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2050, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 110, - altitudeCorrection: 80, - windCorrection: 240, - tempCorrection: 70, - slopeCorrection: 120, - reverserCorrection: -130, - overweightProcedureCorrection: 880, - }, - }, - [AutobrakeMode.Medium]: { - [LandingFlapsConfig.Full]: { - refDistance: 1810, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 110, - altitudeCorrection: 70, - windCorrection: 230, - tempCorrection: 60, - slopeCorrection: 110, - reverserCorrection: -100, - overweightProcedureCorrection: 200, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2100, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 110, - altitudeCorrection: 80, - windCorrection: 240, - tempCorrection: 70, - slopeCorrection: 130, - reverserCorrection: -140, - overweightProcedureCorrection: 300, - }, - }, - [AutobrakeMode.Low]: { - [LandingFlapsConfig.Full]: { - refDistance: 1960, - weightCorrectionAbove: 40, - weightCorrectionBelow: -10, - speedCorrection: 130, - altitudeCorrection: 70, - windCorrection: 240, - tempCorrection: 70, - slopeCorrection: 100, - reverserCorrection: -40, - overweightProcedureCorrection: 230, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2270, - weightCorrectionAbove: 50, - weightCorrectionBelow: -20, - speedCorrection: 140, - altitudeCorrection: 80, - windCorrection: 250, - tempCorrection: 80, - slopeCorrection: 110, - reverserCorrection: -70, - overweightProcedureCorrection: 260, - }, - }, -}; - -const mediumPoorRunwayLandingData: AutobrakeConfigLandingData = { - [AutobrakeMode.Max]: { - [LandingFlapsConfig.Full]: { - refDistance: 1930, - weightCorrectionAbove: 70, - weightCorrectionBelow: -10, - speedCorrection: 170, - altitudeCorrection: 110, - windCorrection: 350, - tempCorrection: 100, - slopeCorrection: 150, - reverserCorrection: -110, - overweightProcedureCorrection: 480, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2380, - weightCorrectionAbove: 80, - weightCorrectionBelow: -30, - speedCorrection: 170, - altitudeCorrection: 140, - windCorrection: 410, - tempCorrection: 120, - slopeCorrection: 200, - reverserCorrection: -150, - overweightProcedureCorrection: 580, - }, - }, - [AutobrakeMode.Medium]: { - [LandingFlapsConfig.Full]: { - refDistance: 1960, - weightCorrectionAbove: 70, - weightCorrectionBelow: -10, - speedCorrection: 160, - altitudeCorrection: 110, - windCorrection: 360, - tempCorrection: 90, - slopeCorrection: 150, - reverserCorrection: -110, - overweightProcedureCorrection: 230, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2400, - weightCorrectionAbove: 80, - weightCorrectionBelow: -30, - speedCorrection: 170, - altitudeCorrection: 140, - windCorrection: 410, - tempCorrection: 120, - slopeCorrection: 200, - reverserCorrection: -160, - overweightProcedureCorrection: 310, - }, - }, - [AutobrakeMode.Low]: { - [LandingFlapsConfig.Full]: { - refDistance: 2000, - weightCorrectionAbove: 70, - weightCorrectionBelow: -10, - speedCorrection: 160, - altitudeCorrection: 120, - windCorrection: 360, - tempCorrection: 90, - slopeCorrection: 150, - reverserCorrection: -40, - overweightProcedureCorrection: 220, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 2430, - weightCorrectionAbove: 80, - weightCorrectionBelow: -30, - speedCorrection: 180, - altitudeCorrection: 140, - windCorrection: 400, - tempCorrection: 130, - slopeCorrection: 210, - reverserCorrection: -80, - overweightProcedureCorrection: 290, - }, - }, -}; - -const poorRunwayLandingData: AutobrakeConfigLandingData = { - [AutobrakeMode.Max]: { - [LandingFlapsConfig.Full]: { - refDistance: 2760, - weightCorrectionAbove: 60, - weightCorrectionBelow: -20, - speedCorrection: 140, - altitudeCorrection: 110, - windCorrection: 430, - tempCorrection: 110, - slopeCorrection: 460, - reverserCorrection: -370, - overweightProcedureCorrection: 550, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 3250, - weightCorrectionAbove: 70, - weightCorrectionBelow: -30, - speedCorrection: 150, - altitudeCorrection: 130, - windCorrection: 470, - tempCorrection: 130, - slopeCorrection: 550, - reverserCorrection: -490, - overweightProcedureCorrection: 660, - }, - }, - [AutobrakeMode.Medium]: { - [LandingFlapsConfig.Full]: { - refDistance: 2790, - weightCorrectionAbove: 60, - weightCorrectionBelow: -20, - speedCorrection: 130, - altitudeCorrection: 110, - windCorrection: 440, - tempCorrection: 100, - slopeCorrection: 470, - reverserCorrection: -380, - overweightProcedureCorrection: 230, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 3280, - weightCorrectionAbove: 70, - weightCorrectionBelow: -30, - speedCorrection: 150, - altitudeCorrection: 130, - windCorrection: 470, - tempCorrection: 120, - slopeCorrection: 560, - reverserCorrection: -490, - overweightProcedureCorrection: 310, - }, - }, - [AutobrakeMode.Low]: { - [LandingFlapsConfig.Full]: { - refDistance: 2830, - weightCorrectionAbove: 60, - weightCorrectionBelow: -20, - speedCorrection: 140, - altitudeCorrection: 110, - windCorrection: 440, - tempCorrection: 110, - slopeCorrection: 470, - reverserCorrection: -380, - overweightProcedureCorrection: 220, - }, - [LandingFlapsConfig.Conf3]: { - refDistance: 3330, - weightCorrectionAbove: 70, - weightCorrectionBelow: -30, - speedCorrection: 140, - altitudeCorrection: 130, - windCorrection: 470, - tempCorrection: 120, - slopeCorrection: 560, - reverserCorrection: -500, - overweightProcedureCorrection: 290, - }, - }, -}; - -/** - * Stores all landing data for the aircraft. - * Retrieve with runwayConditionLandingData[runwayCondition][autobrakeMode][flapsConfig] - */ -const runwayConditionLandingData: RunwayConditionLandingData = { - [LandingRunwayConditions.Dry]: dryRunwayLandingData, - [LandingRunwayConditions.Good]: goodRunwayLandingData, - [LandingRunwayConditions.GoodMedium]: goodMediumRunwayLandingData, - [LandingRunwayConditions.Medium]: mediumRunwayLandingData, - [LandingRunwayConditions.MediumPoor]: mediumPoorRunwayLandingData, - [LandingRunwayConditions.Poor]: poorRunwayLandingData, -}; - -/** - * Safety margin multiplier, obtained from QRH In-Flight Performance section - */ -const SAFETY_MARGIN = 1.15; - -/** - * VLS speed (kts) for full flap configuration - * Index 0 = 50T, Index 11 = 105T, 5T increment - */ -const CONF_FULL_VLS = [112, 114, 119, 124, 128, 132, 137, 141, 145, 149, 154, 157]; - -/** - * VLS speed (kts) for conf 3 flaps - * Index 0 = 50T, Index 11 = 90T, 5T increment - */ -const CONF3_VLS = [113, 119, 124, 129, 134, 138, 143, 146, 150, 155, 160, 166]; - -/** - * Gets the interpolated VLS speed (kts) for the given mass, in tonnes, and the appropriate VLS speed table. - * @param mass - * @param vlsSpeedTable - */ -const getInterpolatedVlsTableValue = (mass: number, vlsSpeedTable: number[]): number => { - const index = Math.max(0, Math.ceil((Math.min(105, mass) - 50) / 5)); - - if (index === 0) return vlsSpeedTable[0]; - if (index === 8) return vlsSpeedTable[8]; - - const lower = vlsSpeedTable[index - 1]; - const upper = vlsSpeedTable[index]; - - const oneTonSpeedIncrement = (upper - lower) / 5; - - return lower + oneTonSpeedIncrement * (mass % 5); -}; - -export class LandingCalculator { - /** - * Calculates the landing distances for each autobrake mode for the given conditions - * @param weight Aircraft weight in KGs - * @param flaps Flap Configuration - * @param runwayCondition - * @param approachSpeed Actual approach speed in kts - * @param windDirection Heading wind is coming from, relative to north - * @param windMagnitude Magnitude of wind in Knots - * @param runwayHeading Heading of runway relative to north - * @param reverseThrust Indicates if reverse thrust is active - * @param altitude Runway altitude in feet ASL - * @param temperature OAT of runway - * @param slope Runway slope in %. Negative is downward slope - * @param overweightProcedure Overweight procedure is being used if true - * @param autoland Indicates if the usage of autoland is active - */ - public calculateLandingDistances( - weight: number, - flaps: LandingFlapsConfig, - runwayCondition: LandingRunwayConditions, - approachSpeed: number, - windDirection: number, - windMagnitude: number, - runwayHeading: number, - reverseThrust: boolean, - altitude: number, - temperature: number, - slope: number, - overweightProcedure: boolean, - pressure: number, - autoland: boolean, - ): { maxAutobrakeDist: number, mediumAutobrakeDist: number, lowAutobrakeDist: number} { - return { - maxAutobrakeDist: SAFETY_MARGIN - * this.calculateRequiredLandingDistance(weight, flaps, runwayCondition, AutobrakeMode.Max, approachSpeed, - windDirection, windMagnitude, runwayHeading, reverseThrust, altitude, temperature, slope, overweightProcedure, pressure, autoland), - mediumAutobrakeDist: SAFETY_MARGIN - * this.calculateRequiredLandingDistance(weight, flaps, runwayCondition, AutobrakeMode.Medium, approachSpeed, - windDirection, windMagnitude, runwayHeading, reverseThrust, altitude, temperature, slope, overweightProcedure, pressure, autoland), - lowAutobrakeDist: SAFETY_MARGIN - * this.calculateRequiredLandingDistance(weight, flaps, runwayCondition, AutobrakeMode.Low, approachSpeed, - windDirection, windMagnitude, runwayHeading, reverseThrust, altitude, temperature, slope, overweightProcedure, pressure, autoland), - }; - } - - /** - * Calculates the required landing distance for the given conditions - * @param weight Aircraft weight in KGs - * @param flaps Flap Configuration - * @param runwayCondition - * @param autobrakeMode - * @param approachSpeed Actual approach speed in kts - * @param windDirection Heading wind is coming from, relative to north - * @param windMagnitude Magnitude of wind in Knots - * @param runwayHeading Heading of runway relative to north - * @param reverseThrust Indicates if reverse thrust is active - * @param altitude Runway altitude in feet ASL - * @param temperature OAT of runway - * @param slope Runway slope in %. Negative is downward slope - * @param overweightProcedure Overweight procedure is being used if true - * @param autoland Indicates if the usage of autoland is active - */ - private calculateRequiredLandingDistance( - weight: number, - flaps: LandingFlapsConfig, - runwayCondition: LandingRunwayConditions, - autobrakeMode: AutobrakeMode, - approachSpeed: number, - windDirection: number, - windMagnitude: number, - runwayHeading: number, - reverseThrust: boolean, - altitude: number, - temperature: number, - slope: number, - overweightProcedure: boolean, - pressure: number, - autoland: boolean, - ): number { - const pressureAltitude = altitude + this.getPressureAltitude(pressure); - const isaTemperature = this.getISATemperature(pressureAltitude); - - let targetApproachSpeed: number; - const tonnage = weight / 1000; - - if (flaps === LandingFlapsConfig.Full) { - targetApproachSpeed = getInterpolatedVlsTableValue(tonnage, CONF_FULL_VLS); - } else { - targetApproachSpeed = getInterpolatedVlsTableValue(tonnage, CONF3_VLS); - } - - const landingData = runwayConditionLandingData[runwayCondition][autobrakeMode][flaps]; - - let tailWind = getTailWind(windDirection, windMagnitude, runwayHeading); - if (tailWind < 0) { - tailWind = 0; - } - - const weightDifference = (weight / 1000) - 68; - let weightCorrection: number; - if (weightDifference < 0) { - weightCorrection = landingData.weightCorrectionBelow * Math.abs(weightDifference); - } else { - weightCorrection = landingData.weightCorrectionAbove * weightDifference; - } - - let speedDifference = approachSpeed - targetApproachSpeed; - if (speedDifference < 0) { - speedDifference = 0; - } - - const speedCorrection = (speedDifference / 5) * landingData.speedCorrection; - const windCorrection = (tailWind / 5) * landingData.windCorrection; - let reverserCorrection; - if (reverseThrust) { - reverserCorrection = landingData.reverserCorrection * 2; - } else { - reverserCorrection = 0; - } - - const altitudeCorrection = pressureAltitude > 0 - ? (pressureAltitude / 1000) * landingData.altitudeCorrection - : 0; - const slopeCorrection = slope < 0 - ? Math.abs(slope) * landingData.slopeCorrection - : 0; - const temperatureCorrection = temperature > isaTemperature - ? ((temperature - isaTemperature) / 10) * landingData.tempCorrection - : 0; - const overweightProcCorrection = overweightProcedure - ? landingData.overweightProcedureCorrection - : 0; - - let autolandCorrection; - - if (autoland) { - autolandCorrection = flaps === LandingFlapsConfig.Full ? 280 : 250; - } else { - autolandCorrection = 0; - } - - const requiredLandingDistance = landingData.refDistance + weightCorrection + speedCorrection + windCorrection + reverserCorrection - + altitudeCorrection + slopeCorrection + temperatureCorrection + overweightProcCorrection + autolandCorrection; - - return Math.round(requiredLandingDistance); - } - - /** - * Converts a given pressure to equivalent pressure altitude - * @param pressure Pressure in mb - * @returns Pressure altitude in feet - */ - private getPressureAltitude(pressure: number): number { - // Equation from Boeing Jet Transport Performance Methods document - return 145442.15 * (1 - ((pressure / 1013.25) ** 0.190263)); - } - - /** - * Calculates ISA temperature for a given pressure altitude - * @param PressureAltitude is pressure altitude in feet - * @returns ISA temperature in degrees C - */ - private getISATemperature(pressureAltitude: number): number { - return 15 - (0.0019812 * pressureAltitude); - } -} diff --git a/hsim-common/src/systems/instruments/src/EFB/Performance/Performance.tsx b/hsim-common/src/systems/instruments/src/EFB/Performance/Performance.tsx index 9fba01a9..d324c76e 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Performance/Performance.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Performance/Performance.tsx @@ -1,10 +1,13 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + import React from 'react'; -import { t } from '../translation'; -import { Navbar } from '../UtilComponents/Navbar'; +import { t } from '../Localization/translation'; import { TODCalculator } from '../TODCalculator/TODCalculator'; +import { Navbar } from '../UtilComponents/Navbar'; +import { PageLink, PageRedirect, TabRoutes } from '../Utils/routing'; import { LandingWidget } from './Widgets/LandingWidget'; -import { TabRoutes, PageLink, PageRedirect } from '../Utils/routing'; export const Performance = () => { const tabs: PageLink[] = [ @@ -17,7 +20,7 @@ export const Performance = () => {

{t('Performance.Title')}

diff --git a/hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/LandingWidget.tsx b/hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/LandingWidget.tsx deleted file mode 100644 index 50bb5c18..00000000 --- a/hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/LandingWidget.tsx +++ /dev/null @@ -1,748 +0,0 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - -/* eslint-disable max-len */ -/* - * A32NX - * Copyright (C) 2020-2021 FlyByWire Simulations and its contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import React, { FC, useState } from 'react'; -import { Units, MetarParserType, useSimVar, usePersistentProperty, parseMetar } from '@flybywiresim/fbw-sdk'; -import { toast } from 'react-toastify'; -import { Calculator, CloudArrowDown, Trash } from 'react-bootstrap-icons'; -import { t } from '../../translation'; -import { TooltipWrapper } from '../../UtilComponents/TooltipWrapper'; -import { PromptModal, useModals } from '../../UtilComponents/Modals/Modals'; -import { LandingCalculator, LandingFlapsConfig, LandingRunwayConditions } from '../Calculators/LandingCalculator'; -import RunwayVisualizationWidget, { LabelType } from './RunwayVisualizationWidget'; -import { SimpleInput } from '../../UtilComponents/Form/SimpleInput/SimpleInput'; -import { SelectInput } from '../../UtilComponents/Form/SelectInput/SelectInput'; -import { useAppDispatch, useAppSelector } from '../../Store/store'; -import { clearLandingValues, initialState, setLandingValues } from '../../Store/features/performance'; - -interface OutputDisplayProps { - label: string; - value: string | number; - error?: boolean; - reverse?: boolean; -} - -const OutputDisplay = (props: OutputDisplayProps) => ( -
-

{props.label}

-

- {props.value} -

-
-); - -interface LabelProps { - className?: string; - text: string; -} - -const Label: FC = ({ text, className, children }) => ( -
-

{text}

- {children} -
-); - -export const LandingWidget = () => { - const dispatch = useAppDispatch(); - - const calculator: LandingCalculator = new LandingCalculator(); - - const [totalWeight] = useSimVar('TOTAL WEIGHT', 'Pounds', 1000); - const [autoFillSource, setAutoFillSource] = useState<'METAR' | 'OFP'>('OFP'); - - const { usingMetric } = Units; - - const { showModal } = useModals(); - - const { - icao, - windDirection, - windMagnitude, - weight, - runwayHeading, - approachSpeed, - flaps, - runwayCondition, - reverseThrust, - autoland, - altitude, - slope, - temperature, - overweightProcedure, - pressure, - runwayLength, - maxAutobrakeLandingDist, - mediumAutobrakeLandingDist, - lowAutobrakeLandingDist, - runwayVisualizationLabels, - displayedRunwayLength, - - } = useAppSelector((state) => state.performance.landing); - - const { arrivingAirport, arrivingMetar } = useAppSelector((state) => state.simbrief.data); - - const handleCalculateLanding = (): void => { - if (!areInputsValid()) return; - const landingDistances = calculator.calculateLandingDistances( - weight ?? 0, - flaps ?? LandingFlapsConfig.Full, - runwayCondition, - approachSpeed ?? 0, - windDirection ?? 0, - windMagnitude ?? 0, - runwayHeading ?? 0, - reverseThrust, - altitude ?? 0, - temperature ?? 0, - slope ?? 0, - overweightProcedure, - pressure ?? 0, - autoland, - ); - - dispatch(setLandingValues({ - maxAutobrakeLandingDist: Math.round(landingDistances.maxAutobrakeDist), - mediumAutobrakeLandingDist: Math.round(landingDistances.mediumAutobrakeDist), - lowAutobrakeLandingDist: Math.round(landingDistances.lowAutobrakeDist), - runwayVisualizationLabels: [ - { - label: 'LOW', - distance: landingDistances.lowAutobrakeDist, - type: LabelType.Main, - }, - { - label: 'MED', - distance: landingDistances.mediumAutobrakeDist, - type: LabelType.Main, - }, - { - label: 'MAX', - distance: landingDistances.maxAutobrakeDist, - type: LabelType.Main, - }, - ], - displayedRunwayLength: runwayLength ?? 0, - })); - }; - - const syncValuesWithApiMetar = async (icao: string): Promise => { - if (!isValidIcao(icao)) return; - - fetch(`https://api.flybywiresim.com/metar/${icao}`) - .then((res) => { - if (res.ok) { - return res.json(); - } - return res.json().then((json) => { - throw new Error(json.message); - }); - }).then((json) => { - const parsedMetar: MetarParserType = parseMetar(json.metar); - - const weightKgs = Math.round(Units.poundToKilogram(totalWeight)); - - dispatch(setLandingValues({ - weight: weightKgs, - windDirection: parsedMetar.wind.degrees, - windMagnitude: parsedMetar.wind.speed_kts, - temperature: parsedMetar.temperature.celsius, - pressure: parsedMetar.barometer.mb, - })); - }) - .catch((err) => toast.error(err.message)); - }; - - const isValidIcao = (icao: string): boolean => icao.length === 4; - - const handleICAOChange = (icao: string): void => { - dispatch(setLandingValues( - { icao }, - )); - }; - - const handleWindDirectionChange = (value: string): void => { - let windDirection: number | undefined = parseInt(value); - - if (Number.isNaN(windDirection)) { - windDirection = undefined; - } - - dispatch(setLandingValues({ windDirection })); - }; - - const handleWindMagnitudeChange = (value: string): void => { - let windMagnitude: number | undefined = parseInt(value); - - if (Number.isNaN(windMagnitude)) { - windMagnitude = undefined; - } - - dispatch(setLandingValues({ windMagnitude })); - }; - - const handleWeightChange = (value: string): void => { - let weight: number | undefined = parseInt(value); - - if (Number.isNaN(weight)) { - weight = undefined; - } else if (weightUnit === 'lb') { - weight = Units.poundToKilogram(weight); - } - - dispatch(setLandingValues({ weight })); - }; - - const handleRunwayHeadingChange = (value: string): void => { - let runwayHeading: number | undefined = parseInt(value); - - if (Number.isNaN(runwayHeading)) { - runwayHeading = undefined; - } - - dispatch(setLandingValues({ runwayHeading })); - }; - - const handleApproachSpeedChange = (value: string): void => { - let approachSpeed: number | undefined = parseInt(value); - - if (Number.isNaN(approachSpeed)) { - approachSpeed = undefined; - } - - dispatch(setLandingValues({ approachSpeed })); - }; - - const handleAltitudeChange = (value: string): void => { - let altitude: number | undefined = parseInt(value); - - if (Number.isNaN(altitude)) { - altitude = undefined; - } - - dispatch(setLandingValues({ altitude })); - }; - - const handleTemperatureChange = (value: string): void => { - let temperature: number | undefined = parseFloat(value); - - if (Number.isNaN(temperature)) { - temperature = undefined; - } else if (temperatureUnit === 'F') { - temperature = Units.fahrenheitToCelsius(temperature); - } - - dispatch(setLandingValues({ temperature })); - }; - - const handleFlapsChange = (newValue: number | string): void => { - let flaps: LandingFlapsConfig = parseInt(newValue.toString()); - - if (flaps !== LandingFlapsConfig.Full && flaps !== LandingFlapsConfig.Conf3) { - flaps = LandingFlapsConfig.Full; - } - - dispatch(setLandingValues({ flaps })); - }; - - const handleRunwayConditionChange = (newValue: number | string): void => { - let runwayCondition: LandingRunwayConditions = parseInt(newValue.toString()); - - if (!runwayCondition) { - runwayCondition = LandingRunwayConditions.Dry; - } - - dispatch(setLandingValues({ runwayCondition })); - }; - - const handleReverseThrustChange = (newValue: boolean): void => { - const reverseThrust: boolean = newValue; - - dispatch(setLandingValues({ reverseThrust })); - }; - - const handleAutolandChange = (newValue: boolean): void => { - const autoland: boolean = newValue; - - dispatch(setLandingValues({ autoland })); - }; - - const handleRunwaySlopeChange = (value: string): void => { - let slope: number | undefined = parseInt(value); - - if (Number.isNaN(slope)) { - slope = undefined; - } - - dispatch(setLandingValues({ slope })); - }; - - const handleRunwayLengthChange = (value: string): void => { - let runwayLength: number | undefined = parseInt(value); - - if (Number.isNaN(runwayLength)) { - runwayLength = undefined; - } else if (distanceUnit === 'ft') { - runwayLength = Units.footToMetre(runwayLength); - } - - dispatch(setLandingValues({ runwayLength })); - }; - - const handleOverweightProcedureChange = (newValue: boolean): void => { - const overweightProcedure: boolean = newValue; - - dispatch(setLandingValues({ overweightProcedure })); - }; - - const handlePressureChange = (value: string): void => { - let pressure: number | undefined = parseFloat(value); - - if (Number.isNaN(pressure)) { - pressure = undefined; - } else if (pressureUnit === 'inHg') { - pressure = Units.inchOfMercuryToHectopascal(pressure); - } - - dispatch(setLandingValues({ pressure })); - }; - - const handleClearInputs = (): void => { - dispatch(clearLandingValues()); - }; - - const areInputsValid = (): boolean => windDirection !== undefined - && windMagnitude !== undefined - && weight !== undefined - && runwayHeading !== undefined - && approachSpeed !== undefined - && altitude !== undefined - && slope !== undefined - && temperature !== undefined - && pressure !== undefined - && runwayLength !== undefined; - - const handleAutoFill = () => { - if (autoFillSource === 'METAR') { - syncValuesWithApiMetar(icao); - } else { - try { - const parsedMetar: MetarParserType = parseMetar(arrivingMetar); - - const weightKgs = Math.round(Units.poundToKilogram(totalWeight)); - - dispatch(setLandingValues({ - weight: weightKgs, - windDirection: parsedMetar.wind.degrees, - windMagnitude: parsedMetar.wind.speed_kts, - temperature: parsedMetar.temperature.celsius, - pressure: parsedMetar.barometer.mb, - })); - } catch (err) { - showModal( - syncValuesWithApiMetar(arrivingAirport)} - />, - ); - } - - dispatch(setLandingValues({ icao: arrivingAirport })); - } - }; - - const isAutoFillIcaoValid = () => { - if (autoFillSource === 'METAR') { - return isValidIcao(icao); - } - return isValidIcao(arrivingAirport); - }; - - const [temperatureUnit, setTemperatureUnit] = usePersistentProperty('EFB_PREFERRED_TEMPERATURE_UNIT', usingMetric ? 'C' : 'F'); - const [pressureUnit, setPressureUnit] = usePersistentProperty('EFB_PREFERRED_PRESSURE_UNIT', usingMetric ? 'hPa' : 'inHg'); - const [distanceUnit, setDistanceUnit] = usePersistentProperty('EFB_PREFERRED_DISTANCE_UNIT', usingMetric ? 'm' : 'ft'); - const [weightUnit, setWeightUnit] = usePersistentProperty('EFB_PREFERRED_WEIGHT_UNIT', usingMetric ? 'kg' : 'lb'); - - const getVariableUnitDisplayValue = (value: number | undefined, unit: T, imperialUnit: T, metricToImperial: (value: number) => number) => { - if (value !== undefined) { - if (unit === imperialUnit) { - return metricToImperial(value); - } - return value; - } - return undefined; - }; - - const fillDataTooltip = () => { - switch (autoFillSource) { - case 'METAR': - if (!isAutoFillIcaoValid()) { - return t('Performance.Landing.TT.YouNeedToEnterAnIcaoCodeInOrderToMakeAMetarRequest'); - } - break; - case 'OFP': - if (!isAutoFillIcaoValid()) { - return t('Performance.Landing.TT.YouNeedToLoadSimBriefDataInOrderToAutofillData'); - } - break; - default: return undefined; - } - - return undefined; - }; - - return ( -
-
-
-
-
-

{t('Performance.Landing.AirportIcao')}

-
- -
- - - - setAutoFillSource(value)} - /> -
-
-
-
-
- - - - - - - -
-
- - - - - - - - -
-
-
- - -
-
-
- (displayedRunwayLength ?? 0)} - /> - (displayedRunwayLength ?? 0)} - /> - (displayedRunwayLength ?? 0)} - /> -
-
-
-
- -
-
- ); -}; diff --git a/hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/RunwayVisualizationWidget.tsx b/hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/RunwayVisualizationWidget.tsx deleted file mode 100644 index 07ed026f..00000000 --- a/hsim-common/src/systems/instruments/src/EFB/Performance/Widgets/RunwayVisualizationWidget.tsx +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - -/* eslint-disable max-len */ -/* - * A32NX - * Copyright (C) 2020-2021 FlyByWire Simulations and its contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import { Units } from '@flybywiresim/fbw-sdk'; -import React, { useEffect, useState } from 'react'; - -export type DistanceLabel = { - distance: number, - label: string, - type: LabelType -} - -export enum LabelType { - Main, - Asda, - Toda -} - -interface RunwayVisualizationProps { - mainLength?: number; - asda?: number; - toda?: number; - labels?: DistanceLabel[]; - runwayHeading?: number; - distanceUnit: 'ft' | 'm'; -} - -interface RunwayNumberProps { - heading?: number; -} - -const RunwayNumber = ({ heading }: RunwayNumberProps) => { - const displayedHeading = (heading! % 360 < 5) ? 360 : heading! % 360; - - return ( -
- {heading !== undefined ? Math.round(displayedHeading / 10).toString().padStart(2, '0') : '??'} -
- ); -}; - -const RunwayVisualizationWidget = ({ asda = 0, labels = [], mainLength = 0, runwayHeading, toda = 0, distanceUnit }: RunwayVisualizationProps) => { - const maxDist = () => { - const distances = labels.map((label) => label.distance); - - return Math.max(mainLength ?? 0, asda ?? 0, toda ?? 0, ...distances); - }; - - const getLabelBottomPercentage = (label: DistanceLabel): number => (label.distance / maxDist()) * 100; - - const mainHeightPercentage = (): number => { - const maximumDist = maxDist(); - - if (mainLength === 0 || maximumDist === 0) { - return 100; - } - - const percentage = (mainLength / maxDist()) * 100; - - return Math.max(percentage, 20); - }; - - const asdaHeightPercentage = (): number => Math.max(((asda - mainLength) / maxDist()) * 100, 0); - - const todaHeightPercentage = (): number => Math.max(((toda - asda) / maxDist()) * 100, 0); - - const isLabelOverDistance = (label: DistanceLabel): boolean => { - switch (label.type) { - case LabelType.Asda: - return label.distance > (asda); - case LabelType.Toda: - return label.distance > (toda); - default: - return label.distance > (mainLength); - } - }; - - const [labelComponents, setLabelComponents] = useState(); - - useEffect(() => setLabelComponents(() => { - const elements = labels.map((label) => { - const bottomPercentage = getLabelBottomPercentage(label); - const showBelow = label.label === 'MAX'; - - return ( -
-

- {label.label} - {' '} - { Math.round(distanceUnit === 'ft' ? Units.metreToFoot(label.distance) : label.distance) } - {distanceUnit} -

-
- ); - }); - - return <>{elements}; - }), [labels, distanceUnit]); - - const runwayBoundMarkers = ( -
-
-
-
-
-
-
-
- ); - - return ( -
-
-
-
-
-
-
-
-
- {runwayBoundMarkers} - {runwayBoundMarkers} -
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
- -
- {runwayBoundMarkers} - {runwayBoundMarkers} -
-
-
-
- {labelComponents} -
-
- ); -}; - -export default RunwayVisualizationWidget; diff --git a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx b/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx index 90934412..c348b03a 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx @@ -1,15 +1,13 @@ -// Copyright (c) 2022 FlyByWire Simulations +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 +import { AircraftVersionChecker, BuildInfo, SENTRY_CONSENT_KEY, SentryConsentState, usePersistentProperty, useSessionStorage } from '@flybywiresim/fbw-sdk'; import React, { useEffect, useState } from 'react'; -import { usePersistentProperty, useSessionStorage } from '@flybywiresim/fbw-sdk'; -import { SentryConsentState, SENTRY_CONSENT_KEY } from '@sentry/FbwAircraftSentryClient'; -import { AircraftVersionChecker, BuildInfo } from '@shared/AircraftVersionChecker'; import { SettingsPage } from '../Settings'; // @ts-ignore import HorizonLogo from '../../Assets/Horizon_Simulations_Logo.svg'; -import { t } from '../../translation'; +import { t } from '../../Localization/translation'; interface BuildInfoEntryProps { title: string; @@ -36,7 +34,7 @@ const BuildInfoEntry = ({ title, value, underline = 0 }: BuildInfoEntryProps) => const last = value?.substring(underline); return ( -
+

{title + '\u00A0'.repeat(Math.abs(SPACE_BETWEEN - title.length))}

{first} @@ -70,13 +68,13 @@ export const AboutPage = () => { return ( -

+
-

flyPadOS 3

+

flyPadOS 3

@@ -86,9 +84,9 @@ export const AboutPage = () => {

-
+

© 2020-2022 FlyByWire Simulations and its contributors, all rights reserved.

-

© 2022-2023 Horizon Simulations and its contributors, all rights reserved.

+

© 2022-2024 Horizon Simulations and its contributors, all rights reserved.

Licensed under the GNU General Public License Version 3

diff --git a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AircraftOptionsPinProgramsPage.tsx b/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AircraftOptionsPinProgramsPage.tsx deleted file mode 100644 index 9dcf9481..00000000 --- a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/AircraftOptionsPinProgramsPage.tsx +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - -import { usePersistentNumberProperty, usePersistentProperty } from '@flybywiresim/fbw-sdk'; -import React, { useState } from 'react'; -import { Link, Route, Switch } from 'react-router-dom'; -import { PageLink, TabRoutes, pathify } from 'instruments/src/EFB/Utils/routing'; -import { AutomaticCallOutsPage } from 'instruments/src/EFB/Settings/Pages/AutomaticCallOutsPage'; -import { t } from '../../translation'; -import { SelectGroup, SelectItem } from '../../UtilComponents/Form/Select'; -import { SimpleInput } from '../../UtilComponents/Form/SimpleInput/SimpleInput'; -import { ButtonType, SettingItem, SettingsPage } from '../Settings'; -import { Toggle } from '../../UtilComponents/Form/Toggle'; - -const basePinProgRoute = `/settings/${pathify('Aircraft Options / Pin Programs')}`; - -const subTabs: PageLink[] = [ - { alias: t('Settings.AutomaticCallOuts.Title'), name: 'Automatic Call Outs', component: }, -]; - -export const AircraftOptionsPinProgramsPage = () => { - const [thrustReductionHeight, setThrustReductionHeight] = usePersistentProperty('CONFIG_THR_RED_ALT', '1500'); - const [thrustReductionHeightSetting, setThrustReductionHeightSetting] = useState(thrustReductionHeight); - const [accelerationHeight, setAccelerationHeight] = usePersistentProperty('CONFIG_ACCEL_ALT', '1500'); - const [accelerationHeightSetting, setAccelerationHeightSetting] = useState(accelerationHeight); - const [accelerationOutHeight, setAccelerationOutHeight] = usePersistentProperty('CONFIG_ENG_OUT_ACCEL_ALT', '1500'); - const [accelerationOutHeightSetting, setAccelerationOutHeightSetting] = useState(accelerationOutHeight); - - const [usingMetric, setUsingMetric] = usePersistentProperty('CONFIG_USING_METRIC_UNIT', '1'); - const [paxSigns, setPaxSigns] = usePersistentProperty('CONFIG_USING_PORTABLE_DEVICES', '0'); - const [isisBaro, setIsisBaro] = usePersistentProperty('ISIS_BARO_UNIT_INHG', '0'); - const [isisMetricAltitude, setIsisMetricAltitude] = usePersistentNumberProperty('ISIS_METRIC_ALTITUDE', 0); - const [vhfSpacing, setVhfSpacing] = usePersistentProperty('RMP_VHF_SPACING_25KHZ', '0'); - const [latLonExtended, setLatLonExtended] = usePersistentProperty('LATLON_EXT_FMT', '0'); - const [satcomEnabled, setsatcomEnabled] = usePersistentNumberProperty('MODEL_SATCOM_ENABLED', 0); - - const handleSetThrustReductionAlt = (value: string) => { - setThrustReductionHeightSetting(value); - - const parsedValue = parseInt(value); - - if (parsedValue >= 400 && parsedValue <= 5000) { - setThrustReductionHeight(value.trim()); - } - }; - - const handleSetAccelerationAlt = (value: string) => { - setAccelerationHeightSetting(value); - - const parsedValue = parseInt(value); - - if (parsedValue >= 400 && parsedValue <= 10000) { - setAccelerationHeight(value.trim()); - } - }; - - const handleSetAccelerationOutAlt = (value: string) => { - setAccelerationOutHeightSetting(value); - - const parsedValue = parseInt(value); - - if (parsedValue >= 400 && parsedValue <= 10000) { - setAccelerationOutHeight(value.trim()); - } - }; - - const paxSignsButtons: ButtonType[] = [ - { name: 'No Smoking', setting: '0' }, - { name: 'No Portable Device', setting: '1' }, - ]; - - const weightUnitButtons: ButtonType[] = [ - { name: 'kg', setting: '1' }, - { name: 'lbs', setting: '0' }, - ]; - - const isisBaroButtons: ButtonType[] = [ - { name: 'hPa', setting: '0' }, - { name: 'hPa/inHg', setting: '1' }, - ]; - - const vhfSpacingButtons: ButtonType[] = [ - { name: '8.33 kHz', setting: '0' }, - { name: '25 kHz', setting: '1' }, - ]; - - const latLonExtendedButtons: ButtonType[] = [ - { name: 'LLnn', setting: '0' }, - { name: 'AxxByyy', setting: '1' }, - ]; - - return ( - - - - - handleSetThrustReductionAlt(event)} - /> - - - handleSetAccelerationAlt(event)} - /> - - - handleSetAccelerationOutAlt(event)} - /> - - - - - {isisBaroButtons.map((button) => ( - setIsisBaro(button.setting)} - selected={isisBaro === button.setting} - > - {button.name} - - ))} - - - - - setIsisMetricAltitude(value ? 1 : 0)} /> - - - - - {paxSignsButtons.map((button) => ( - setPaxSigns(button.setting)} - selected={paxSigns === button.setting} - > - {button.name} - - ))} - - - - - - {vhfSpacingButtons.map((button) => ( - setVhfSpacing(button.setting)} - selected={vhfSpacing === button.setting} - > - {button.name} - - ))} - - - - - - {latLonExtendedButtons.map((button) => ( - setLatLonExtended(button.setting)} - selected={latLonExtended === button.setting} - > - {button.name} - - ))} - - - - - - {weightUnitButtons.map((button) => ( - setUsingMetric(button.setting)} - selected={usingMetric === button.setting} - > - {button.name} - - ))} - - - - - setsatcomEnabled(value ? 1 : 0)} /> - - - - - {t('Settings.AircraftOptionsPinPrograms.Select')} - - - - - - - - ); -}; diff --git a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/FlyPadPage.tsx b/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/FlyPadPage.tsx deleted file mode 100644 index 21bd355f..00000000 --- a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/FlyPadPage.tsx +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// -// SPDX-License-Identifier: GPL-3.0 - -import React, { useRef } from 'react'; - -import { usePersistentNumberProperty, usePersistentProperty, useSimVar } from '@flybywiresim/fbw-sdk'; - -import Slider from 'rc-slider'; -import { Toggle } from '../../UtilComponents/Form/Toggle'; -import { ButtonType, SettingItem, SettingsPage, SettingGroup } from '../Settings'; -import { SelectGroup, SelectItem } from '../../UtilComponents/Form/Select'; -import { SimpleInput } from '../../UtilComponents/Form/SimpleInput/SimpleInput'; -import { SelectInput } from '../../UtilComponents/Form/SelectInput/SelectInput'; -import { keyboardLayoutOptions } from '../../UtilComponents/KeyboardWrapper'; -import { languageOptions, tt } from '../../translation'; - -export const FlyPadPage = () => { - const [brightnessSetting, setBrightnessSetting] = usePersistentNumberProperty('EFB_BRIGHTNESS', 0); - const [brightness] = useSimVar('L:A32NX_EFB_BRIGHTNESS', 'number', 500); - const [usingAutobrightness, setUsingAutobrightness] = usePersistentNumberProperty('EFB_USING_AUTOBRIGHTNESS', 0); - const [theme, setTheme] = usePersistentProperty('EFB_UI_THEME', 'blue'); - const [autoOSK, setAutoOSK] = usePersistentNumberProperty('EFB_AUTO_OSK', 0); - const [timeDisplayed, setTimeDisplayed] = usePersistentProperty('EFB_TIME_DISPLAYED', 'utc'); - const [timeFormat, setTimeFormat] = usePersistentProperty('EFB_TIME_FORMAT', '24'); - const [showStatusBarFlightProgress, setShowStatusBarFlightProgress] = usePersistentNumberProperty('EFB_SHOW_STATUSBAR_FLIGHTPROGRESS', 1); - const [usingColoredMetar, setUsingColoredMetar] = usePersistentNumberProperty('EFB_USING_COLOREDMETAR', 1); - const [language, setLanguage] = usePersistentProperty('EFB_LANGUAGE', 'en'); - const [keyboardLayout, setKeyboardLayout] = usePersistentProperty('EFB_KEYBOARD_LAYOUT_IDENT', 'english'); - const [batteryLifeEnabled, setBatteryLifeEnabled] = usePersistentNumberProperty('EFB_BATTERY_LIFE_ENABLED', 1); - - // the tt() is a special case to update the page with the correct language after user - // changes the language. the change to simvar hooks changed timing/order of updates. - - const themeButtons: ButtonType[] = [ - { name: tt('Settings.flyPad.Blue', language), setting: 'blue' }, - { name: tt('Settings.flyPad.Dark', language), setting: 'dark' }, - { name: tt('Settings.flyPad.Light', language), setting: 'light' }, - ]; - - const timeDisplayButtons: ButtonType[] = [ - { name: tt('Settings.flyPad.Utc', language), setting: 'utc' }, - { name: tt('Settings.flyPad.Local', language), setting: 'local' }, - { name: tt('Settings.flyPad.UtcAndLocal', language), setting: 'both' }, - ]; - - const timeFormatButtons: ButtonType[] = [ - { name: tt('Settings.flyPad.TwelveHours', language), setting: '12' }, - { name: tt('Settings.flyPad.TwentyFourHours', language), setting: '24' }, - ]; - - const handleThemeSelect = (theme: string) => { - setTheme(theme); - document.documentElement.classList.forEach((className) => { - if (className.includes('theme-')) { - document.documentElement.classList.remove(className); - } - }); - document.documentElement.classList.add(`theme-${theme}`); - }; - - // To prevent keyboard input (esp. END key for external view) to change - // the slider position. This is accomplished by a - // onAfterChange={() => sliderRef.current.blur()} - // in the Slider component props. - const brightnessSliderRef = useRef(null); - - return ( - - - setLanguage(value as string)} - options={languageOptions.map((option) => ({ - value: option.langCode, - displayValue: `${option.alias}`, - tooltip: `${option.langName}`, - }))} - maxHeight={32} - /> - - - - setKeyboardLayout(value as string)} - options={keyboardLayoutOptions.map((option) => ({ - value: option.name, - displayValue: option.alias, - }))} - maxHeight={32} - /> - - - - setAutoOSK(value ? 1 : 0)} /> - - - - - setUsingAutobrightness(value ? 1 : 0)} /> - - {!usingAutobrightness && ( - -
- <> - brightnessSliderRef.current.blur()} - /> - setBrightnessSetting(parseInt(value))} - decimalPrecision={0} - number - /> - -
-
- )} -
- - - setBatteryLifeEnabled(value ? 1 : 0)} /> - - - - setShowStatusBarFlightProgress(value ? 1 : 0)} /> - - - - setUsingColoredMetar(value ? 1 : 0)} /> - - - - - - {timeDisplayButtons.map((button) => ( - setTimeDisplayed(button.setting)} - selected={timeDisplayed === button.setting} - > - {button.name} - - ))} - - - {timeDisplayed !== 'utc' && ( - - - {timeFormatButtons.map((button) => ( - setTimeFormat(button.setting)} - selected={timeFormat === button.setting} - > - {button.name} - - ))} - - - )} - - - - - {themeButtons.map((button) => ( - handleThemeSelect(button.setting)} - selected={theme === button.setting} - > - {button.name} - - ))} - - - -
- ); -}; diff --git a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx b/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx index 9cfa9518..1bee1f62 100644 --- a/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx +++ b/hsim-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx @@ -1,13 +1,12 @@ -// Copyright (c) 2021-2023 FlyByWire Simulations -// +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 /* eslint-disable max-len */ +import { usePersistentProperty, useSimVar } from '@flybywiresim/fbw-sdk'; import React, { useState } from 'react'; -import { usePersistentNumberProperty, usePersistentProperty, useSimVar } from '@flybywiresim/fbw-sdk'; import { toast } from 'react-toastify'; -import { t } from '../../translation'; +import { t } from '../../Localization/translation'; import { Toggle } from '../../UtilComponents/Form/Toggle'; import { ButtonType, SettingItem, SettingsPage } from '../Settings'; @@ -189,8 +188,8 @@ export const SimOptionsPage = () => {
+ {' '} + {t('Ground.Payload.Planned')} + {t('Ground.Payload.Current')}
+ {t('Ground.Payload.Passengers')} -
+
0 ? maxPax : 999} @@ -323,18 +323,18 @@ export const PayloadInputTable: React.FC = (
+
+ {t('Ground.Payload.Cargo')} -
+
0 ? Math.round(Units.kilogramToUser(maxCargo)) : 99999} @@ -350,20 +350,20 @@ export const PayloadInputTable: React.FC = (
+
+ {displayZfw ? t('Ground.Payload.ZFW') : t('Ground.Payload.GW')} {(displayZfw ? ( -
+
= ( ) : ( -
+
= ( ) )}
+ = (
-
+
+
{t(displayZfw ? 'Ground.Payload.ZFWCG' : 'Ground.Payload.GWCG')}
-
+
{/* TODO FIXME: Setting pax/cargo given desired ZFWCG, ZFW, total pax, total cargo */} -
+
{/* @@ -444,7 +444,7 @@ export const PayloadInputTable: React.FC = (
+