1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-23 16:25:22 +03:00

ISSUE-1609: Create communication mechanism between windows, implement dark theme for sticks window using it. Small fix for Tip popup window.

This commit is contained in:
Anisotropic 2019-09-17 23:21:43 +03:00
parent c6fd43fdec
commit 262bc05ab5
11 changed files with 190 additions and 72 deletions

View file

@ -29,27 +29,28 @@ var css_dark = [
var DarkTheme = {
configEnabled: undefined,
};
DarkTheme.setConfig = function(result) {
DarkTheme.isDarkThemeEnabled = function (val) {
return val === 0 || val === 2 && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
DarkTheme.setConfig = function (result) {
if (this.configEnabled != result) {
this.configEnabled = result;
if (this.configEnabled === 0 || this.configEnabled === 2 && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
if (this.isDarkThemeEnabled(this.configEnabled)) {
this.applyDark();
} else {
this.applyNormal();
}
windowWatcherUtil.passValue(chrome.app.window.get("receiver_msp"), 'darkTheme', this.isDarkThemeEnabled(this.configEnabled));
}
};
DarkTheme.applyDark = function() {
for (var i = 0; i < css_dark.length; i++) {
$('link[href="' + css_dark[i] + '"]').prop('disabled', false);
}
DarkTheme.applyDark = function () {
css_dark.forEach((el) => $('link[href="' + el + '"]').prop('disabled', false));
};
DarkTheme.applyNormal = function() {
for (var i = 0; i < css_dark.length; i++) {
$('link[href="' + css_dark[i] + '"]').prop('disabled', true);
}
DarkTheme.applyNormal = function () {
css_dark.forEach((el) => $('link[href="' + el + '"]').prop('disabled', true));
};

View file

@ -76,7 +76,7 @@ TABS.receiver.initialize = function (callback) {
tab.yawDeadband = parseInt($(this).val());
}).change();
}
if (semver.lt(CONFIG.apiVersion, "1.15.0")) {
$('.sticks').hide();
} else {
@ -319,6 +319,9 @@ TABS.receiver.initialize = function (callback) {
return false;
}
}
windowWatcherUtil.passValue(createdWindow, 'darkTheme', DarkTheme.isDarkThemeEnabled(DarkTheme.configEnabled));
});
});
@ -350,7 +353,7 @@ TABS.receiver.initialize = function (callback) {
if ($(this).val() == 1) {
rcSmoothingnNumberElement.val(RX_CONFIG.rcSmoothingInputCutoff);
$('.tab-receiver .rcSmoothing-input-cutoff').show();
}
}
});
$('.tab-receiver .rcSmoothing-derivative-cutoff').show();
@ -578,7 +581,7 @@ TABS.receiver.initModelPreview = function () {
if (CONFIG.flightControllerIdentifier == 'BTFL' && semver.lt(CONFIG.flightControllerVersion, '2.8.0')) {
useOldRateCurve = true;
}
this.rateCurve = new RateCurve(useOldRateCurve);
$(window).on('resize', $.proxy(this.model.resize, this.model));
@ -665,4 +668,4 @@ function updateInterpolationView() {
if (RX_CONFIG.rcSmoothingInputCutoff == 0) {
$('.tab-receiver .rcSmoothing-input-cutoff').hide();
}
}
}

View file

@ -1,10 +1,15 @@
"use strict";
let css_dark = [
'/css/main-dark.css'
];
var
CHANNEL_MIN_VALUE = 1000,
CHANNEL_MID_VALUE = 1500,
CHANNEL_MAX_VALUE = 2000,
// What's the index of each channel in the MSP channel list?
channelMSPIndexes = {
Roll: 0,
@ -16,7 +21,7 @@ var
Aux3: 6,
Aux4: 7,
},
// Set reasonable initial stick positions (Mode 2)
stickValues = {
Throttle: CHANNEL_MIN_VALUE,
@ -28,21 +33,31 @@ var
Aux3: CHANNEL_MIN_VALUE,
Aux4: CHANNEL_MIN_VALUE
},
// First the vertical axis, then the horizontal:
gimbals = [
["Throttle", "Yaw"],
["Pitch", "Roll"],
],
gimbalElems,
sliderElems,
enableTX = false;
// This is a hack to get the i18n var of the parent, but the localizePage not works
const i18n = opener.i18n;
let watchers = {
darkTheme: (val) => {
if (val) {
applyDarkTheme();
} else {
applyNormalTheme();
}
}
};
$(document).ready(function () {
$('[i18n]:not(.i18n-replaced)').each(function() {
var element = $(this);
@ -50,20 +65,22 @@ $(document).ready(function () {
element.html(i18n.getMessage(element.attr('i18n')));
element.addClass('i18n-replaced');
});
})
windowWatcherUtil.bindWatchers(window, watchers);
});
function transmitChannels() {
var
var
channelValues = [0, 0, 0, 0, 0, 0, 0, 0];
if (!enableTX) {
return;
}
for (var stickName in stickValues) {
channelValues[channelMSPIndexes[stickName]] = stickValues[stickName];
}
// Callback given to us by the window creator so we can have it send data over MSP for us:
if (!window.setRawRx(channelValues)) {
// MSP connection has gone away
@ -73,7 +90,7 @@ function transmitChannels() {
function stickPortionToChannelValue(portion) {
portion = Math.min(Math.max(portion, 0.0), 1.0);
return Math.round(portion * (CHANNEL_MAX_VALUE - CHANNEL_MIN_VALUE) + CHANNEL_MIN_VALUE);
}
@ -85,15 +102,15 @@ function updateControlPositions() {
for (var stickName in stickValues) {
var
stickValue = stickValues[stickName];
// Look for the gimbal which corresponds to this stick name
for (var gimbalIndex in gimbals) {
var
var
gimbal = gimbals[gimbalIndex],
gimbalElem = gimbalElems.get(gimbalIndex),
gimbalSize = $(gimbalElem).width(),
stickElem = $(".control-stick", gimbalElem);
if (gimbal[0] == stickName) {
stickElem.css('top', (1.0 - channelValueToStickPortion(stickValue)) * gimbalSize + "px");
break;
@ -106,62 +123,70 @@ function updateControlPositions() {
}
function handleGimbalMouseDrag(e) {
var
var
gimbal = $(gimbalElems.get(e.data.gimbalIndex)),
gimbalOffset = gimbal.offset(),
gimbalSize = gimbal.width();
stickValues[gimbals[e.data.gimbalIndex][0]] = stickPortionToChannelValue(1.0 - (e.pageY - gimbalOffset.top) / gimbalSize);
stickValues[gimbals[e.data.gimbalIndex][1]] = stickPortionToChannelValue((e.pageX - gimbalOffset.left) / gimbalSize);
updateControlPositions();
}
function localizeAxisNames() {
for (var gimbalIndex in gimbals) {
var
var
gimbal = gimbalElems.get(gimbalIndex);
$(".gimbal-label-vert", gimbal).text(i18n.getMessage("controlAxis" + gimbals[gimbalIndex][0]));
$(".gimbal-label-horz", gimbal).text(i18n.getMessage("controlAxis" + gimbals[gimbalIndex][1]));
}
for (var sliderIndex = 0; sliderIndex < 4; sliderIndex++) {
$(".slider-label", sliderElems.get(sliderIndex)).text(i18n.getMessage("controlAxisAux" + (sliderIndex + 1)));
}
}
function applyDarkTheme() {
css_dark.forEach((el) => $('link[href="' + el + '"]').prop('disabled', false));
};
function applyNormalTheme() {
css_dark.forEach((el) => $('link[href="' + el + '"]').prop('disabled', true));
};
$(document).ready(function() {
$(".button-enable .btn").click(function() {
var
shrinkHeight = $(".warning").height();
$(".warning").slideUp("short", function() {
chrome.app.window.current().innerBounds.minHeight -= shrinkHeight;
chrome.app.window.current().innerBounds.height -= shrinkHeight;
chrome.app.window.current().innerBounds.maxHeight -= shrinkHeight;
});
enableTX = true;
});
gimbalElems = $(".control-gimbal");
sliderElems = $(".control-slider");
gimbalElems.each(function(gimbalIndex) {
$(this).on('mousedown', {gimbalIndex: gimbalIndex}, function(e) {
if (e.which == 1) { // Only move sticks on left mouse button
handleGimbalMouseDrag(e);
$(window).on('mousemove', {gimbalIndex: gimbalIndex}, handleGimbalMouseDrag);
}
});
});
$(".slider", sliderElems).each(function(sliderIndex) {
var
var
initialValue = stickValues["Aux" + (sliderIndex + 1)];
$(this)
.noUiSlider({
start: initialValue,
@ -171,27 +196,27 @@ $(document).ready(function() {
}
}).on('slide change set', function(e, value) {
value = Math.round(parseFloat(value));
stickValues["Aux" + (sliderIndex + 1)] = value;
$(".tooltip", this).text(value);
});
$(this).append('<div class="tooltip"></div>');
$(".tooltip", this).text(initialValue);
});
/*
/*
* Mouseup handler needs to be bound to the window in order to receive mouseup if mouse leaves window.
*/
$(window).mouseup(function(e) {
$(this).off('mousemove', handleGimbalMouseDrag);
});
localizeAxisNames();
updateControlPositions();
setInterval(transmitChannels, 50);
});
});

View file

@ -0,0 +1,59 @@
'use strict';
/*
This utility is intended to communicate between chrome windows.
One window could watch passed values from another window and react to them.
*/
var windowWatcherUtil = {};
windowWatcherUtil.invokeWatcher = function(bindingKey, bindingVal, watchersObject) {
if (watchersObject[bindingKey]) {
watchersObject[bindingKey](bindingVal);
}
}
windowWatcherUtil.iterateOverBindings = function(bindings, watchersObject) {
let entries = Object.entries(bindings);
for (const [key, val] of entries) {
this.invokeWatcher(key, val, watchersObject)
}
}
windowWatcherUtil.bindWatchers = function(windowObject, watchersObject) {
if (!windowObject.bindings) {
windowObject.bindings = {};
} else {
this.iterateOverBindings(windowObject.bindings, watchersObject);
}
windowObject.bindings = new Proxy(windowObject.bindings, {
set(target, prop, val, receiver) {
windowWatcherUtil.invokeWatcher(prop, val, watchersObject);
return Reflect.set(target, prop, val, receiver);
}
});
}
// 'Windows' here could be array or single window reference
windowWatcherUtil.passValue = function(windows, key, val) {
let applyBinding = function(win, key, val) {
if (!win) {
return;
}
if (win.contentWindow.bindings) {
win.contentWindow.bindings[key] = val;
} else {
win.contentWindow.bindings = {
[key]: val
};
}
}
if (Array.isArray(windows)) {
windows.forEach((el) => applyBinding(el, key, val));
} else {
applyBinding(windows, key, val)
}
}