From 46e470b55a54d44517360c30b5462ff523f8fff4 Mon Sep 17 00:00:00 2001 From: Marcelo Bezerra <23555060+mmosca@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:00:04 +0200 Subject: [PATCH 1/8] HUD refactor --- tabs/osd.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tabs/osd.js b/tabs/osd.js index c9ab19a51..4c8ec7518 100644 --- a/tabs/osd.js +++ b/tabs/osd.js @@ -1682,6 +1682,26 @@ OSD.constants = { id: 99, preview: FONT.symbol(SYM.DIRECTION) + '\nN', }, + { + name: 'HOMING', + id: 144, + positionable: false + }, + { + name: 'HOMEPOINT', + id: 145, + positionable: false + }, + { + name: 'INAV_RADAR', + id: 146, + positionable: false + }, + { + name: 'WAYPOINTS', + id: 147, + positionable: false + } ], }, { From cc25c7e82809e9c2b8ae18c9075762927cb9a614 Mon Sep 17 00:00:00 2001 From: Marcelo Bezerra <23555060+mmosca@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:10:44 +0200 Subject: [PATCH 2/8] break it up in a different section --- _locales/en/messages.json | 3 +++ tabs/osd.js | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 6b2998c94..c1881674e 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -3593,6 +3593,9 @@ "osdGroupMapsAndRadars": { "message": "Maps and Radars" }, + "osdGroupHud": { + "message": "Heads up display" + }, "osdGroupMapsAndRadars_HELP": { "message": "Maps and radars allow laying out additional elements on top of them as long as they don't overlap any of the map parts visible in the preview." }, diff --git a/tabs/osd.js b/tabs/osd.js index 4c8ec7518..aaa825f82 100644 --- a/tabs/osd.js +++ b/tabs/osd.js @@ -1681,7 +1681,12 @@ OSD.constants = { name: 'MAP_REFERENCE', id: 99, preview: FONT.symbol(SYM.DIRECTION) + '\nN', - }, + } + ], + }, + { + name: 'osdGroupHud', + items: [ { name: 'HOMING', id: 144, @@ -1702,7 +1707,7 @@ OSD.constants = { id: 147, positionable: false } - ], + ] }, { name: 'osdGroupVTX', From f62e3bf56c581d6dac9db40450626dd6b6e456f9 Mon Sep 17 00:00:00 2001 From: Marcelo Bezerra <23555060+mmosca@users.noreply.github.com> Date: Thu, 27 Jul 2023 17:27:03 +0200 Subject: [PATCH 3/8] Inav Radar => INAV Radar/Formation Flight --- _locales/en/messages.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c1881674e..674d1f7d2 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -3594,7 +3594,15 @@ "message": "Maps and Radars" }, "osdGroupHud": { - "message": "Heads up display" + "message": "Heads up Display" + }, + "osdGroupHud_HELP": + { + "message": "HUD elements are positioned around the center of the screen and move as their position in relation to the aircraft changes." + }, + "osdElement_INAV_RADAR": + { + "message": "INAV Radar/FormationFlight" }, "osdGroupMapsAndRadars_HELP": { "message": "Maps and radars allow laying out additional elements on top of them as long as they don't overlap any of the map parts visible in the preview." From 893d566342fbe875bce6e3d6e122d205c35b1d34 Mon Sep 17 00:00:00 2001 From: Marcelo Bezerra <23555060+mmosca@users.noreply.github.com> Date: Fri, 28 Jul 2023 11:50:32 +0200 Subject: [PATCH 4/8] Update help messages for radar/wp_disp --- _locales/en/messages.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index a0df306db..e9efb89e9 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -3426,10 +3426,10 @@ "message": "This section allows tweaking the behavior of HUD elements." }, "osd_hud_radar_disp": { - "message": "Maximum number of radar elements on screen." + "message": "Maximum count of nearby aircrafts to display in the HUD. The nearby aircrafts will appear as markers A, B, C, etc" }, "osd_hud_radar_disp_help": { - "message": "This is used for INAV Radar/FormationFlight. 0 disables this feature." + "message": "This is used for INAV Radar/FormationFlight." }, "osd_hud_radar_range_min": { @@ -3451,7 +3451,7 @@ "message": "Maximum number of waypoint elements on screen." }, "osd_hud_wp_disp_help": { - "message": "Number of Wayponts to show on screen. 0 disables this feature." + "message": "How many navigation waypoints are displayed in the HUD. As sample, if set to 2, and you just passed the 3rd waypoint of the mission, you'll see markers for the 4th waypoint (marked 1) and the 5th waypoint (marked 2)" }, "osd_camera_fov_h": { "message": "Camera Horizontal FOV" From 12ab5c8d86c0eb7ccff2aafd34ae66ea8bbf45de Mon Sep 17 00:00:00 2001 From: Marcelo Bezerra <23555060+mmosca@users.noreply.github.com> Date: Thu, 7 Sep 2023 18:42:47 +0200 Subject: [PATCH 5/8] aditional tab --- _locales/en/messages.json | 5 +- js/gui.js | 1 + main.html | 3 + main.js | 3 + src/css/tabs/osd_settings.css | 722 ++++++++++++++ tabs/osd_settings.html | 435 +++++++++ tabs/osd_settings.js | 1739 +++++++++++++++++++++++++++++++++ 7 files changed, 2907 insertions(+), 1 deletion(-) create mode 100644 src/css/tabs/osd_settings.css create mode 100644 tabs/osd_settings.html create mode 100644 tabs/osd_settings.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e9efb89e9..af75c897f 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -2699,7 +2699,10 @@ "message": "In general, higher value is better. With asynchronous gyroscope, should be kept below gyro update frequency. Maximal practical value is hardware dependant. If set too high, board might not run properly. Observe CPU usage." }, "tabOSD": { - "message": "OSD" + "message": "OSD Layout" + }, + "tabOSD_settings": { + "message": "OSD Settings" }, "configurationSensors": { "message": "Sensors & buses" diff --git a/js/gui.js b/js/gui.js index 3d20d07a1..e9864ef2f 100644 --- a/js/gui.js +++ b/js/gui.js @@ -37,6 +37,7 @@ var GUI_control = function () { 'calibration', 'setup', 'osd', + 'osd_settings', 'profiles', 'advanced_tuning', 'mission_control', diff --git a/main.html b/main.html index 3deabe822..3ab775f96 100755 --- a/main.html +++ b/main.html @@ -235,6 +235,9 @@

+
  • + +
  • diff --git a/main.js b/main.js index 7086b3cc9..bcf83a48c 100644 --- a/main.js +++ b/main.js @@ -283,6 +283,9 @@ $(document).ready(function () { case 'osd': TABS.osd.initialize(content_ready); break; + case 'osd_settings': + TABS.osd_settings.initialize(content_ready); + break; case 'sensors': TABS.sensors.initialize(content_ready); break; diff --git a/src/css/tabs/osd_settings.css b/src/css/tabs/osd_settings.css new file mode 100644 index 000000000..4ad182715 --- /dev/null +++ b/src/css/tabs/osd_settings.css @@ -0,0 +1,722 @@ +.tab-osd_settings .info { + margin: 10px 0 0 0; + position: relative; +} + +.tab-osd_settings .info .progressLabel { + position: absolute; + width: 100%; + height: 26px; + top: 0; + left: 0; + text-align: center; + line-height: 24px; + color: white; + font-weight: bold; + + /* text-shadow: 1px 0px 2px rgba(0, 0, 0, 0.9);*/ +} + +.darkgrey { + background-color: #575757; +} + +.blue { + color: #151f8c; +} + +.tab-osd_settings .spacer_box_title { + float: none; +} + +.tab-osd_settings .info { + float: left; + width: 100%; +} + +.info .progressLabel a { + color: white; +} + +.info .progressLabel a:hover { + text-decoration: underline; +} + +.info .progress { + width: 100%; + height: 26px; + border-radius: 5px; + border: 1px solid silver; +} + +.info .progress { + -webkit-appearance: none; +} + +/*noinspection CssInvalidPseudoSelector*/ +.info .progress::-webkit-progress-bar { + background-color: #4f4f4f; + border-radius: 4px; + box-shadow: inset 0 0 5px #2f2f2f; +} + +/*noinspection CssInvalidPseudoSelector*/ +.info .progress::-webkit-progress-value { + background-color: #F86008; + border-radius: 4px; +} + +/*noinspection CssInvalidPseudoSelector*/ +.info .progress.valid::-webkit-progress-bar { + background-color: #56ac1d; + border-radius: 4px; +} + +/*noinspection CssInvalidPseudoSelector*/ +.info .progress.valid::-webkit-progress-value { + background-color: #56ac1d; + border-radius: 4px; +} + +/*noinspection CssInvalidPseudoSelector*/ +.info .progress.invalid::-webkit-progress-bar { + background-color: #A62E32; + border-radius: 4px; +} + +/*noinspection CssInvalidPseudoSelector*/ +.info .progress.invalid::-webkit-progress-value { + background-color: #A62E32; + border-radius: 4px; +} + +.tab-osd_settings ul li { + list-style: circle; + margin-left: 30px; +} + +.tab-osd_settings .options { + position: relative; + margin-bottom: 10px; + line-height: 18px; + text-align: left; +} + +.tab-osd_settings td { + text-align: left; +} + +.tab-osd_settings .options label input { + float: left; + margin-top: 2px; +} + +.tab-osd_settings .options label span { + font-weight: bold; + margin-left: 6px; +} + +.tab-osd_settings .options select { + width: 300px; + height: 20px; + border: 1px solid silver; +} + +.tab-osd_settings .options .releases select { + width: 280px; +} + +.tab-osd_settings .option.releases { + margin: 0 0 2px 0; + line-height: 20px; +} + +.tab-osd_settings .options .description { + position: relative; + left: 0; + font-style: italic; + color: #818181; +} + +.tab-osd_settings .cf_table td:last-child { + text-align: left; +} + +.tab-osd_settings .options .flash_on_connect_wrapper { + display: none; +} + +.tab-osd_settings .options .manual_baud_rate select { + width: 75px; + margin-left: 19px; +} + +.tab-osd_settings .release_info { + display: none; +} + +.tab-osd_settings .release_info .title { + line-height: 20px; + text-align: center; + font-weight: bold; + color: white; + border-bottom: 1px solid silver; + background-color: #3f4241; +} + +.tab-osd_settings .release_info .target { + color: blue; +} + +.tab-osd_settings .release_info p { + padding: 5px; +} + +.tab-osd_settings .release_info p a { + font-weight: bold; +} + +.tab-osd_settings .release_info p a:hover { + text-decoration: underline; +} + +.tab-osd_settings .release_info .notes { + padding: 5px; +} + +.tab-osd_settings .git_info { + display: none; + margin-bottom: 10px; + border: 1px solid silver; +} + +.tab-osd_settings .git_info .title { + line-height: 20px; + text-align: center; + font-weight: bold; + color: white; + border-bottom: 1px solid silver; + background-color: #3f4241; +} + +.tab-osd_settings .git_info p { + padding: 5px; +} + +.tab-osd_settings .git_info p a { + font-weight: bold; +} + +.tab-osd_settings .git_info p a:hover { + text-decoration: underline; +} + +.tab-osd_settings .buttons { + width: calc(100% - 20px); + margin-top: 10px; + bottom: 10px; +} + +.tab-osd_settings .buttons a { + display: block; + float: left; + margin: 0 10px 0 0; + padding: 0 15px 0 15px; + height: 28px; + line-height: 28px; + text-align: center; + font-weight: bold; + border: 1px solid silver; + background-color: #ececec; +} + +.tab-osd_settings .buttons a:hover { + background-color: #dedcdc; +} + +.tab-osd_settings .buttons a.flash_font.locked { + background-color: #b8b8b8; +} + +.tab-osd_settings .buttons a.flash_font.locked:hover { + cursor: default; + background-color: #b8b8b8; +} + +.tab-osd_settings .buttons a.load_remote_file.locked { + background-color: #b8b8b8; +} + +.tab-osd_settings .buttons a.load_remote_file.locked:hover { + cursor: default; + background-color: #b8b8b8; +} + +.tab-osd_settings .buttons .back { + float: right; + margin: 0; +} + +.tab-osd_settings .btn .disabled { + cursor: default; + color: #fff; + background-color: #AFAFAF; + border: none; + pointer-events: none; + text-shadow: none; + opacity: 0.5; +} + +.tab-osd_settings .display-layout label { + margin: .25em .1em; + display: inline-block; +} + +.tab-osd_settings .display-layout input { + margin: .1em 1em; +} + +.tab-osd_settings .display-layout input.position { + width: 5em; + border-bottom: 1px solid #ccc +} + +.tab-osd_settings .hide { + display: none; +} + +.tab-osd_settings .note { + padding: 1em; +} + +.tab-osd_settings .col { + display: inline-block; +} + +.tab-osd_settings .left { + float: left; +} + +.tab-osd_settings .right { + float: right; + margin-top: -7px; +} + +.tab-osd_settings .preview .gui_box_titlebar { + position: relative; +} + +.tab-osd_settings .preview .char { + display: inline-block; + padding: 0; + margin: 0; +} + +.tab-osd_settings .char.mouseover { + background: rgba(255, 255, 255, 0.4); +} + +.tab-osd_settings .char.dragging { + background: rgba(255, 255, 255, 0.4); +} + +.tab-osd_settings .char-label.mouseover { + background: rgba(255, 255, 255, 0.4); +} + +.tab-osd_settings .preview .char[draggable="true"] { + cursor: move; +} + +.tab-osd_settings .preview .row { + height: 18px; +} + +.tab-osd_settings .content_wrapper { + height: calc(100% - 41px); +} + +.font-preview { + padding-top:10px; +} + +.tab-osd_settings .content_toolbar { + text-align: right; +} + +.tab-osd_settings .content_toolbar button { + margin-right: 1em; +} + +button { + padding: 4px 10px !important; + font-family: 'open_sanssemibold', Arial, serif; + font-size: 9pt !important; + cursor: pointer; +} + +.fontbuttons { + display: inline-block; + position: absolute; + right: 1.2em; + top: .8em; +} + +.tab-osd_settings .display-field { + padding: 4px; + border-bottom: 1px solid #ddd; +} + +.tab-osd_settings .display-field.mouseover { + background: #fff; + border: 1px solid #ccc; + font-weight: 800; +} + +.tab-osd_settings .display-field input { + float: right; + width: 50px; + border-radius: 3px; + border: 1px solid #ddd; + padding: 2px; + margin-top: -2px; + display: none; + +} + +.tab-osd_settings .display-field label { + margin-left: 5px; + +} + +.tab-osd_settings .display-fields { + float: left; + margin-top: 5px; + margin-bottom: 8px; + width: 100%; + +} + +.spacer_box_title span { + font-size: 11px; + font-weight: normal; + font-family: 'open_sansregular', 'Segoe UI', Tahoma, sans-serif; +} + +.spacer_box div input[type="radio"] { + margin-right: 5px; +} + +.spacer_box div label { + margin-right: 10px; +} + +.tab-osd_settings .display-field:last-child { + border-bottom: 0; +} + +.tab-osd_settings .third_left { + float: left; + width: calc(50% - 197px); +} + +.tab-osd_settings .third_right { + float: right; + width: calc(50% - 197px); +} + +.tab-osd_settings .preview { + width: 360px; + left: calc(50% - 197px); +} + +.tab-osd_settings .preview_bfhdcompat { + width: 636px !important; /* 12 X char width */ + left: calc(50% - 335px) !important; /* width / 2 + 17 */ +} + +.tab-osd_settings .hd_bfhdcompat_43_left { + border-left: 2px solid red; + position: absolute; + /*left: 77.5px; // Calculated correct position */ + left: 70px; + height: calc(100% - 27px); +} + +.tab-osd_settings .hd_bfhdcompat_43_right { + border-right: 2px solid red; + position: absolute; + /* right: 77.5px; // Calculated correct position */ + right: 70px; + height: calc(100% - 27px); +} + +.tab-osd_settings .preview_bfhdcompat_side { + width: calc(50% - 335px) !important; +} + +.tab-osd_settings .preview_avatar { + width: 636px !important; /* 12 X char width */ + left: calc(50% - 335px) !important; /* width / 2 + 17 */ +} + +.tab-osd_settings .hd_avatar_43_left { + border-left: 2px solid red; + position: absolute; + /*left: 77.5px; // Calculated correct position */ + left: 30px; + height: calc(100% - 27px); +} + +.tab-osd_settings .hd_avatar_43_right { + border-right: 2px solid red; + position: absolute; + /* right: 77.5px; // Calculated correct position */ + right: 36px; + height: calc(100% - 27px); +} + +.tab-osd_settings .preview_avatar_side { + width: calc(50% - 335px) !important; +} + +.tab-osd_settings .preview_hdzero { + width: 600px !important; + left: calc(50% - 317px) !important; +} + +.tab-osd_settings .hdzero_43_left { + border-left: 2px solid red; + position: absolute; + left: 60px; + height: calc(100% - 27px); +} + +.tab-osd_settings .hdzero_43_right { + border-right: 2px solid red; + position: absolute; + right: 60px; + height: calc(100% - 27px); +} + +.tab-osd_settings .preview_hdzero_side { + width: calc(50% - 317px) !important; +} + +.tab-osd_settings .preview_dji_hd { + width: 720px !important; + left: calc(50% - 377px) !important; +} + +.tab-osd_settings .dji_hd_43_left { + border-left: 2px solid red; + position: absolute; + left: 84px; + height: calc(100% - 27px); +} + +.tab-osd_settings .dji_hd_43_right { + border-right: 2px solid red; + position: absolute; + right: 84px; + height: calc(100% - 27px); +} + +.tab-osd_settings .preview_dji_hd_side { + width: calc(50% - 377px) !important; +} + +.tab-osd_settings .hd_3016_top { + border-top: 2px solid blue; + position: absolute; + top: 46px; + left: 120px; + width: 360px; +} + +.tab-osd_settings .hd_3016_bottom { + border-bottom: 2px solid blue; + position: absolute; + bottom: 18px; + left: 120px; + width: 360px; +} + +.tab-osd_settings .hd_3016_left { + border-left: 2px solid blue; + position: absolute; + top: 46px; + left: 120px; + height: 288px; +} + +.tab-osd_settings .hd_3016_right { + border-right: 2px solid blue; + position: absolute; + top: 46px; + right: 120px; + height: 288px; +} + +.tab-osd_settings .hd_bfhdcompat_bottom { + border: 2px solid purple; + position: absolute; + height: 70px; + bottom: 0px; + left: 450px; + right: 0px; + pointer-events: none; +} + +.tab-osd_settings .hd_bfhdcompat_storagebox { + border: 2px solid purple; + position: absolute; + top: 115px; + height: 55px; + right: 0px; + width: 80px; + pointer-events: none; +} + +.tab-osd_settings .hd_avatar_bottom { + border-bottom: 2px solid purple; + position: absolute; + bottom: 33px; + left: 0px; + right: 0px; +} + +.tab-osd_settings .hd_avatar_storagebox_t { + border-top: 2px solid purple; + position: absolute; + top: 56px; + height: 1px; + right: 34px; + width: 48px; +} + +.tab-osd_settings .hd_avatar_storagebox_b { + border-bottom: 2px solid purple; + position: absolute; + top: 88px; + height: 1px; + right: 34px; + width: 48px; +} + +.tab-osd_settings .hd_avatar_storagebox_l { + border-left: 2px solid purple; + position: absolute; + top: 56px; + height: 35px; + right: 80px; + width: 1px; +} + +.tab-osd_settings .hd_avatar_storagebox_r { + border-right: 2px solid purple; + position: absolute; + top: 56px; + height: 35px; + right: 32px; + width: 1px; +} + +.tab-osd_settings .ntsc_bottom { + border-bottom: 2px solid green; + position: absolute; + bottom: 54px; + left: 0px; + width: 100%; +} + +.tab-osd_settings .preview { + /* please don't copy the generic background image from another project + * and replace the one that @nathantsoi took :) + */ + background: url(/images/osd-bg-1.jpg); + background-size: cover; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} + +.tab-osd_settings .settings label { + display: block; + width: 100%; + border-bottom: 1px solid #ddd; + margin-top: 5px; + padding-bottom: 5px +} + +.tab-osd_settings .settings label:last-child { + border-bottom: none; + padding-bottom: 0; +} + +.tab-osd_settings .settings input { + width: 75px; + padding-left: 3px; + height: 18px; + line-height: 20px; + text-align: left; + border: 1px solid silver; + border-radius: 3px; + font-size: 11px; + font-weight: normal; +} + +.tab-osd_settings .settings select { + width: 80px; +} + +.tab-osd_settings .settings .switchery { + margin-right: 33px; +} + +.tab-osd_settings .settings .djiCraftNameElements { + display: block; + width: 100%; + border-bottom: 1px solid #ddd; + margin-top: 5px; + padding-bottom: 5px; +} + +.no-bottom { + border-bottom: none !important; + padding-bottom: 0 i !important; +} + +@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) { + .tab-osd_settings .content_wrapper { + height: calc(100% - 30px); + } +} + +.osd__elements { + margin-bottom: 3em; +} + +.osd_layouts { + display: inline-block; + margin-bottom: 1em; + width: auto !important; +} + +.osd_search { + float: right; + width: auto !important; + margin-right: 0 !important; +} + +.tab-osd_settings label > .i18n-replaced { + display: inline-block; + left: 108px; + width: calc(100% - 110px); +} + +.tab-osd_settings .settings select, +.tab-osd_settings .settings input, +.tab-osd_settings .osd_settings .switchery, +.tab-osd_settings .unit_wrapper { + vertical-align: top; +} \ No newline at end of file diff --git a/tabs/osd_settings.html b/tabs/osd_settings.html new file mode 100644 index 000000000..1e65fe370 --- /dev/null +++ b/tabs/osd_settings.html @@ -0,0 +1,435 @@ +
    +
    +

    + + +
    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + +
    + +
    + +
    + + + + +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    + +
    + + + +
    + +
    + +
    + +
    + +
    + + + + + + + + + + +
    + +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + + + + + + + + +
    +
    +
    +
    +
    +
    +
    + + + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    + + +
    + +
    + + +
    + +
    + + + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + diff --git a/tabs/osd_settings.js b/tabs/osd_settings.js new file mode 100644 index 000000000..2296c6965 --- /dev/null +++ b/tabs/osd_settings.js @@ -0,0 +1,1739 @@ +/*global $,nwdialog*/ +'use strict'; + +var useESCTelemetry = false; +var useBaro = false; +var useCRSFRx = false; +var usePitot = false; + +var video_type = null; +var isGuidesChecked = false; + +var OSD_SETTINGS = OSD_SETTINGS || {}; + +// common functions for altitude and negative altitude alarms +function altitude_alarm_unit(osd_data) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + case 4: // GA + return 'ft'; + default: // Metric + return 'm'; + } +} + +function altitude_alarm_to_display(osd_data, value) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + case 4: // GA + // feet to meters + return Math.round(value * 3.28084) + default: // Metric + return value; + } +} + +function altitude_alarm_from_display(osd_data, value) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + case 4: // GA + // feet to meters + return Math.round(value / 3.28084); + default: // Metric + return value; + } +} + +function altitude_alarm_max(osd_data, value) { + var meters_max = 10000; + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + case 4: // GA + // meters max to feet max + return Math.trunc(meters_max * 3.28084); + default: // Metric + return meters_max; + } +} + +// Used to wrap altitude conversion functions for firmwares up +// to 1.7.3, since the altitude alarm used either m or feet +// depending on the OSD_SETTINGS display unit used (hence, no conversion) +function altitude_alarm_display_function(fn) { + return function(osd_data, value) { + return fn(osd_data, value) + } +} + +function osdMainBatteryPreview() { + var s = '16.8'; + if (Settings.getInputValue('osd_main_voltage_decimals') == 2) { + s += '3'; + } + + s += FONT.symbol(SYM.VOLT); + return FONT.symbol(SYM.BATT) + FONT.embed_dot(s); +} + +function osdmAhdrawnPreview() { + let precision = Settings.getInputValue('osd_mah_used_precision'); + let preview = "1215075".substring(0, precision); + + return preview + FONT.symbol(SYM.MAH); +} + +function osdCoordinatePreview(symbol, coordinate) { + return function() { + var digits = Settings.getInputValue('osd_coordinate_digits'); + if (!digits) { + // Setting doesn't exist in the FC. Use 11, which + // will make it look close to how it looked before 2.0 + digits = 11; + } + var integerLength = ('' + parseInt(coordinate)).length; + return FONT.symbol(symbol) + FONT.embed_dot(coordinate.toFixed(digits - integerLength)); + } +} + +// parsed fc output and output to fc, used by to OSD_SETTINGS.msp.encode +OSD_SETTINGS.initData = function () { + OSD_SETTINGS.data = { + supported: false, + preferences: { + video_system: null, + main_voltage_decimals: null, + ahi_reverse_roll: null, + crosshairs_style: null, + left_sidebar_scroll: null, + right_sidebar_scroll: null, + sidebar_scroll_arrows: null, + units: null, + stats_energy_unit: null, + }, + alarms: { + rssi: null, + batt_cap: null, + fly_minutes: null, + max_altitude: null, + dist: null, + max_neg_altitude: null, + gforce: null, + gforce_axis_min: null, + gforce_axis_max: null, + current: null, + imu_temp_alarm_min: null, + imu_temp_alarm_max: null, + baro_temp_alarm_min: null, + baro_temp_alarm_max: null, + }, + layouts: [], + layout_count: 1, // This needs to be 1 for compatibility with < 2.0 + item_count: 0, + items: [], + groups: {}, + preview: [], + isDjiHdFpv: false, + isMspDisplay: false + }; +}; + +OSD_SETTINGS.constants = { + VISIBLE: 0x2000, + VIDEO_TYPES: [ + 'AUTO', + 'PAL', + 'NTSC', + 'HDZERO', + 'DJIWTF', + 'AVATAR', + 'BF43COMPAT', + 'BFHDCOMPAT' + ], + VIDEO_LINES: { + PAL: 16, + NTSC: 13, + HDZERO: 18, + DJIWTF: 22, + AVATAR: 20, + BF43COMPAT: 16, + BFHDCOMPAT: 20 + }, + VIDEO_COLS: { + PAL: 30, + NTSC: 30, + HDZERO: 50, + DJIWTF: 60, + AVATAR: 53, + BF43COMPAT: 30, + BFHDCOMPAT: 53 + }, + VIDEO_BUFFER_CHARS: { + PAL: 480, + NTSC: 390, + HDZERO: 900, + DJIWTF: 1320, + AVATAR: 1060, + BF43COMPAT: 480, + BFHDCOMPAT: 1060 + }, + UNIT_TYPES: [ + {name: 'osdUnitImperial', value: 0}, + {name: 'osdUnitMetric', value: 1}, + {name: 'osdUnitMetricMPH', tip: 'osdUnitMetricMPHTip', value: 2}, + {name: 'osdUnitUK', tip: 'osdUnitUKTip', value: 3}, + {name: 'osdUnitGA', tip: 'osdUnitGATip', value: 4}, + ], + AHISIDEBARWIDTHPOSITION: 7, + AHISIDEBARHEIGHTPOSITION: 3, + + ALL_ALARMS: [ + { + name: 'RSSI', + field: 'rssi', + unit: '%', + min: 0, + max: 100 + }, + { + name: 'BATT_CAP', + field: 'batt_cap', + unit: 'mah', + min: 0, + max: 4294967295 + }, + { + name: 'FLY_MINUTES', + field: 'fly_minutes', + unit: 'minutes', + min: 0, + max: 600 + }, + { + name: 'MAX_ALTITUDE', + field: 'max_altitude', + unit: altitude_alarm_unit, + to_display: altitude_alarm_display_function(altitude_alarm_to_display), + from_display: altitude_alarm_display_function(altitude_alarm_from_display), + min: 0, + max: altitude_alarm_max + }, + { + name: 'MAX_NEG_ALTITUDE', + field: 'max_neg_altitude', + unit: altitude_alarm_unit, + to_display: altitude_alarm_to_display, + from_display: altitude_alarm_from_display, + min: 0, + max: altitude_alarm_max + }, + { + name: 'DIST', + field: 'dist', + unit: function(osd_data) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + return 'mi'; + case 4: // GA + return 'NM'; + default: // Metric + return 'm'; + } + }, + to_display: function(osd_data, value) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + // meters to miles + return (value / 1609.344).toFixed(2); + case 4: // GA + // metres to nautical miles + return (value / 1852.001).toFixed(2); + default: // Metric + return value; + } + }, + from_display: function(osd_data, value) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + // miles to meters + return Math.round(value * 1609.344); + case 4: // GA + return Math.round(value * 1852.001); + default: // Metric + return value; + } + }, + step: function(osd_data) { + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + case 4: // GA + return 0.01; + default: // Metric + return 1; + } + }, + min: 0, + max: function(osd_data) { + var meters_max = 50000; + switch (OSD_SETTINGS.data.preferences.units) { + case 0: // Imperial + case 3: // UK + // Meters max to miles max + return Math.trunc(meters_max / 1609.344); + case 4: // GA + // Meters max to nautical miles max + return Math.trunc(meters_max / 1852.001); + default: // Metric + return meters_max; + } + } + }, + { + name: 'GFORCE', + field: 'gforce', + min_version: '2.2.0', + step: 0.1, + unit: 'g', + to_display: function(osd_data, value) { return value / 1000 }, + from_display: function(osd_data, value) { return value * 1000 }, + min: 0, + max: 20 + }, + { + name: 'GFORCE_AXIS_MIN', + field: 'gforce_axis_min', + min_version: '2.2.0', + step: 0.1, + unit: 'g', + to_display: function(osd_data, value) { return value / 1000 }, + from_display: function(osd_data, value) { return value * 1000 }, + min: -20, + max: 20 + }, + { + name: 'GFORCE_AXIS_MAX', + field: 'gforce_axis_max', + min_version: '2.2.0', + step: 0.1, + unit: 'g', + to_display: function(osd_data, value) { return value / 1000 }, + from_display: function(osd_data, value) { return value * 1000 }, + min: -20, + max: 20 + }, + { + name: 'CURRENT', + field: 'current', + min_version: '2.2.0', + step: 1, + unit: 'A', + min: 0, + max: 255 + }, + { + name: 'IMU_TEMPERATURE_MIN', + field: 'imu_temp_alarm_min', + unit: '°C', + step: 0.5, + to_display: function(osd_data, value) { return value / 10 }, + from_display: function(osd_data, value) { return value * 10 }, + min: -55, + max: 125 + }, + { + name: 'IMU_TEMPERATURE_MAX', + field: 'imu_temp_alarm_max', + step: 0.5, + unit: '°C', + to_display: function(osd_data, value) { return value / 10 }, + from_display: function(osd_data, value) { return value * 10 }, + min: -55, + max: 125 + }, + { + name: 'BARO_TEMPERATURE_MIN', + field: 'baro_temp_alarm_min', + step: 0.5, + unit: '°C', + to_display: function(osd_data, value) { return value / 10 }, + from_display: function(osd_data, value) { return value * 10 }, + min: -55, + max: 125 + }, + { + name: 'BARO_TEMPERATURE_MAX', + field: 'baro_temp_alarm_max', + step: 0.5, + unit: '°C', + to_display: function(osd_data, value) { return value / 10 }, + from_display: function(osd_data, value) { return value * 10 }, + min: -55, + max: 125 + }, + ] +}; + +OSD_SETTINGS.reload = function(callback) { + OSD_SETTINGS.initData(); + var done = function() { + OSD_SETTINGS.updateDisplaySize(); + if (callback) { + callback(); + } + }; + + MSP.promise(MSPCodes.MSP2_CF_SERIAL_CONFIG).then(function (resp) { + $.each(SERIAL_CONFIG.ports, function(index, port){ + if(port.functions.includes('DJI_FPV')) { + OSD_SETTINGS.data.isDjiHdFpv = true; + } + if(port.functions.includes('MSP_DISPLAYPORT')) { + OSD_SETTINGS.data.isMspDisplay = true; + } + }); + }); + + /* + MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_LAYOUTS).then(function (resp) { + + OSD_SETTINGS.msp.decodeLayoutCounts(resp); + // Get data for all layouts + var ids = Array.apply(null, {length: OSD_SETTINGS.data.layout_count}).map(Number.call, Number); + var layouts = Promise.mapSeries(ids, function (layoutIndex, ii) { + var data = []; + data.push8(layoutIndex); + return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_LAYOUTS, data).then(function (resp) { + OSD_SETTINGS.msp.decodeLayout(layoutIndex, resp); + }); + }); + layouts.then(function () { + OSD_SETTINGS.updateSelectedLayout(OSD_SETTINGS.data.selected_layout || 0); + + MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_ALARMS).then(function (resp) { + OSD_SETTINGS.msp.decodeAlarms(resp); + + MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_PREFERENCES).then(function (resp) { + OSD_SETTINGS.data.supported = true; + OSD_SETTINGS.msp.decodePreferences(resp); + done(); + }); + }); + }); + }); + */ + layouts.then(function () { + //OSD_SETTINGS.updateSelectedLayout(OSD_SETTINGS.data.selected_layout || 0); + + MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_ALARMS).then(function (resp) { + OSD_SETTINGS.msp.decodeAlarms(resp); + + MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_PREFERENCES).then(function (resp) { + OSD_SETTINGS.data.supported = true; + OSD_SETTINGS.msp.decodePreferences(resp); + done(); + }); + }); + }); + +}; + +OSD_SETTINGS.saveAlarms = function(callback) { + let data = OSD_SETTINGS.msp.encodeAlarms(); + return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_SET_ALARMS, data).then(callback); +} + +OSD_SETTINGS.saveConfig = function(callback) { + return OSD_SETTINGS.saveAlarms(function () { + var data = OSD_SETTINGS.msp.encodePreferences(); + return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_SET_PREFERENCES, data).then(callback); + }); +}; + +OSD_SETTINGS.saveItem = function(item, callback) { + let pos = OSD_SETTINGS.data.items[item.id]; + let data = OSD_SETTINGS.msp.encodeLayoutItem(OSD_SETTINGS.data.selected_layout, item, pos); + return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_SET_LAYOUT_ITEM, data).then(callback); +}; + +//noinspection JSUnusedLocalSymbols +OSD_SETTINGS.msp = { + /** + * Unsigned 16 bit int for position is packed: + * 0: unused + * v: visible flag + * b: blink flag + * y: y coordinate + * x: x coordinate + * 00vb yyyy yyxx xxxx + */ + helpers: { + unpack: { + position: function (bits) { + var display_item = {}; + display_item.x = bits & 0x3F; + display_item.y = (bits >> 6) & 0x3F; + display_item.position = (display_item.y) * FONT.constants.SIZES.LINE + (display_item.x); + display_item.isVisible = (bits & OSD_SETTINGS.constants.VISIBLE) != 0; + return display_item; + } + }, + calculate: { + coords: function(display_item) { + display_item.x = (display_item.position % FONT.constants.SIZES.LINE) & 0x3F; + display_item.y = (display_item.position / FONT.constants.SIZES.LINE) & 0x3F; + return display_item; + } + }, + pack: { + position: function (display_item) { + return (display_item.isVisible ? OSD_SETTINGS.constants.VISIBLE : 0) + | ((display_item.y & 0x3F) << 6) | (display_item.x & 0x3F); + } + } + }, + + encodeAlarms: function() { + var result = []; + + result.push8(OSD_SETTINGS.data.alarms.rssi); + result.push16(OSD_SETTINGS.data.alarms.fly_minutes); + result.push16(OSD_SETTINGS.data.alarms.max_altitude); + result.push16(OSD_SETTINGS.data.alarms.dist); + result.push16(OSD_SETTINGS.data.alarms.max_neg_altitude); + result.push16(OSD_SETTINGS.data.alarms.gforce); + result.push16(OSD_SETTINGS.data.alarms.gforce_axis_min); + result.push16(OSD_SETTINGS.data.alarms.gforce_axis_max); + result.push8(OSD_SETTINGS.data.alarms.current); + result.push16(OSD_SETTINGS.data.alarms.imu_temp_alarm_min); + result.push16(OSD_SETTINGS.data.alarms.imu_temp_alarm_max); + result.push16(OSD_SETTINGS.data.alarms.baro_temp_alarm_min); + result.push16(OSD_SETTINGS.data.alarms.baro_temp_alarm_max); + return result; + }, + + decodeAlarms: function(resp) { + var alarms = resp.data; + + OSD_SETTINGS.data.alarms.rssi = alarms.readU8(); + OSD_SETTINGS.data.alarms.fly_minutes = alarms.readU16(); + OSD_SETTINGS.data.alarms.max_altitude = alarms.readU16(); + OSD_SETTINGS.data.alarms.dist = alarms.readU16(); + OSD_SETTINGS.data.alarms.max_neg_altitude = alarms.readU16(); + OSD_SETTINGS.data.alarms.gforce = alarms.readU16(); + OSD_SETTINGS.data.alarms.gforce_axis_min = alarms.read16(); + OSD_SETTINGS.data.alarms.gforce_axis_max = alarms.read16(); + OSD_SETTINGS.data.alarms.current = alarms.readU8(); + OSD_SETTINGS.data.alarms.imu_temp_alarm_min = alarms.read16(); + OSD_SETTINGS.data.alarms.imu_temp_alarm_max = alarms.read16(); + OSD_SETTINGS.data.alarms.baro_temp_alarm_min = alarms.read16(); + OSD_SETTINGS.data.alarms.baro_temp_alarm_max = alarms.read16(); + }, + + encodePreferences: function() { + var result = []; + var p = OSD_SETTINGS.data.preferences; + + result.push8(p.video_system); + result.push8(p.main_voltage_decimals); + result.push8(p.ahi_reverse_roll); + result.push8(p.crosshairs_style); + result.push8(p.left_sidebar_scroll); + result.push8(p.right_sidebar_scroll); + result.push8(p.sidebar_scroll_arrows); + result.push8(p.units); + result.push8(p.stats_energy_unit) + return result; + }, + + decodePreferences: function(resp) { + var prefs = resp.data; + var p = OSD_SETTINGS.data.preferences; + + p.video_system = prefs.readU8(); + p.main_voltage_decimals = prefs.readU8(); + p.ahi_reverse_roll = prefs.readU8(); + p.crosshairs_style = prefs.readU8(); + p.left_sidebar_scroll = prefs.readU8(); + p.right_sidebar_scroll = prefs.readU8(); + p.sidebar_scroll_arrows = prefs.readU8(); + p.units = prefs.readU8(); + p.stats_energy_unit = prefs.readU8(); + }, + + encodeLayoutItem: function(layout, item, pos) { + var result = []; + + result.push8(layout); + result.push8(item.id); + result.push16(this.helpers.pack.position(pos)); + + return result; + }, + + decodeLayoutCounts: function(resp) { + OSD_SETTINGS.data.layout_count = resp.data.readU8(); + OSD_SETTINGS.data.item_count = resp.data.readU8(); + }, + + decodeLayout: function(layoutIndex, resp) { + var items = []; + + for (var ii = 0; ii < OSD_SETTINGS.data.item_count; ii++) { + var bits = resp.data.readU16(); + items.push(this.helpers.unpack.position(bits)); + } + OSD_SETTINGS.data.layouts[layoutIndex] = items; + }, + + encodeOther: function () { + var result = [-1, OSD_SETTINGS.data.preferences.video_system]; + result.push8(OSD_SETTINGS.data.preferences.units); + // watch out, order matters! match the firmware + result.push8(OSD_SETTINGS.data.alarms.rssi); + result.push16(OSD_SETTINGS.data.alarms.batt_cap); + result.push16(OSD_SETTINGS.data.alarms.fly_minutes); + result.push16(OSD_SETTINGS.data.alarms.max_altitude); + // These might be null, since there weren't supported + // until version 1.8 + if (OSD_SETTINGS.data.alarms.dist !== null) { + result.push16(OSD_SETTINGS.data.alarms.dist); + } + if (OSD_SETTINGS.data.alarms.max_neg_altitude !== null) { + result.push16(OSD_SETTINGS.data.alarms.max_neg_altitude); + } + return result; + }, + + encodeItem: function (id, itemData) { + var buffer = []; + buffer.push8(id); + buffer.push16(this.helpers.pack.position(itemData)); + return buffer; + }, + + decode: function (payload) { + if (payload.length <= 1) { + return; + } + var view = payload.data; + var d = OSD_SETTINGS.data; + d.supported = view.readU8(); + d.preferences.video_system = view.readU8(); + d.preferences.units = view.readU8(); + + d.alarms.rssi = view.readU8(); + d.alarms.batt_cap = view.readU16(); + d.alarms.fly_minutes = view.readU16(); + d.alarms.max_altitude = view.readU16(); + + d.alarms.dist = view.readU16(); + d.alarms.max_neg_altitude = view.readU16(); + + d.items = []; + // start at the offset from the other fields + while (view.offset < view.byteLength) { + var bits = view.readU16(); + d.items.push(this.helpers.unpack.position(bits)); + } + }, +}; + +OSD_SETTINGS.GUI = {}; +OSD_SETTINGS.GUI.preview = { + onMouseEnter: function () { + var item = $(this).data('item'); + if (!item) { + return; + } + $('.field-' + item.id).addClass('mouseover'); + }, + + onMouseLeave: function () { + var item = $(this).data('item'); + if (!item) { + return; + } + $('.field-' + item.id).removeClass('mouseover') + }, + + onDragStart: function (e) { + var ev = e.originalEvent; + var item = $(ev.target).data('item'); + //noinspection JSUnresolvedVariable + ev.dataTransfer.setData("text/plain", item.id); + //noinspection JSUnresolvedVariable + ev.dataTransfer.setDragImage(item.preview_img, 6, 9); + }, + onDragOver: function (e) { + var ev = e.originalEvent; + ev.preventDefault(); + //noinspection JSUnresolvedVariable + ev.dataTransfer.dropEffect = "move"; + $(this).css({ + background: 'rgba(0,0,0,.5)' + }); + }, + + onDragLeave: function (e) { + // brute force unstyling on drag leave + $(this).removeAttr('style'); + }, + + onDrop: function (e) { + var ev = e.originalEvent; + var position = $(this).removeAttr('style').data('position');; + //noinspection JSUnresolvedVariable + var item_id = parseInt(ev.dataTransfer.getData('text')); + var item = OSD_SETTINGS.get_item(item_id); + var preview = OSD_SETTINGS.get_item_preview(item); + var line_width = 0; + var item_width = 0; + for (var ii = 0; ii < preview.length; ii++) { + if (preview[ii] == '\n') { + item_width = Math.max(item_width, line_width); + line_width = 0; + continue; + } + line_width++; + } + item_width = Math.max(item_width, line_width); + var overflows_line = FONT.constants.SIZES.LINE - ((position % FONT.constants.SIZES.LINE) + item_width); + if (overflows_line < 0) { + position += overflows_line; + } + + $('input.' + item_id + '.position').val(position).change(); + } +}; + +OSD_SETTINGS.GUI.checkAndProcessSymbolPosition = function(pos, charCode) { + if (typeof OSD_SETTINGS.data.preview[pos] === 'object' && OSD_SETTINGS.data.preview[pos][0] !== null) { + // position already in use, always put object item at position + OSD_SETTINGS.data.preview[pos] = [OSD_SETTINGS.data.preview[pos][0], charCode, 'red']; + } else { + // position not used by an object type, put character at position + // character types can overwrite character types (e.g. crosshair) + OSD_SETTINGS.data.preview[pos] = charCode; + } +}; + + +OSD_SETTINGS.GUI.updateVideoMode = function() { + // video mode + var $videoTypes = $('.video-types').empty(); + + if (!OSD_SETTINGS.data.isDjiHdFpv) { + $('#dji_settings').hide(); + } + + if (OSD_SETTINGS.data.isMspDisplay) { + if (mspVideoSystem.includes(OSD_SETTINGS.data.preferences.video_system) == false) { + OSD_SETTINGS.data.preferences.video_system = OSD_SETTINGS.constants.VIDEO_TYPES.indexOf('HDZERO'); + OSD_SETTINGS.updateDisplaySize(); + OSD_SETTINGS.GUI.saveConfig(); + } + } else { + if (analogVideoSystem.includes(OSD_SETTINGS.data.preferences.video_system) == false) { + OSD_SETTINGS.data.preferences.video_system = OSD_SETTINGS.constants.VIDEO_TYPES.indexOf('AUTO') + OSD_SETTINGS.updateDisplaySize(); + OSD_SETTINGS.GUI.saveConfig(); + } + } + + if (OSD_SETTINGS.data.isMspDisplay) { + for (var i = 0; i < OSD_SETTINGS.constants.VIDEO_TYPES.length; i++) { + if (mspVideoSystem.includes(i)) + { + $videoTypes.append( + $('') + .prop('selected', i === OSD_SETTINGS.data.preferences.video_system) + .data('type', i) + ); + } + } + } else { + for (var i = 0; i < OSD_SETTINGS.constants.VIDEO_TYPES.length; i++) { + if (analogVideoSystem.includes(i)) + { + $videoTypes.append( + $('') + .prop('selected', i === OSD_SETTINGS.data.preferences.video_system) + .data('type', i) + ); + } + } + } + + $videoTypes.change(function () { + OSD_SETTINGS.data.preferences.video_system = $(this).find(':selected').data('type'); + OSD_SETTINGS.updateDisplaySize(); + OSD_SETTINGS.GUI.saveConfig(); + }); +}; + +OSD_SETTINGS.GUI.updateUnits = function() { + // units + var $unitMode = $('#unit_mode').empty(); + var $unitTip = $('.units .cf_tip'); + + for (var i = 0; i < OSD_SETTINGS.constants.UNIT_TYPES.length; i++) { + var unitType = OSD_SETTINGS.constants.UNIT_TYPES[i]; + if (unitType.min_version && semver.lt(CONFIG.flightControllerVersion, unitType.min_version)) { + continue; + } + var name = chrome.i18n.getMessage(unitType.name); + var $option = $(''); + $option.attr('value', name); + $option.data('type', unitType.value); + if (OSD_SETTINGS.data.preferences.units === unitType.value) { + $option.prop('selected', true); + } + $unitMode.append($option); + } + function updateUnitHelp() { + var unitType = OSD_SETTINGS.constants.UNIT_TYPES[OSD_SETTINGS.data.preferences.units]; + var tip; + if (unitType.tip) { + tip = chrome.i18n.getMessage(unitType.tip); + } + if (tip) { + $unitTip.attr('title', tip); + $unitTip.fadeIn(); + } else { + $unitTip.fadeOut(); + } + } + updateUnitHelp(); + $unitMode.change(function (e) { + var selected = $(this).find(':selected'); + OSD_SETTINGS.data.preferences.units = selected.data('type'); + globalSettings.osdUnits = OSD_SETTINGS.data.preferences.units; + OSD_SETTINGS.GUI.saveConfig(); + updateUnitHelp(); + }); +}; + +OSD_SETTINGS.GUI.updateFields = function() { + // display fields on/off and position + var $tmpl = $('#osd_group_template').hide(); + // Clear previous groups, if any + $('.osd_group').remove(); + for (var ii = 0; ii < OSD_SETTINGS.constants.ALL_DISPLAY_GROUPS.length; ii++) { + var group = OSD_SETTINGS.constants.ALL_DISPLAY_GROUPS[ii]; + var groupItems = []; + for (var jj = 0; jj < group.items.length; jj++) { + var item = group.items[jj]; + if (!OSD_SETTINGS.is_item_displayed(item, group)) { + continue; + } + OSD_SETTINGS.data.groups[item.id] = group; + groupItems.push(item); + } + if (groupItems.length == 0) { + continue; + } + var groupContainer = $tmpl.clone().addClass('osd_group').show(); + groupContainer.attr('id', group.name); + var groupTitleContainer = groupContainer.find('.spacer_box_title'); + var groupTitle = chrome.i18n.getMessage(group.name); + groupTitleContainer.text(groupTitle); + var groupHelp = chrome.i18n.getMessage(group.name + '_HELP'); + if (groupHelp) { + $('
    ') + .css('margin-top', '1px') + .attr('title', groupHelp) + .appendTo(groupTitleContainer.parent()) + .jBox('Tooltip', { + delayOpen: 100, + delayClose: 100, + position: { + x: 'right', + y: 'center' + }, + outside: 'x' + }); + } + var $displayFields = groupContainer.find('.display-fields'); + for (var jj = 0; jj < groupItems.length; jj++) { + var item = groupItems[jj]; + var itemData = OSD_SETTINGS.data.items[item.id]; + var checked = itemData.isVisible ? 'checked' : ''; + var $field = $('
    '); + var name = item.name; + var nameKey = 'osdElement_' + name; + var nameMessage = chrome.i18n.getMessage(nameKey); + if (nameMessage) { + name = nameMessage; + } else { + name = inflection.titleize(name); + } + var searchTerm = $('.osd_search').val(); + if (searchTerm.length > 0 && !name.toLowerCase().includes(searchTerm.toLowerCase())) { + continue; + } + var help = chrome.i18n.getMessage(nameKey + '_HELP'); + if (help) { + $('
    ') + .css('margin-top', '1px') + .attr('title', help) + .appendTo($field) + .jBox('Tooltip', { + delayOpen: 100, + delayClose: 100, + position: { + x: 'right', + y: 'center' + }, + outside: 'x' + }); + } + $field.append( + $('') + .data('item', item) + .attr('checked', itemData.isVisible) + .change(function () { + var item = $(this).data('item'); + var itemData = OSD_SETTINGS.data.items[item.id]; + var $position = $(this).parent().find('.position.' + item.name); + itemData.isVisible = !itemData.isVisible; + + if (itemData.isVisible) { + // Ensure the element is inside the viewport, at least partially. + // In that case move it to the very first row/col, otherwise there's + // no way to reposition items that are outside the viewport. + OSD_SETTINGS.msp.helpers.calculate.coords(itemData); + if (itemData.x > OSD_SETTINGS.data.display_size.x || itemData.y > OSD_SETTINGS.data.display_size.y) { + itemData.x = itemData.y = itemData.position = 0; + } + $position.show(); + } else { + $position.hide(); + } + + OSD_SETTINGS.GUI.saveItem(item); + }) + ); + + $field.append(''); + if (item.positionable !== false) { + $field.append( + $('') + .data('item', item) + .val(itemData.position) + .change($.debounce(250, function (e) { + var item = $(this).data('item'); + var itemData = OSD_SETTINGS.data.items[item.id]; + itemData.position = parseInt($(this).val()); + OSD_SETTINGS.msp.helpers.calculate.coords(itemData); + OSD_SETTINGS.GUI.saveItem(item); + })) + ); + } + $displayFields.append($field); + } + if (groupContainer.find('.display-fields').children().size() > 0) { + $tmpl.parent().append(groupContainer); + } + } + + if ($('#videoGuidesToggle').length == false) { + $('#videoGuides').prepend( + $('') + .attr('checked', isGuidesChecked) + .on('change', function () { + OSD_SETTINGS.GUI.updateGuidesView(this.checked); + chrome.storage.local.set({'showOSD_SETTINGSGuides': this.checked}); + OSD_SETTINGS.GUI.updatePreviews(); + }) + ); + } + + if ($('#djiUnsupportedElementsToggle').length == false) { + $('#djiUnsupportedElements').prepend( + $('') + .attr('checked', OSD_SETTINGS.data.isDjiHdFpv && !OSD_SETTINGS.data.isMspDisplay) + .on('change', function () { + OSD_SETTINGS.GUI.updateDjiView(this.checked); + OSD_SETTINGS.GUI.updatePreviews(); + }) + ); + } + + // TODO: If we add more switches somewhere else, this + // needs to be called after all of them have been set up + GUI.switchery(); + + // Update the OSD_SETTINGS preview + refreshOSD_SETTINGSSwitchIndicators(); + updatePilotAndCraftNames(); + updatePanServoPreview(); +}; + +OSD_SETTINGS.GUI.removeBottomLines = function(){ + // restore + $('.display-field').removeClass('no-bottom'); + $('.gui_box').each(function(index, gui_box){ + var elements = $(gui_box).find('.display-fields, .settings').children(); + var lastVisible = false; + elements.each(function(index, element){ + if ($(element).is(':visible')) { + lastVisible = $(element); + } + }); + if (lastVisible) { + lastVisible.addClass('no-bottom'); + } + }); +}; + +OSD_SETTINGS.GUI.updateDjiMessageElements = function(on) { + $('.display-field').each(function(index, element) { + var name = $(element).find('input').attr('name'); + if (OSD_SETTINGS.DjiElements.craftNameElements.includes(name)) { + if (on) { + $(element) + .addClass('blue') + .show(); + } else if ($('#djiUnsupportedElements').find('input').is(':checked')) { + $(element).hide(); + } + } + + if (!on) { + $(element).removeClass('blue'); + } + }); + OSD_SETTINGS.GUI.removeBottomLines(); +}; + +OSD_SETTINGS.GUI.updateGuidesView = function(on) { + isHdZero = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'HDZERO'; + $('.hd_43_margin_left').toggleClass('hdzero_43_left', (isHdZero && on)) + $('.hd_43_margin_right').toggleClass('hdzero_43_right', (isHdZero && on)) + $('.hd_3016_box_top').toggleClass('hd_3016_top', (isHdZero && on)) + $('.hd_3016_box_bottom').toggleClass('hd_3016_bottom', (isHdZero && on)) + $('.hd_3016_box_left').toggleClass('hd_3016_left', (isHdZero && on)) + $('.hd_3016_box_right').toggleClass('hd_3016_right', (isHdZero && on)) + + isDJIWTF = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'DJIWTF'; + $('.hd_43_margin_left').toggleClass('dji_hd_43_left', (isDJIWTF && on)) + $('.hd_43_margin_right').toggleClass('dji_hd_43_right', (isDJIWTF && on)) + + isAvatar = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'AVATAR'; + $('.hd_43_margin_left').toggleClass('hd_avatar_43_left', (isAvatar && on)) + $('.hd_43_margin_right').toggleClass('hd_avatar_43_right', (isAvatar && on)) + $('.hd_avatar_bottom_bar').toggleClass('hd_avatar_bottom', (isAvatar && on)) + $('.hd_avatar_storage_box_top').toggleClass('hd_avatar_storagebox_t', (isAvatar && on)) + $('.hd_avatar_storage_box_bottom').toggleClass('hd_avatar_storagebox_b', (isAvatar && on)) + $('.hd_avatar_storage_box_left').toggleClass('hd_avatar_storagebox_l', (isAvatar && on)) + $('.hd_avatar_storage_box_right').toggleClass('hd_avatar_storagebox_r', (isAvatar && on)) + + isBfHdCompat = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'BFHDCOMPAT'; + $('.hd_43_margin_left').toggleClass('hd_bfhdcompat_43_left', (isBfHdCompat && on)); + $('.hd_43_margin_right').toggleClass('hd_bfhdcompat_43_right', (isBfHdCompat && on)); + $('.hd_bfhdcompat_bottom_box').toggleClass('hd_bfhdcompat_bottom', (isBfHdCompat && on)); + $('.hd_bfhdcompat_storage_box').toggleClass('hd_bfhdcompat_storagebox', (isBfHdCompat && on)); + + isPAL = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'PAL' || OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'AUTO'; + $('.pal_ntsc_box_bottom').toggleClass('ntsc_bottom', (isPAL && on)) +}; + +OSD_SETTINGS.GUI.updateDjiView = function(on) { + if (on) { + $(OSD_SETTINGS.DjiElements.emptyGroups).each(function(index, groupName) { + $('#osdGroup' + groupName).hide(); + }); + + var displayFields = $('.display-field'); + displayFields.each(function(index, element) { + var name = $(element).find('input').attr('name'); + if (!OSD_SETTINGS.DjiElements.supported.includes(name)) { + $(element).hide(); + } + }); + + var settings = $('.settings-container').find('.settings').children(); + settings.each(function(index, element) { + var name = $(element).attr('class'); + if (!OSD_SETTINGS.DjiElements.supportedSettings.includes(name)) { + $(element).hide(); + } + }); + + var alarms = $('.alarms-container').find('.settings').children(); + alarms.each(function(index, element) { + var name = $(element).attr('for'); + if (!OSD_SETTINGS.DjiElements.supportedAlarms.includes(name)) { + $(element).hide(); + } + }); + + $('.switch-indicator-container').hide(); + } else { + $(OSD_SETTINGS.DjiElements.emptyGroups).each(function(index, groupName) { + $('#osdGroup' + groupName).show(); + }); + + $('.display-field') + .show() + .removeClass('no-bottom'); + + $('.settings-container, .alarms-container').find('.settings').children() + .show() + .removeClass('no-bottom'); + + $('.switch-indicator-container').show(); + } + OSD_SETTINGS.GUI.updateDjiMessageElements($('#useCraftnameForMessages').is(':checked')); +}; + +OSD_SETTINGS.GUI.updateAlarms = function() { + $(".osd_use_airspeed_alarm").toggle(usePitot); + $(".osd_use_baro_temp_alarm").toggle(useBaro); + $(".osd_use_esc_telemetry").toggle(useESCTelemetry); + $(".osd_use_crsf").toggle(useCRSFRx); +}; + +OSD_SETTINGS.GUI.updateMapPreview = function(mapCenter, name, directionSymbol, centerSymbol) { + if ($('input[name="' + name + '"]').prop('checked')) { + var mapInitialX = OSD_SETTINGS.data.display_size.x - 2; + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(mapCenter, centerSymbol); + } +}; + +OSD_SETTINGS.GUI.updatePreviews = function() { + // buffer the preview; + OSD_SETTINGS.data.preview = []; + + // clear the buffer + for (i = 0; i < OSD_SETTINGS.data.display_size.total; i++) { + OSD_SETTINGS.data.preview.push([null, ' '.charCodeAt(0)]); + }; + + // draw all the displayed items and the drag and drop preview images + for (var ii = 0; ii < OSD_SETTINGS.data.items.length; ii++) { + var item = OSD_SETTINGS.get_item(ii); + if (!item || !OSD_SETTINGS.is_item_displayed(item, OSD_SETTINGS.data.groups[item.id])) { + continue; + } + var itemData = OSD_SETTINGS.data.items[ii]; + if (!itemData.isVisible) { + continue; + } + + if (itemData.x >= OSD_SETTINGS.data.display_size.x) + { + continue; + } + + // DJI HD FPV: Hide elements that only appear in craft name + if (OSD_SETTINGS.DjiElements.craftNameElements.includes(item.name) && + $('#djiUnsupportedElements').find('input').is(':checked')) { + continue; + } + var j = (itemData.position >= 0) ? itemData.position : itemData.position + OSD_SETTINGS.data.display_size.total; + // create the preview image + item.preview_img = new Image(); + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext("2d"); + // fill the screen buffer + var preview = OSD_SETTINGS.get_item_preview(item); + if (!preview) { + continue; + } + var x = 0; + var y = 0; + for (i = 0; i < preview.length; i++) { + var charCode = preview.charCodeAt(i); + if (charCode == '\n'.charCodeAt(0)) { + x = 0; + y++; + continue; + } + var previewPos = j + x + (y * OSD_SETTINGS.data.display_size.x); + if (previewPos >= OSD_SETTINGS.data.preview.length) { + // Character is outside the viewport + x++; + continue; + } + // test if this position already has a character placed + if (OSD_SETTINGS.data.preview[previewPos][0] !== null) { + // if so set background color to red to show user double usage of position + OSD_SETTINGS.data.preview[previewPos] = [item, charCode, 'red']; + } else { + OSD_SETTINGS.data.preview[previewPos] = [item, charCode]; + } + // draw the preview + var img = new Image(); + img.src = FONT.draw(charCode); + ctx.drawImage(img, x*FONT.constants.SIZES.CHAR_WIDTH, y*FONT.constants.SIZES.CHAR_HEIGHT); + x++; + } + item.preview_img.src = canvas.toDataURL('image/png'); + // Required for NW.js - Otherwise the will + // consume drag/drop events. + item.preview_img.style.pointerEvents = 'none'; + } + + + var centerPosition = (OSD_SETTINGS.data.display_size.x * OSD_SETTINGS.data.display_size.y / 2); + if (OSD_SETTINGS.data.display_size.y % 2 == 0) { + centerPosition += Math.floor(OSD_SETTINGS.data.display_size.x / 2); + } + + let hudCenterPosition = centerPosition - (OSD_SETTINGS.constants.VIDEO_COLS[video_type] * $('#osd_horizon_offset').val()); + + // artificial horizon + if ($('input[name="ARTIFICIAL_HORIZON"]').prop('checked')) { + for (i = 0; i < 9; i++) { + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 4 + i, SYM.AH_BAR9_0 + 4); + } + } + + // crosshairs + if ($('input[name="CROSSHAIRS"]').prop('checked')) { + crsHNumber = Settings.getInputValue('osd_crosshairs_style'); + if (crsHNumber == 1) { + // AIRCRAFT style + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 2, SYM.AH_AIRCRAFT0); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 1, SYM.AH_AIRCRAFT1); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition, SYM.AH_AIRCRAFT2); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 1, SYM.AH_AIRCRAFT3); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 2, SYM.AH_AIRCRAFT4); + } else if ((crsHNumber > 1) && (crsHNumber < 8)) { + // TYPES 3 to 8 (zero indexed) + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 1, SYM.AH_CROSSHAIRS[crsHNumber][0]); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition, SYM.AH_CROSSHAIRS[crsHNumber][1]); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 1, SYM.AH_CROSSHAIRS[crsHNumber][2]); + } else { + // DEFAULT or unknown style + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 1, SYM.AH_CENTER_LINE); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition, SYM.AH_CROSSHAIRS[crsHNumber]); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 1, SYM.AH_CENTER_LINE_RIGHT); + } + } + + // sidebars + if ($('input[name="HORIZON_SIDEBARS"]').prop('checked')) { + var hudwidth = OSD_SETTINGS.constants.AHISIDEBARWIDTHPOSITION; + var hudheight = OSD_SETTINGS.constants.AHISIDEBARHEIGHTPOSITION; + for (i = -hudheight; i <= hudheight; i++) { + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - hudwidth + (i * FONT.constants.SIZES.LINE), SYM.AH_DECORATION); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + hudwidth + (i * FONT.constants.SIZES.LINE), SYM.AH_DECORATION); + } + // AH level indicators + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - hudwidth + 1, SYM.AH_LEFT); + OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + hudwidth - 1, SYM.AH_RIGHT); + } + + OSD_SETTINGS.GUI.updateMapPreview(centerPosition, 'MAP_NORTH', 'N', SYM.HOME); + OSD_SETTINGS.GUI.updateMapPreview(centerPosition, 'MAP_TAKEOFF', 'T', SYM.HOME); + OSD_SETTINGS.GUI.updateMapPreview(centerPosition, 'RADAR', null, SYM.DIR_TO_HOME); + + // render + var $preview = $('.display-layout .preview').empty(); + var $row = $('
    '); + for (i = 0; i < OSD_SETTINGS.data.display_size.total;) { + var charCode = OSD_SETTINGS.data.preview[i]; + var colorStyle = ''; + + if (typeof charCode === 'object') { + var item = OSD_SETTINGS.data.preview[i][0]; + charCode = OSD_SETTINGS.data.preview[i][1]; + if (OSD_SETTINGS.data.preview[i][2] !== undefined) { + // if third field is set it contains a background color + colorStyle = 'style="background-color: ' + OSD_SETTINGS.data.preview[i][2] + ';"'; + } + } + var $img = $('
    ') + .on('mouseenter', OSD_SETTINGS.GUI.preview.onMouseEnter) + .on('mouseleave', OSD_SETTINGS.GUI.preview.onMouseLeave) + .on('dragover', OSD_SETTINGS.GUI.preview.onDragOver) + .on('dragleave', OSD_SETTINGS.GUI.preview.onDragLeave) + .on('drop', OSD_SETTINGS.GUI.preview.onDrop) + .data('item', item) + .data('position', i); + // Required for NW.js - Otherwise the will + // consume drag/drop events. + $img.find('img').css('pointer-events', 'none'); + if (item && item.positionable !== false) { + var nameKey = 'osdElement_' + item.name; + var nameMessage = chrome.i18n.getMessage(nameKey); + + if (!nameMessage) { + nameMessage = inflection.titleize(item.name); + } + + $img.addClass('field-' + item.id) + .data('item', item) + .prop('draggable', true) + .on('dragstart', OSD_SETTINGS.GUI.preview.onDragStart) + .prop('title', nameMessage); + } + + $row.append($img); + if (++i % OSD_SETTINGS.data.display_size.x == 0) { + $preview.append($row); + $row = $('
    '); + } + } +}; + +OSD_SETTINGS.GUI.updateAll = function() { + if (!OSD_SETTINGS.data.supported) { + $('.unsupported').fadeIn(); + return; + } + var layouts = $('.osd_layouts'); + if (OSD_SETTINGS.data.layout_count > 1) { + layouts.empty(); + for (var ii = 0; ii < OSD_SETTINGS.data.layout_count; ii++) { + var name = ii > 0 ? chrome.i18n.getMessage('osdLayoutAlternative', [ii]) : chrome.i18n.getMessage('osdLayoutDefault'); + var opt = $('
    diff --git a/tabs/osd_settings.js b/tabs/osd_settings.js deleted file mode 100644 index 2296c6965..000000000 --- a/tabs/osd_settings.js +++ /dev/null @@ -1,1739 +0,0 @@ -/*global $,nwdialog*/ -'use strict'; - -var useESCTelemetry = false; -var useBaro = false; -var useCRSFRx = false; -var usePitot = false; - -var video_type = null; -var isGuidesChecked = false; - -var OSD_SETTINGS = OSD_SETTINGS || {}; - -// common functions for altitude and negative altitude alarms -function altitude_alarm_unit(osd_data) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - case 4: // GA - return 'ft'; - default: // Metric - return 'm'; - } -} - -function altitude_alarm_to_display(osd_data, value) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - case 4: // GA - // feet to meters - return Math.round(value * 3.28084) - default: // Metric - return value; - } -} - -function altitude_alarm_from_display(osd_data, value) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - case 4: // GA - // feet to meters - return Math.round(value / 3.28084); - default: // Metric - return value; - } -} - -function altitude_alarm_max(osd_data, value) { - var meters_max = 10000; - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - case 4: // GA - // meters max to feet max - return Math.trunc(meters_max * 3.28084); - default: // Metric - return meters_max; - } -} - -// Used to wrap altitude conversion functions for firmwares up -// to 1.7.3, since the altitude alarm used either m or feet -// depending on the OSD_SETTINGS display unit used (hence, no conversion) -function altitude_alarm_display_function(fn) { - return function(osd_data, value) { - return fn(osd_data, value) - } -} - -function osdMainBatteryPreview() { - var s = '16.8'; - if (Settings.getInputValue('osd_main_voltage_decimals') == 2) { - s += '3'; - } - - s += FONT.symbol(SYM.VOLT); - return FONT.symbol(SYM.BATT) + FONT.embed_dot(s); -} - -function osdmAhdrawnPreview() { - let precision = Settings.getInputValue('osd_mah_used_precision'); - let preview = "1215075".substring(0, precision); - - return preview + FONT.symbol(SYM.MAH); -} - -function osdCoordinatePreview(symbol, coordinate) { - return function() { - var digits = Settings.getInputValue('osd_coordinate_digits'); - if (!digits) { - // Setting doesn't exist in the FC. Use 11, which - // will make it look close to how it looked before 2.0 - digits = 11; - } - var integerLength = ('' + parseInt(coordinate)).length; - return FONT.symbol(symbol) + FONT.embed_dot(coordinate.toFixed(digits - integerLength)); - } -} - -// parsed fc output and output to fc, used by to OSD_SETTINGS.msp.encode -OSD_SETTINGS.initData = function () { - OSD_SETTINGS.data = { - supported: false, - preferences: { - video_system: null, - main_voltage_decimals: null, - ahi_reverse_roll: null, - crosshairs_style: null, - left_sidebar_scroll: null, - right_sidebar_scroll: null, - sidebar_scroll_arrows: null, - units: null, - stats_energy_unit: null, - }, - alarms: { - rssi: null, - batt_cap: null, - fly_minutes: null, - max_altitude: null, - dist: null, - max_neg_altitude: null, - gforce: null, - gforce_axis_min: null, - gforce_axis_max: null, - current: null, - imu_temp_alarm_min: null, - imu_temp_alarm_max: null, - baro_temp_alarm_min: null, - baro_temp_alarm_max: null, - }, - layouts: [], - layout_count: 1, // This needs to be 1 for compatibility with < 2.0 - item_count: 0, - items: [], - groups: {}, - preview: [], - isDjiHdFpv: false, - isMspDisplay: false - }; -}; - -OSD_SETTINGS.constants = { - VISIBLE: 0x2000, - VIDEO_TYPES: [ - 'AUTO', - 'PAL', - 'NTSC', - 'HDZERO', - 'DJIWTF', - 'AVATAR', - 'BF43COMPAT', - 'BFHDCOMPAT' - ], - VIDEO_LINES: { - PAL: 16, - NTSC: 13, - HDZERO: 18, - DJIWTF: 22, - AVATAR: 20, - BF43COMPAT: 16, - BFHDCOMPAT: 20 - }, - VIDEO_COLS: { - PAL: 30, - NTSC: 30, - HDZERO: 50, - DJIWTF: 60, - AVATAR: 53, - BF43COMPAT: 30, - BFHDCOMPAT: 53 - }, - VIDEO_BUFFER_CHARS: { - PAL: 480, - NTSC: 390, - HDZERO: 900, - DJIWTF: 1320, - AVATAR: 1060, - BF43COMPAT: 480, - BFHDCOMPAT: 1060 - }, - UNIT_TYPES: [ - {name: 'osdUnitImperial', value: 0}, - {name: 'osdUnitMetric', value: 1}, - {name: 'osdUnitMetricMPH', tip: 'osdUnitMetricMPHTip', value: 2}, - {name: 'osdUnitUK', tip: 'osdUnitUKTip', value: 3}, - {name: 'osdUnitGA', tip: 'osdUnitGATip', value: 4}, - ], - AHISIDEBARWIDTHPOSITION: 7, - AHISIDEBARHEIGHTPOSITION: 3, - - ALL_ALARMS: [ - { - name: 'RSSI', - field: 'rssi', - unit: '%', - min: 0, - max: 100 - }, - { - name: 'BATT_CAP', - field: 'batt_cap', - unit: 'mah', - min: 0, - max: 4294967295 - }, - { - name: 'FLY_MINUTES', - field: 'fly_minutes', - unit: 'minutes', - min: 0, - max: 600 - }, - { - name: 'MAX_ALTITUDE', - field: 'max_altitude', - unit: altitude_alarm_unit, - to_display: altitude_alarm_display_function(altitude_alarm_to_display), - from_display: altitude_alarm_display_function(altitude_alarm_from_display), - min: 0, - max: altitude_alarm_max - }, - { - name: 'MAX_NEG_ALTITUDE', - field: 'max_neg_altitude', - unit: altitude_alarm_unit, - to_display: altitude_alarm_to_display, - from_display: altitude_alarm_from_display, - min: 0, - max: altitude_alarm_max - }, - { - name: 'DIST', - field: 'dist', - unit: function(osd_data) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - return 'mi'; - case 4: // GA - return 'NM'; - default: // Metric - return 'm'; - } - }, - to_display: function(osd_data, value) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - // meters to miles - return (value / 1609.344).toFixed(2); - case 4: // GA - // metres to nautical miles - return (value / 1852.001).toFixed(2); - default: // Metric - return value; - } - }, - from_display: function(osd_data, value) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - // miles to meters - return Math.round(value * 1609.344); - case 4: // GA - return Math.round(value * 1852.001); - default: // Metric - return value; - } - }, - step: function(osd_data) { - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - case 4: // GA - return 0.01; - default: // Metric - return 1; - } - }, - min: 0, - max: function(osd_data) { - var meters_max = 50000; - switch (OSD_SETTINGS.data.preferences.units) { - case 0: // Imperial - case 3: // UK - // Meters max to miles max - return Math.trunc(meters_max / 1609.344); - case 4: // GA - // Meters max to nautical miles max - return Math.trunc(meters_max / 1852.001); - default: // Metric - return meters_max; - } - } - }, - { - name: 'GFORCE', - field: 'gforce', - min_version: '2.2.0', - step: 0.1, - unit: 'g', - to_display: function(osd_data, value) { return value / 1000 }, - from_display: function(osd_data, value) { return value * 1000 }, - min: 0, - max: 20 - }, - { - name: 'GFORCE_AXIS_MIN', - field: 'gforce_axis_min', - min_version: '2.2.0', - step: 0.1, - unit: 'g', - to_display: function(osd_data, value) { return value / 1000 }, - from_display: function(osd_data, value) { return value * 1000 }, - min: -20, - max: 20 - }, - { - name: 'GFORCE_AXIS_MAX', - field: 'gforce_axis_max', - min_version: '2.2.0', - step: 0.1, - unit: 'g', - to_display: function(osd_data, value) { return value / 1000 }, - from_display: function(osd_data, value) { return value * 1000 }, - min: -20, - max: 20 - }, - { - name: 'CURRENT', - field: 'current', - min_version: '2.2.0', - step: 1, - unit: 'A', - min: 0, - max: 255 - }, - { - name: 'IMU_TEMPERATURE_MIN', - field: 'imu_temp_alarm_min', - unit: '°C', - step: 0.5, - to_display: function(osd_data, value) { return value / 10 }, - from_display: function(osd_data, value) { return value * 10 }, - min: -55, - max: 125 - }, - { - name: 'IMU_TEMPERATURE_MAX', - field: 'imu_temp_alarm_max', - step: 0.5, - unit: '°C', - to_display: function(osd_data, value) { return value / 10 }, - from_display: function(osd_data, value) { return value * 10 }, - min: -55, - max: 125 - }, - { - name: 'BARO_TEMPERATURE_MIN', - field: 'baro_temp_alarm_min', - step: 0.5, - unit: '°C', - to_display: function(osd_data, value) { return value / 10 }, - from_display: function(osd_data, value) { return value * 10 }, - min: -55, - max: 125 - }, - { - name: 'BARO_TEMPERATURE_MAX', - field: 'baro_temp_alarm_max', - step: 0.5, - unit: '°C', - to_display: function(osd_data, value) { return value / 10 }, - from_display: function(osd_data, value) { return value * 10 }, - min: -55, - max: 125 - }, - ] -}; - -OSD_SETTINGS.reload = function(callback) { - OSD_SETTINGS.initData(); - var done = function() { - OSD_SETTINGS.updateDisplaySize(); - if (callback) { - callback(); - } - }; - - MSP.promise(MSPCodes.MSP2_CF_SERIAL_CONFIG).then(function (resp) { - $.each(SERIAL_CONFIG.ports, function(index, port){ - if(port.functions.includes('DJI_FPV')) { - OSD_SETTINGS.data.isDjiHdFpv = true; - } - if(port.functions.includes('MSP_DISPLAYPORT')) { - OSD_SETTINGS.data.isMspDisplay = true; - } - }); - }); - - /* - MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_LAYOUTS).then(function (resp) { - - OSD_SETTINGS.msp.decodeLayoutCounts(resp); - // Get data for all layouts - var ids = Array.apply(null, {length: OSD_SETTINGS.data.layout_count}).map(Number.call, Number); - var layouts = Promise.mapSeries(ids, function (layoutIndex, ii) { - var data = []; - data.push8(layoutIndex); - return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_LAYOUTS, data).then(function (resp) { - OSD_SETTINGS.msp.decodeLayout(layoutIndex, resp); - }); - }); - layouts.then(function () { - OSD_SETTINGS.updateSelectedLayout(OSD_SETTINGS.data.selected_layout || 0); - - MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_ALARMS).then(function (resp) { - OSD_SETTINGS.msp.decodeAlarms(resp); - - MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_PREFERENCES).then(function (resp) { - OSD_SETTINGS.data.supported = true; - OSD_SETTINGS.msp.decodePreferences(resp); - done(); - }); - }); - }); - }); - */ - layouts.then(function () { - //OSD_SETTINGS.updateSelectedLayout(OSD_SETTINGS.data.selected_layout || 0); - - MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_ALARMS).then(function (resp) { - OSD_SETTINGS.msp.decodeAlarms(resp); - - MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_PREFERENCES).then(function (resp) { - OSD_SETTINGS.data.supported = true; - OSD_SETTINGS.msp.decodePreferences(resp); - done(); - }); - }); - }); - -}; - -OSD_SETTINGS.saveAlarms = function(callback) { - let data = OSD_SETTINGS.msp.encodeAlarms(); - return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_SET_ALARMS, data).then(callback); -} - -OSD_SETTINGS.saveConfig = function(callback) { - return OSD_SETTINGS.saveAlarms(function () { - var data = OSD_SETTINGS.msp.encodePreferences(); - return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_SET_PREFERENCES, data).then(callback); - }); -}; - -OSD_SETTINGS.saveItem = function(item, callback) { - let pos = OSD_SETTINGS.data.items[item.id]; - let data = OSD_SETTINGS.msp.encodeLayoutItem(OSD_SETTINGS.data.selected_layout, item, pos); - return MSP.promise(MSPCodes.MSP2_INAV_OSD_SETTINGS_SET_LAYOUT_ITEM, data).then(callback); -}; - -//noinspection JSUnusedLocalSymbols -OSD_SETTINGS.msp = { - /** - * Unsigned 16 bit int for position is packed: - * 0: unused - * v: visible flag - * b: blink flag - * y: y coordinate - * x: x coordinate - * 00vb yyyy yyxx xxxx - */ - helpers: { - unpack: { - position: function (bits) { - var display_item = {}; - display_item.x = bits & 0x3F; - display_item.y = (bits >> 6) & 0x3F; - display_item.position = (display_item.y) * FONT.constants.SIZES.LINE + (display_item.x); - display_item.isVisible = (bits & OSD_SETTINGS.constants.VISIBLE) != 0; - return display_item; - } - }, - calculate: { - coords: function(display_item) { - display_item.x = (display_item.position % FONT.constants.SIZES.LINE) & 0x3F; - display_item.y = (display_item.position / FONT.constants.SIZES.LINE) & 0x3F; - return display_item; - } - }, - pack: { - position: function (display_item) { - return (display_item.isVisible ? OSD_SETTINGS.constants.VISIBLE : 0) - | ((display_item.y & 0x3F) << 6) | (display_item.x & 0x3F); - } - } - }, - - encodeAlarms: function() { - var result = []; - - result.push8(OSD_SETTINGS.data.alarms.rssi); - result.push16(OSD_SETTINGS.data.alarms.fly_minutes); - result.push16(OSD_SETTINGS.data.alarms.max_altitude); - result.push16(OSD_SETTINGS.data.alarms.dist); - result.push16(OSD_SETTINGS.data.alarms.max_neg_altitude); - result.push16(OSD_SETTINGS.data.alarms.gforce); - result.push16(OSD_SETTINGS.data.alarms.gforce_axis_min); - result.push16(OSD_SETTINGS.data.alarms.gforce_axis_max); - result.push8(OSD_SETTINGS.data.alarms.current); - result.push16(OSD_SETTINGS.data.alarms.imu_temp_alarm_min); - result.push16(OSD_SETTINGS.data.alarms.imu_temp_alarm_max); - result.push16(OSD_SETTINGS.data.alarms.baro_temp_alarm_min); - result.push16(OSD_SETTINGS.data.alarms.baro_temp_alarm_max); - return result; - }, - - decodeAlarms: function(resp) { - var alarms = resp.data; - - OSD_SETTINGS.data.alarms.rssi = alarms.readU8(); - OSD_SETTINGS.data.alarms.fly_minutes = alarms.readU16(); - OSD_SETTINGS.data.alarms.max_altitude = alarms.readU16(); - OSD_SETTINGS.data.alarms.dist = alarms.readU16(); - OSD_SETTINGS.data.alarms.max_neg_altitude = alarms.readU16(); - OSD_SETTINGS.data.alarms.gforce = alarms.readU16(); - OSD_SETTINGS.data.alarms.gforce_axis_min = alarms.read16(); - OSD_SETTINGS.data.alarms.gforce_axis_max = alarms.read16(); - OSD_SETTINGS.data.alarms.current = alarms.readU8(); - OSD_SETTINGS.data.alarms.imu_temp_alarm_min = alarms.read16(); - OSD_SETTINGS.data.alarms.imu_temp_alarm_max = alarms.read16(); - OSD_SETTINGS.data.alarms.baro_temp_alarm_min = alarms.read16(); - OSD_SETTINGS.data.alarms.baro_temp_alarm_max = alarms.read16(); - }, - - encodePreferences: function() { - var result = []; - var p = OSD_SETTINGS.data.preferences; - - result.push8(p.video_system); - result.push8(p.main_voltage_decimals); - result.push8(p.ahi_reverse_roll); - result.push8(p.crosshairs_style); - result.push8(p.left_sidebar_scroll); - result.push8(p.right_sidebar_scroll); - result.push8(p.sidebar_scroll_arrows); - result.push8(p.units); - result.push8(p.stats_energy_unit) - return result; - }, - - decodePreferences: function(resp) { - var prefs = resp.data; - var p = OSD_SETTINGS.data.preferences; - - p.video_system = prefs.readU8(); - p.main_voltage_decimals = prefs.readU8(); - p.ahi_reverse_roll = prefs.readU8(); - p.crosshairs_style = prefs.readU8(); - p.left_sidebar_scroll = prefs.readU8(); - p.right_sidebar_scroll = prefs.readU8(); - p.sidebar_scroll_arrows = prefs.readU8(); - p.units = prefs.readU8(); - p.stats_energy_unit = prefs.readU8(); - }, - - encodeLayoutItem: function(layout, item, pos) { - var result = []; - - result.push8(layout); - result.push8(item.id); - result.push16(this.helpers.pack.position(pos)); - - return result; - }, - - decodeLayoutCounts: function(resp) { - OSD_SETTINGS.data.layout_count = resp.data.readU8(); - OSD_SETTINGS.data.item_count = resp.data.readU8(); - }, - - decodeLayout: function(layoutIndex, resp) { - var items = []; - - for (var ii = 0; ii < OSD_SETTINGS.data.item_count; ii++) { - var bits = resp.data.readU16(); - items.push(this.helpers.unpack.position(bits)); - } - OSD_SETTINGS.data.layouts[layoutIndex] = items; - }, - - encodeOther: function () { - var result = [-1, OSD_SETTINGS.data.preferences.video_system]; - result.push8(OSD_SETTINGS.data.preferences.units); - // watch out, order matters! match the firmware - result.push8(OSD_SETTINGS.data.alarms.rssi); - result.push16(OSD_SETTINGS.data.alarms.batt_cap); - result.push16(OSD_SETTINGS.data.alarms.fly_minutes); - result.push16(OSD_SETTINGS.data.alarms.max_altitude); - // These might be null, since there weren't supported - // until version 1.8 - if (OSD_SETTINGS.data.alarms.dist !== null) { - result.push16(OSD_SETTINGS.data.alarms.dist); - } - if (OSD_SETTINGS.data.alarms.max_neg_altitude !== null) { - result.push16(OSD_SETTINGS.data.alarms.max_neg_altitude); - } - return result; - }, - - encodeItem: function (id, itemData) { - var buffer = []; - buffer.push8(id); - buffer.push16(this.helpers.pack.position(itemData)); - return buffer; - }, - - decode: function (payload) { - if (payload.length <= 1) { - return; - } - var view = payload.data; - var d = OSD_SETTINGS.data; - d.supported = view.readU8(); - d.preferences.video_system = view.readU8(); - d.preferences.units = view.readU8(); - - d.alarms.rssi = view.readU8(); - d.alarms.batt_cap = view.readU16(); - d.alarms.fly_minutes = view.readU16(); - d.alarms.max_altitude = view.readU16(); - - d.alarms.dist = view.readU16(); - d.alarms.max_neg_altitude = view.readU16(); - - d.items = []; - // start at the offset from the other fields - while (view.offset < view.byteLength) { - var bits = view.readU16(); - d.items.push(this.helpers.unpack.position(bits)); - } - }, -}; - -OSD_SETTINGS.GUI = {}; -OSD_SETTINGS.GUI.preview = { - onMouseEnter: function () { - var item = $(this).data('item'); - if (!item) { - return; - } - $('.field-' + item.id).addClass('mouseover'); - }, - - onMouseLeave: function () { - var item = $(this).data('item'); - if (!item) { - return; - } - $('.field-' + item.id).removeClass('mouseover') - }, - - onDragStart: function (e) { - var ev = e.originalEvent; - var item = $(ev.target).data('item'); - //noinspection JSUnresolvedVariable - ev.dataTransfer.setData("text/plain", item.id); - //noinspection JSUnresolvedVariable - ev.dataTransfer.setDragImage(item.preview_img, 6, 9); - }, - onDragOver: function (e) { - var ev = e.originalEvent; - ev.preventDefault(); - //noinspection JSUnresolvedVariable - ev.dataTransfer.dropEffect = "move"; - $(this).css({ - background: 'rgba(0,0,0,.5)' - }); - }, - - onDragLeave: function (e) { - // brute force unstyling on drag leave - $(this).removeAttr('style'); - }, - - onDrop: function (e) { - var ev = e.originalEvent; - var position = $(this).removeAttr('style').data('position');; - //noinspection JSUnresolvedVariable - var item_id = parseInt(ev.dataTransfer.getData('text')); - var item = OSD_SETTINGS.get_item(item_id); - var preview = OSD_SETTINGS.get_item_preview(item); - var line_width = 0; - var item_width = 0; - for (var ii = 0; ii < preview.length; ii++) { - if (preview[ii] == '\n') { - item_width = Math.max(item_width, line_width); - line_width = 0; - continue; - } - line_width++; - } - item_width = Math.max(item_width, line_width); - var overflows_line = FONT.constants.SIZES.LINE - ((position % FONT.constants.SIZES.LINE) + item_width); - if (overflows_line < 0) { - position += overflows_line; - } - - $('input.' + item_id + '.position').val(position).change(); - } -}; - -OSD_SETTINGS.GUI.checkAndProcessSymbolPosition = function(pos, charCode) { - if (typeof OSD_SETTINGS.data.preview[pos] === 'object' && OSD_SETTINGS.data.preview[pos][0] !== null) { - // position already in use, always put object item at position - OSD_SETTINGS.data.preview[pos] = [OSD_SETTINGS.data.preview[pos][0], charCode, 'red']; - } else { - // position not used by an object type, put character at position - // character types can overwrite character types (e.g. crosshair) - OSD_SETTINGS.data.preview[pos] = charCode; - } -}; - - -OSD_SETTINGS.GUI.updateVideoMode = function() { - // video mode - var $videoTypes = $('.video-types').empty(); - - if (!OSD_SETTINGS.data.isDjiHdFpv) { - $('#dji_settings').hide(); - } - - if (OSD_SETTINGS.data.isMspDisplay) { - if (mspVideoSystem.includes(OSD_SETTINGS.data.preferences.video_system) == false) { - OSD_SETTINGS.data.preferences.video_system = OSD_SETTINGS.constants.VIDEO_TYPES.indexOf('HDZERO'); - OSD_SETTINGS.updateDisplaySize(); - OSD_SETTINGS.GUI.saveConfig(); - } - } else { - if (analogVideoSystem.includes(OSD_SETTINGS.data.preferences.video_system) == false) { - OSD_SETTINGS.data.preferences.video_system = OSD_SETTINGS.constants.VIDEO_TYPES.indexOf('AUTO') - OSD_SETTINGS.updateDisplaySize(); - OSD_SETTINGS.GUI.saveConfig(); - } - } - - if (OSD_SETTINGS.data.isMspDisplay) { - for (var i = 0; i < OSD_SETTINGS.constants.VIDEO_TYPES.length; i++) { - if (mspVideoSystem.includes(i)) - { - $videoTypes.append( - $('') - .prop('selected', i === OSD_SETTINGS.data.preferences.video_system) - .data('type', i) - ); - } - } - } else { - for (var i = 0; i < OSD_SETTINGS.constants.VIDEO_TYPES.length; i++) { - if (analogVideoSystem.includes(i)) - { - $videoTypes.append( - $('') - .prop('selected', i === OSD_SETTINGS.data.preferences.video_system) - .data('type', i) - ); - } - } - } - - $videoTypes.change(function () { - OSD_SETTINGS.data.preferences.video_system = $(this).find(':selected').data('type'); - OSD_SETTINGS.updateDisplaySize(); - OSD_SETTINGS.GUI.saveConfig(); - }); -}; - -OSD_SETTINGS.GUI.updateUnits = function() { - // units - var $unitMode = $('#unit_mode').empty(); - var $unitTip = $('.units .cf_tip'); - - for (var i = 0; i < OSD_SETTINGS.constants.UNIT_TYPES.length; i++) { - var unitType = OSD_SETTINGS.constants.UNIT_TYPES[i]; - if (unitType.min_version && semver.lt(CONFIG.flightControllerVersion, unitType.min_version)) { - continue; - } - var name = chrome.i18n.getMessage(unitType.name); - var $option = $(''); - $option.attr('value', name); - $option.data('type', unitType.value); - if (OSD_SETTINGS.data.preferences.units === unitType.value) { - $option.prop('selected', true); - } - $unitMode.append($option); - } - function updateUnitHelp() { - var unitType = OSD_SETTINGS.constants.UNIT_TYPES[OSD_SETTINGS.data.preferences.units]; - var tip; - if (unitType.tip) { - tip = chrome.i18n.getMessage(unitType.tip); - } - if (tip) { - $unitTip.attr('title', tip); - $unitTip.fadeIn(); - } else { - $unitTip.fadeOut(); - } - } - updateUnitHelp(); - $unitMode.change(function (e) { - var selected = $(this).find(':selected'); - OSD_SETTINGS.data.preferences.units = selected.data('type'); - globalSettings.osdUnits = OSD_SETTINGS.data.preferences.units; - OSD_SETTINGS.GUI.saveConfig(); - updateUnitHelp(); - }); -}; - -OSD_SETTINGS.GUI.updateFields = function() { - // display fields on/off and position - var $tmpl = $('#osd_group_template').hide(); - // Clear previous groups, if any - $('.osd_group').remove(); - for (var ii = 0; ii < OSD_SETTINGS.constants.ALL_DISPLAY_GROUPS.length; ii++) { - var group = OSD_SETTINGS.constants.ALL_DISPLAY_GROUPS[ii]; - var groupItems = []; - for (var jj = 0; jj < group.items.length; jj++) { - var item = group.items[jj]; - if (!OSD_SETTINGS.is_item_displayed(item, group)) { - continue; - } - OSD_SETTINGS.data.groups[item.id] = group; - groupItems.push(item); - } - if (groupItems.length == 0) { - continue; - } - var groupContainer = $tmpl.clone().addClass('osd_group').show(); - groupContainer.attr('id', group.name); - var groupTitleContainer = groupContainer.find('.spacer_box_title'); - var groupTitle = chrome.i18n.getMessage(group.name); - groupTitleContainer.text(groupTitle); - var groupHelp = chrome.i18n.getMessage(group.name + '_HELP'); - if (groupHelp) { - $('
    ') - .css('margin-top', '1px') - .attr('title', groupHelp) - .appendTo(groupTitleContainer.parent()) - .jBox('Tooltip', { - delayOpen: 100, - delayClose: 100, - position: { - x: 'right', - y: 'center' - }, - outside: 'x' - }); - } - var $displayFields = groupContainer.find('.display-fields'); - for (var jj = 0; jj < groupItems.length; jj++) { - var item = groupItems[jj]; - var itemData = OSD_SETTINGS.data.items[item.id]; - var checked = itemData.isVisible ? 'checked' : ''; - var $field = $('
    '); - var name = item.name; - var nameKey = 'osdElement_' + name; - var nameMessage = chrome.i18n.getMessage(nameKey); - if (nameMessage) { - name = nameMessage; - } else { - name = inflection.titleize(name); - } - var searchTerm = $('.osd_search').val(); - if (searchTerm.length > 0 && !name.toLowerCase().includes(searchTerm.toLowerCase())) { - continue; - } - var help = chrome.i18n.getMessage(nameKey + '_HELP'); - if (help) { - $('
    ') - .css('margin-top', '1px') - .attr('title', help) - .appendTo($field) - .jBox('Tooltip', { - delayOpen: 100, - delayClose: 100, - position: { - x: 'right', - y: 'center' - }, - outside: 'x' - }); - } - $field.append( - $('') - .data('item', item) - .attr('checked', itemData.isVisible) - .change(function () { - var item = $(this).data('item'); - var itemData = OSD_SETTINGS.data.items[item.id]; - var $position = $(this).parent().find('.position.' + item.name); - itemData.isVisible = !itemData.isVisible; - - if (itemData.isVisible) { - // Ensure the element is inside the viewport, at least partially. - // In that case move it to the very first row/col, otherwise there's - // no way to reposition items that are outside the viewport. - OSD_SETTINGS.msp.helpers.calculate.coords(itemData); - if (itemData.x > OSD_SETTINGS.data.display_size.x || itemData.y > OSD_SETTINGS.data.display_size.y) { - itemData.x = itemData.y = itemData.position = 0; - } - $position.show(); - } else { - $position.hide(); - } - - OSD_SETTINGS.GUI.saveItem(item); - }) - ); - - $field.append(''); - if (item.positionable !== false) { - $field.append( - $('') - .data('item', item) - .val(itemData.position) - .change($.debounce(250, function (e) { - var item = $(this).data('item'); - var itemData = OSD_SETTINGS.data.items[item.id]; - itemData.position = parseInt($(this).val()); - OSD_SETTINGS.msp.helpers.calculate.coords(itemData); - OSD_SETTINGS.GUI.saveItem(item); - })) - ); - } - $displayFields.append($field); - } - if (groupContainer.find('.display-fields').children().size() > 0) { - $tmpl.parent().append(groupContainer); - } - } - - if ($('#videoGuidesToggle').length == false) { - $('#videoGuides').prepend( - $('') - .attr('checked', isGuidesChecked) - .on('change', function () { - OSD_SETTINGS.GUI.updateGuidesView(this.checked); - chrome.storage.local.set({'showOSD_SETTINGSGuides': this.checked}); - OSD_SETTINGS.GUI.updatePreviews(); - }) - ); - } - - if ($('#djiUnsupportedElementsToggle').length == false) { - $('#djiUnsupportedElements').prepend( - $('') - .attr('checked', OSD_SETTINGS.data.isDjiHdFpv && !OSD_SETTINGS.data.isMspDisplay) - .on('change', function () { - OSD_SETTINGS.GUI.updateDjiView(this.checked); - OSD_SETTINGS.GUI.updatePreviews(); - }) - ); - } - - // TODO: If we add more switches somewhere else, this - // needs to be called after all of them have been set up - GUI.switchery(); - - // Update the OSD_SETTINGS preview - refreshOSD_SETTINGSSwitchIndicators(); - updatePilotAndCraftNames(); - updatePanServoPreview(); -}; - -OSD_SETTINGS.GUI.removeBottomLines = function(){ - // restore - $('.display-field').removeClass('no-bottom'); - $('.gui_box').each(function(index, gui_box){ - var elements = $(gui_box).find('.display-fields, .settings').children(); - var lastVisible = false; - elements.each(function(index, element){ - if ($(element).is(':visible')) { - lastVisible = $(element); - } - }); - if (lastVisible) { - lastVisible.addClass('no-bottom'); - } - }); -}; - -OSD_SETTINGS.GUI.updateDjiMessageElements = function(on) { - $('.display-field').each(function(index, element) { - var name = $(element).find('input').attr('name'); - if (OSD_SETTINGS.DjiElements.craftNameElements.includes(name)) { - if (on) { - $(element) - .addClass('blue') - .show(); - } else if ($('#djiUnsupportedElements').find('input').is(':checked')) { - $(element).hide(); - } - } - - if (!on) { - $(element).removeClass('blue'); - } - }); - OSD_SETTINGS.GUI.removeBottomLines(); -}; - -OSD_SETTINGS.GUI.updateGuidesView = function(on) { - isHdZero = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'HDZERO'; - $('.hd_43_margin_left').toggleClass('hdzero_43_left', (isHdZero && on)) - $('.hd_43_margin_right').toggleClass('hdzero_43_right', (isHdZero && on)) - $('.hd_3016_box_top').toggleClass('hd_3016_top', (isHdZero && on)) - $('.hd_3016_box_bottom').toggleClass('hd_3016_bottom', (isHdZero && on)) - $('.hd_3016_box_left').toggleClass('hd_3016_left', (isHdZero && on)) - $('.hd_3016_box_right').toggleClass('hd_3016_right', (isHdZero && on)) - - isDJIWTF = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'DJIWTF'; - $('.hd_43_margin_left').toggleClass('dji_hd_43_left', (isDJIWTF && on)) - $('.hd_43_margin_right').toggleClass('dji_hd_43_right', (isDJIWTF && on)) - - isAvatar = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'AVATAR'; - $('.hd_43_margin_left').toggleClass('hd_avatar_43_left', (isAvatar && on)) - $('.hd_43_margin_right').toggleClass('hd_avatar_43_right', (isAvatar && on)) - $('.hd_avatar_bottom_bar').toggleClass('hd_avatar_bottom', (isAvatar && on)) - $('.hd_avatar_storage_box_top').toggleClass('hd_avatar_storagebox_t', (isAvatar && on)) - $('.hd_avatar_storage_box_bottom').toggleClass('hd_avatar_storagebox_b', (isAvatar && on)) - $('.hd_avatar_storage_box_left').toggleClass('hd_avatar_storagebox_l', (isAvatar && on)) - $('.hd_avatar_storage_box_right').toggleClass('hd_avatar_storagebox_r', (isAvatar && on)) - - isBfHdCompat = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'BFHDCOMPAT'; - $('.hd_43_margin_left').toggleClass('hd_bfhdcompat_43_left', (isBfHdCompat && on)); - $('.hd_43_margin_right').toggleClass('hd_bfhdcompat_43_right', (isBfHdCompat && on)); - $('.hd_bfhdcompat_bottom_box').toggleClass('hd_bfhdcompat_bottom', (isBfHdCompat && on)); - $('.hd_bfhdcompat_storage_box').toggleClass('hd_bfhdcompat_storagebox', (isBfHdCompat && on)); - - isPAL = OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'PAL' || OSD_SETTINGS.constants.VIDEO_TYPES[OSD_SETTINGS.data.preferences.video_system] == 'AUTO'; - $('.pal_ntsc_box_bottom').toggleClass('ntsc_bottom', (isPAL && on)) -}; - -OSD_SETTINGS.GUI.updateDjiView = function(on) { - if (on) { - $(OSD_SETTINGS.DjiElements.emptyGroups).each(function(index, groupName) { - $('#osdGroup' + groupName).hide(); - }); - - var displayFields = $('.display-field'); - displayFields.each(function(index, element) { - var name = $(element).find('input').attr('name'); - if (!OSD_SETTINGS.DjiElements.supported.includes(name)) { - $(element).hide(); - } - }); - - var settings = $('.settings-container').find('.settings').children(); - settings.each(function(index, element) { - var name = $(element).attr('class'); - if (!OSD_SETTINGS.DjiElements.supportedSettings.includes(name)) { - $(element).hide(); - } - }); - - var alarms = $('.alarms-container').find('.settings').children(); - alarms.each(function(index, element) { - var name = $(element).attr('for'); - if (!OSD_SETTINGS.DjiElements.supportedAlarms.includes(name)) { - $(element).hide(); - } - }); - - $('.switch-indicator-container').hide(); - } else { - $(OSD_SETTINGS.DjiElements.emptyGroups).each(function(index, groupName) { - $('#osdGroup' + groupName).show(); - }); - - $('.display-field') - .show() - .removeClass('no-bottom'); - - $('.settings-container, .alarms-container').find('.settings').children() - .show() - .removeClass('no-bottom'); - - $('.switch-indicator-container').show(); - } - OSD_SETTINGS.GUI.updateDjiMessageElements($('#useCraftnameForMessages').is(':checked')); -}; - -OSD_SETTINGS.GUI.updateAlarms = function() { - $(".osd_use_airspeed_alarm").toggle(usePitot); - $(".osd_use_baro_temp_alarm").toggle(useBaro); - $(".osd_use_esc_telemetry").toggle(useESCTelemetry); - $(".osd_use_crsf").toggle(useCRSFRx); -}; - -OSD_SETTINGS.GUI.updateMapPreview = function(mapCenter, name, directionSymbol, centerSymbol) { - if ($('input[name="' + name + '"]').prop('checked')) { - var mapInitialX = OSD_SETTINGS.data.display_size.x - 2; - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(mapCenter, centerSymbol); - } -}; - -OSD_SETTINGS.GUI.updatePreviews = function() { - // buffer the preview; - OSD_SETTINGS.data.preview = []; - - // clear the buffer - for (i = 0; i < OSD_SETTINGS.data.display_size.total; i++) { - OSD_SETTINGS.data.preview.push([null, ' '.charCodeAt(0)]); - }; - - // draw all the displayed items and the drag and drop preview images - for (var ii = 0; ii < OSD_SETTINGS.data.items.length; ii++) { - var item = OSD_SETTINGS.get_item(ii); - if (!item || !OSD_SETTINGS.is_item_displayed(item, OSD_SETTINGS.data.groups[item.id])) { - continue; - } - var itemData = OSD_SETTINGS.data.items[ii]; - if (!itemData.isVisible) { - continue; - } - - if (itemData.x >= OSD_SETTINGS.data.display_size.x) - { - continue; - } - - // DJI HD FPV: Hide elements that only appear in craft name - if (OSD_SETTINGS.DjiElements.craftNameElements.includes(item.name) && - $('#djiUnsupportedElements').find('input').is(':checked')) { - continue; - } - var j = (itemData.position >= 0) ? itemData.position : itemData.position + OSD_SETTINGS.data.display_size.total; - // create the preview image - item.preview_img = new Image(); - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext("2d"); - // fill the screen buffer - var preview = OSD_SETTINGS.get_item_preview(item); - if (!preview) { - continue; - } - var x = 0; - var y = 0; - for (i = 0; i < preview.length; i++) { - var charCode = preview.charCodeAt(i); - if (charCode == '\n'.charCodeAt(0)) { - x = 0; - y++; - continue; - } - var previewPos = j + x + (y * OSD_SETTINGS.data.display_size.x); - if (previewPos >= OSD_SETTINGS.data.preview.length) { - // Character is outside the viewport - x++; - continue; - } - // test if this position already has a character placed - if (OSD_SETTINGS.data.preview[previewPos][0] !== null) { - // if so set background color to red to show user double usage of position - OSD_SETTINGS.data.preview[previewPos] = [item, charCode, 'red']; - } else { - OSD_SETTINGS.data.preview[previewPos] = [item, charCode]; - } - // draw the preview - var img = new Image(); - img.src = FONT.draw(charCode); - ctx.drawImage(img, x*FONT.constants.SIZES.CHAR_WIDTH, y*FONT.constants.SIZES.CHAR_HEIGHT); - x++; - } - item.preview_img.src = canvas.toDataURL('image/png'); - // Required for NW.js - Otherwise the will - // consume drag/drop events. - item.preview_img.style.pointerEvents = 'none'; - } - - - var centerPosition = (OSD_SETTINGS.data.display_size.x * OSD_SETTINGS.data.display_size.y / 2); - if (OSD_SETTINGS.data.display_size.y % 2 == 0) { - centerPosition += Math.floor(OSD_SETTINGS.data.display_size.x / 2); - } - - let hudCenterPosition = centerPosition - (OSD_SETTINGS.constants.VIDEO_COLS[video_type] * $('#osd_horizon_offset').val()); - - // artificial horizon - if ($('input[name="ARTIFICIAL_HORIZON"]').prop('checked')) { - for (i = 0; i < 9; i++) { - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 4 + i, SYM.AH_BAR9_0 + 4); - } - } - - // crosshairs - if ($('input[name="CROSSHAIRS"]').prop('checked')) { - crsHNumber = Settings.getInputValue('osd_crosshairs_style'); - if (crsHNumber == 1) { - // AIRCRAFT style - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 2, SYM.AH_AIRCRAFT0); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 1, SYM.AH_AIRCRAFT1); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition, SYM.AH_AIRCRAFT2); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 1, SYM.AH_AIRCRAFT3); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 2, SYM.AH_AIRCRAFT4); - } else if ((crsHNumber > 1) && (crsHNumber < 8)) { - // TYPES 3 to 8 (zero indexed) - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 1, SYM.AH_CROSSHAIRS[crsHNumber][0]); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition, SYM.AH_CROSSHAIRS[crsHNumber][1]); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 1, SYM.AH_CROSSHAIRS[crsHNumber][2]); - } else { - // DEFAULT or unknown style - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 1, SYM.AH_CENTER_LINE); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition, SYM.AH_CROSSHAIRS[crsHNumber]); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + 1, SYM.AH_CENTER_LINE_RIGHT); - } - } - - // sidebars - if ($('input[name="HORIZON_SIDEBARS"]').prop('checked')) { - var hudwidth = OSD_SETTINGS.constants.AHISIDEBARWIDTHPOSITION; - var hudheight = OSD_SETTINGS.constants.AHISIDEBARHEIGHTPOSITION; - for (i = -hudheight; i <= hudheight; i++) { - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - hudwidth + (i * FONT.constants.SIZES.LINE), SYM.AH_DECORATION); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + hudwidth + (i * FONT.constants.SIZES.LINE), SYM.AH_DECORATION); - } - // AH level indicators - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition - hudwidth + 1, SYM.AH_LEFT); - OSD_SETTINGS.GUI.checkAndProcessSymbolPosition(hudCenterPosition + hudwidth - 1, SYM.AH_RIGHT); - } - - OSD_SETTINGS.GUI.updateMapPreview(centerPosition, 'MAP_NORTH', 'N', SYM.HOME); - OSD_SETTINGS.GUI.updateMapPreview(centerPosition, 'MAP_TAKEOFF', 'T', SYM.HOME); - OSD_SETTINGS.GUI.updateMapPreview(centerPosition, 'RADAR', null, SYM.DIR_TO_HOME); - - // render - var $preview = $('.display-layout .preview').empty(); - var $row = $('
    '); - for (i = 0; i < OSD_SETTINGS.data.display_size.total;) { - var charCode = OSD_SETTINGS.data.preview[i]; - var colorStyle = ''; - - if (typeof charCode === 'object') { - var item = OSD_SETTINGS.data.preview[i][0]; - charCode = OSD_SETTINGS.data.preview[i][1]; - if (OSD_SETTINGS.data.preview[i][2] !== undefined) { - // if third field is set it contains a background color - colorStyle = 'style="background-color: ' + OSD_SETTINGS.data.preview[i][2] + ';"'; - } - } - var $img = $('
    ') - .on('mouseenter', OSD_SETTINGS.GUI.preview.onMouseEnter) - .on('mouseleave', OSD_SETTINGS.GUI.preview.onMouseLeave) - .on('dragover', OSD_SETTINGS.GUI.preview.onDragOver) - .on('dragleave', OSD_SETTINGS.GUI.preview.onDragLeave) - .on('drop', OSD_SETTINGS.GUI.preview.onDrop) - .data('item', item) - .data('position', i); - // Required for NW.js - Otherwise the will - // consume drag/drop events. - $img.find('img').css('pointer-events', 'none'); - if (item && item.positionable !== false) { - var nameKey = 'osdElement_' + item.name; - var nameMessage = chrome.i18n.getMessage(nameKey); - - if (!nameMessage) { - nameMessage = inflection.titleize(item.name); - } - - $img.addClass('field-' + item.id) - .data('item', item) - .prop('draggable', true) - .on('dragstart', OSD_SETTINGS.GUI.preview.onDragStart) - .prop('title', nameMessage); - } - - $row.append($img); - if (++i % OSD_SETTINGS.data.display_size.x == 0) { - $preview.append($row); - $row = $('
    '); - } - } -}; - -OSD_SETTINGS.GUI.updateAll = function() { - if (!OSD_SETTINGS.data.supported) { - $('.unsupported').fadeIn(); - return; - } - var layouts = $('.osd_layouts'); - if (OSD_SETTINGS.data.layout_count > 1) { - layouts.empty(); - for (var ii = 0; ii < OSD_SETTINGS.data.layout_count; ii++) { - var name = ii > 0 ? chrome.i18n.getMessage('osdLayoutAlternative', [ii]) : chrome.i18n.getMessage('osdLayoutDefault'); - var opt = $('