mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-23 16:25:22 +03:00
improved logo customization UI
This commit is contained in:
parent
fd83241379
commit
9d9a395f6b
4 changed files with 318 additions and 121 deletions
|
@ -2786,19 +2786,28 @@
|
||||||
"osdSetupOpenFont": {
|
"osdSetupOpenFont": {
|
||||||
"message": "Open Font File"
|
"message": "Open Font File"
|
||||||
},
|
},
|
||||||
"osdSetupLogo": {
|
"osdSetupCustomLogoTitle": {
|
||||||
"message": "Logo in font:"
|
"message": "Boot logo:"
|
||||||
},
|
},
|
||||||
"osdSetupReplaceLogo": {
|
"osdSetupCustomLogoOpenImageButton": {
|
||||||
"message": "Replace Logo"
|
"message": "Select custom image…"
|
||||||
},
|
},
|
||||||
"osdSetupReplaceLogoHelp": {
|
"osdSetupCustomLogoInfoTitle": {
|
||||||
"message": "Customized logo image has to be 288×72 pixels in size containing black and white pixels only on a completely green background."
|
"message": "Custom image:"
|
||||||
},
|
},
|
||||||
"osdSetupReplaceLogoImageSizeError": {
|
"osdSetupCustomLogoInfoImageSize": {
|
||||||
"message": "Invalid image size; expected $1×$2 instead of $3×$4"
|
"message": "Size must be $t(logoWidthPx)×$t(logoHeightPx) pixels"
|
||||||
},
|
},
|
||||||
"osdSetupReplaceLogoImageColorsError": {
|
"osdSetupCustomLogoInfoColorMap": {
|
||||||
|
"message": "Must contain green, black and white pixels"
|
||||||
|
},
|
||||||
|
"osdSetupCustomLogoInfoUploadHint": {
|
||||||
|
"message": "Click <b>$t(osdSetupUploadFont.message)</b> to persist custom logo"
|
||||||
|
},
|
||||||
|
"osdSetupCustomLogoImageSizeError": {
|
||||||
|
"message": "Invalid image size: $1×$2 (expected $t(logoWidthPx)×$t(logoHeightPx))"
|
||||||
|
},
|
||||||
|
"osdSetupCustomLogoColorMapError": {
|
||||||
"message": "The image contains an invalid color palette (only green, black and white are allowed)"
|
"message": "The image contains an invalid color palette (only green, black and white are allowed)"
|
||||||
},
|
},
|
||||||
"osdSetupUploadFont": {
|
"osdSetupUploadFont": {
|
||||||
|
|
|
@ -336,11 +336,42 @@
|
||||||
#font-logo-preview-container {
|
#font-logo-preview-container {
|
||||||
background:rgba(0, 255, 0, 0.4);
|
background:rgba(0, 255, 0, 0.4);
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#font-logo-preview {
|
#font-logo-preview {
|
||||||
background:rgba(0, 255, 0, 1);
|
background:rgba(0, 255, 0, 1);
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#font-logo-info {
|
||||||
|
margin-left: 18px;
|
||||||
|
font-size: 125%;
|
||||||
|
line-height: 150%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#font-logo-info h3 {
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#font-logo-info ul li:before {
|
||||||
|
content: '• ';
|
||||||
|
}
|
||||||
|
|
||||||
|
#font-logo-info ul li.valid:before {
|
||||||
|
content: '✔ ';
|
||||||
|
}
|
||||||
|
|
||||||
|
#font-logo-info ul li.invalid:before {
|
||||||
|
content: '🞨 ';
|
||||||
|
}
|
||||||
|
|
||||||
|
#font-logo-info #font-logo-info-upload-hint {
|
||||||
|
margin-top: 1em;
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-osd .content_wrapper {
|
.tab-osd .content_wrapper {
|
||||||
|
|
|
@ -76,20 +76,6 @@ FONT.constants = {
|
||||||
// white
|
// white
|
||||||
2: 'rgba(255,255,255, 1)'
|
2: 'rgba(255,255,255, 1)'
|
||||||
},
|
},
|
||||||
LOGO: {
|
|
||||||
TILES_NUM_HORIZ: 24,
|
|
||||||
TILES_NUM_VERT: 4,
|
|
||||||
MCM_COLORMAP: {
|
|
||||||
// background
|
|
||||||
'0-255-0': '01',
|
|
||||||
// black
|
|
||||||
'0-0-0': '00',
|
|
||||||
// white
|
|
||||||
'255-255-255': '10',
|
|
||||||
// fallback
|
|
||||||
'default': '01',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,6 +87,8 @@ FONT.parseMCMFontFile = function(data) {
|
||||||
FONT.data.characters.length = 0;
|
FONT.data.characters.length = 0;
|
||||||
FONT.data.characters_bytes.length = 0;
|
FONT.data.characters_bytes.length = 0;
|
||||||
FONT.data.character_image_urls.length = 0;
|
FONT.data.character_image_urls.length = 0;
|
||||||
|
// reset logo image info when font data is changed
|
||||||
|
LogoManager.resetImageInfo();
|
||||||
// make sure the font file is valid
|
// make sure the font file is valid
|
||||||
if (data.shift().trim() != 'MAX7456') {
|
if (data.shift().trim() != 'MAX7456') {
|
||||||
var msg = 'that font file doesnt have the MAX7456 header, giving up';
|
var msg = 'that font file doesnt have the MAX7456 header, giving up';
|
||||||
|
@ -163,74 +151,25 @@ FONT.openFontFile = function($preview) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// show a file open dialog and yield an Image object
|
/**
|
||||||
var openLogoImage = function() {
|
* Replaces the logo in the loaded font based on an image.
|
||||||
return new Promise(function(resolve, reject) {
|
*
|
||||||
var validateImage = function(img) {
|
* @param {HTMLImageElement} img
|
||||||
return new Promise(function(resolve, reject) {
|
*/
|
||||||
var expectedWidth = FONT.constants.SIZES.CHAR_WIDTH
|
|
||||||
* FONT.constants.LOGO.TILES_NUM_HORIZ,
|
|
||||||
expectedHeight = FONT.constants.SIZES.CHAR_HEIGHT
|
|
||||||
* FONT.constants.LOGO.TILES_NUM_VERT;
|
|
||||||
if (img.width != expectedWidth || img.height != expectedHeight) {
|
|
||||||
reject(i18n.getMessage("osdSetupReplaceLogoImageSizeError",
|
|
||||||
[expectedWidth, expectedHeight, img.width, img.height]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var canvas = document.createElement('canvas'),
|
|
||||||
ctx = canvas.getContext('2d');
|
|
||||||
canvas.width = img.width;
|
|
||||||
canvas.height = img.height;
|
|
||||||
ctx.drawImage(img, 0, 0);
|
|
||||||
for (var y = 0, Y = canvas.height; y < Y; y++) {
|
|
||||||
for (var x = 0, X = canvas.width; x < X; x++) {
|
|
||||||
var rgbPixel = ctx.getImageData(x, y, 1, 1).data.slice(0, 3),
|
|
||||||
colorKey = rgbPixel.join("-");
|
|
||||||
if (!FONT.constants.LOGO.MCM_COLORMAP[colorKey]) {
|
|
||||||
reject(i18n.getMessage("osdSetupReplaceLogoImageColorsError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chrome.fileSystem.chooseEntry({ type: 'openFile', accepts: [{ extensions: ['png', 'bmp'] }] }, function(fileEntry) {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
console.error(chrome.runtime.lastError.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var img = new Image();
|
|
||||||
img.onload = function() {
|
|
||||||
validateImage(img).then(function() {
|
|
||||||
resolve(img);
|
|
||||||
}).catch(function(error) {
|
|
||||||
console.error(error);
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
img.onerror = function(error) {
|
|
||||||
reject(error);
|
|
||||||
};
|
|
||||||
fileEntry.file(function(file) {
|
|
||||||
img.src = "file://" + file.path;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// replaces the logo in the font based on an Image object
|
|
||||||
FONT.replaceLogoFromImage = function(img) {
|
FONT.replaceLogoFromImage = function(img) {
|
||||||
// takes image data from an ImageData object and returns an MCM symbol as an array of strings
|
/**
|
||||||
|
* Takes an ImageData object and returns an MCM symbol as an array of strings.
|
||||||
|
*
|
||||||
|
* @param {ImageData} data
|
||||||
|
*/
|
||||||
var imageToCharacter = function(data) {
|
var imageToCharacter = function(data) {
|
||||||
var char = [],
|
var char = [],
|
||||||
line = "";
|
line = "";
|
||||||
for (var i = 0, I = data.length; i < I; i += 4) {
|
for (var i = 0, I = data.length; i < I; i += 4) {
|
||||||
var rgbPixel = data.slice(i, i + 3),
|
var rgbPixel = data.slice(i, i + 3),
|
||||||
colorKey = rgbPixel.join("-");
|
colorKey = rgbPixel.join("-");
|
||||||
line += FONT.constants.LOGO.MCM_COLORMAP[colorKey]
|
line += LogoManager.constants.MCM_COLORMAP[colorKey]
|
||||||
|| FONT.constants.LOGO.MCM_COLORMAP['default'];
|
|| LogoManager.constants.MCM_COLORMAP['default'];
|
||||||
if (line.length == 8) {
|
if (line.length == 8) {
|
||||||
char.push(line);
|
char.push(line);
|
||||||
line = "";
|
line = "";
|
||||||
|
@ -238,13 +177,12 @@ FONT.replaceLogoFromImage = function(img) {
|
||||||
}
|
}
|
||||||
var fieldSize = FONT.constants.SIZES.MAX_NVM_FONT_CHAR_FIELD_SIZE;
|
var fieldSize = FONT.constants.SIZES.MAX_NVM_FONT_CHAR_FIELD_SIZE;
|
||||||
if (char.length < fieldSize) {
|
if (char.length < fieldSize) {
|
||||||
var pad = FONT.constants.LOGO.MCM_COLORMAP['default'].repeat(4);
|
var pad = LogoManager.constants.MCM_COLORMAP['default'].repeat(4);
|
||||||
for (var i = 0, I = fieldSize - char.length; i < I; i++)
|
for (var i = 0, I = fieldSize - char.length; i < I; i++)
|
||||||
char.push(pad);
|
char.push(pad);
|
||||||
}
|
}
|
||||||
return char;
|
return char;
|
||||||
};
|
};
|
||||||
|
|
||||||
// takes an OSD symbol as an array of strings and replaces the in-memory character at charAddress with it
|
// takes an OSD symbol as an array of strings and replaces the in-memory character at charAddress with it
|
||||||
var replaceChar = function(lines, charAddress) {
|
var replaceChar = function(lines, charAddress) {
|
||||||
var characterBits = [];
|
var characterBits = [];
|
||||||
|
@ -262,7 +200,6 @@ FONT.replaceLogoFromImage = function(img) {
|
||||||
FONT.data.character_image_urls[charAddress] = null;
|
FONT.data.character_image_urls[charAddress] = null;
|
||||||
FONT.draw(charAddress);
|
FONT.draw(charAddress);
|
||||||
};
|
};
|
||||||
|
|
||||||
// loop through an image and replace font symbols
|
// loop through an image and replace font symbols
|
||||||
var canvas = document.createElement('canvas'),
|
var canvas = document.createElement('canvas'),
|
||||||
ctx = canvas.getContext('2d'),
|
ctx = canvas.getContext('2d'),
|
||||||
|
@ -270,8 +207,8 @@ FONT.replaceLogoFromImage = function(img) {
|
||||||
canvas.width = img.width;
|
canvas.width = img.width;
|
||||||
canvas.height = img.height;
|
canvas.height = img.height;
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
for (var y = 0; y < FONT.constants.LOGO.TILES_NUM_VERT; y++) {
|
for (var y = 0; y < LogoManager.constants.TILES_NUM_VERT; y++) {
|
||||||
for (var x = 0; x < FONT.constants.LOGO.TILES_NUM_HORIZ; x++) {
|
for (var x = 0; x < LogoManager.constants.TILES_NUM_HORIZ; x++) {
|
||||||
var imageData = ctx.getImageData(
|
var imageData = ctx.getImageData(
|
||||||
x * FONT.constants.SIZES.CHAR_WIDTH,
|
x * FONT.constants.SIZES.CHAR_WIDTH,
|
||||||
y * FONT.constants.SIZES.CHAR_HEIGHT,
|
y * FONT.constants.SIZES.CHAR_HEIGHT,
|
||||||
|
@ -285,6 +222,220 @@ FONT.replaceLogoFromImage = function(img) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var LogoManager = LogoManager || {
|
||||||
|
// DOM elements to cache
|
||||||
|
elements: {
|
||||||
|
$preview: "#font-logo-preview",
|
||||||
|
$uploadHint: "#font-logo-info-upload-hint",
|
||||||
|
},
|
||||||
|
constants: {
|
||||||
|
TILES_NUM_HORIZ: 24,
|
||||||
|
TILES_NUM_VERT: 4,
|
||||||
|
MCM_COLORMAP: {
|
||||||
|
// background
|
||||||
|
'0-255-0': '01',
|
||||||
|
// black
|
||||||
|
'0-0-0': '00',
|
||||||
|
// white
|
||||||
|
'255-255-255': '10',
|
||||||
|
// fallback
|
||||||
|
'default': '01',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// config for logo image selection dialog
|
||||||
|
acceptFileTypes: [
|
||||||
|
{ extensions: ['png', 'bmp'] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// custom logo image constraints
|
||||||
|
LogoManager.constraints = {
|
||||||
|
// test for image size
|
||||||
|
imageSize: {
|
||||||
|
$el: "#font-logo-info-size",
|
||||||
|
// calculate logo image size at runtime as it may change conditionally in the future
|
||||||
|
expectedWidth: FONT.constants.SIZES.CHAR_WIDTH
|
||||||
|
* LogoManager.constants.TILES_NUM_HORIZ,
|
||||||
|
expectedHeight: FONT.constants.SIZES.CHAR_HEIGHT
|
||||||
|
* LogoManager.constants.TILES_NUM_VERT,
|
||||||
|
/**
|
||||||
|
* @param {HTMLImageElement} img
|
||||||
|
*/
|
||||||
|
test: function(img) {
|
||||||
|
var constraint = LogoManager.constraints.imageSize;
|
||||||
|
if (img.width != constraint.expectedWidth
|
||||||
|
|| img.height != constraint.expectedHeight) {
|
||||||
|
GUI.log(i18n.getMessage("osdSetupCustomLogoImageSizeError", [
|
||||||
|
img.width,
|
||||||
|
img.height,
|
||||||
|
]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// test for pixel colors
|
||||||
|
colorMap: {
|
||||||
|
$el: "#font-logo-info-colors",
|
||||||
|
/**
|
||||||
|
* @param {HTMLImageElement} img
|
||||||
|
*/
|
||||||
|
test: function(img) {
|
||||||
|
var canvas = document.createElement('canvas'),
|
||||||
|
ctx = canvas.getContext('2d');
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
for (var y = 0, Y = canvas.height; y < Y; y++) {
|
||||||
|
for (var x = 0, X = canvas.width; x < X; x++) {
|
||||||
|
var rgbPixel = ctx.getImageData(x, y, 1, 1).data.slice(0, 3),
|
||||||
|
colorKey = rgbPixel.join("-");
|
||||||
|
if (!LogoManager.constants.MCM_COLORMAP[colorKey]) {
|
||||||
|
GUI.log(i18n.getMessage("osdSetupCustomLogoColorMapError"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
LogoManager.resetImageInfo = function() {
|
||||||
|
LogoManager.hideUploadHint();
|
||||||
|
Object.values(LogoManager.constraints).forEach(function(constraint) {
|
||||||
|
var $el = constraint.$el;
|
||||||
|
$el.toggleClass("message-negative", false);
|
||||||
|
$el.toggleClass("invalid", false);
|
||||||
|
$el.toggleClass("message-positive", false);
|
||||||
|
$el.toggleClass("valid", false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
LogoManager.showConstraintNotSatisfied = function(constraint) {
|
||||||
|
constraint.$el.toggleClass("message-negative", true);
|
||||||
|
constraint.$el.toggleClass("invalid", true);
|
||||||
|
};
|
||||||
|
|
||||||
|
LogoManager.showConstraintSatisfied = function(constraint) {
|
||||||
|
constraint.$el.toggleClass("message-positive", true);
|
||||||
|
constraint.$el.toggleClass("valid", true);
|
||||||
|
};
|
||||||
|
|
||||||
|
LogoManager.showUploadHint = function() {
|
||||||
|
LogoManager.elements.$uploadHint.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
LogoManager.hideUploadHint = function() {
|
||||||
|
LogoManager.elements.$uploadHint.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a file open dialog and resolve to an Image object.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
LogoManager.openImage = function() {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
/**
|
||||||
|
* Validate image using defined constraints and display results on the UI.
|
||||||
|
*
|
||||||
|
* @param {HTMLImageElement} img
|
||||||
|
*/
|
||||||
|
var validateImage = function(img) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
LogoManager.resetImageInfo();
|
||||||
|
for (var key in LogoManager.constraints) {
|
||||||
|
if (!LogoManager.constraints.hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var constraint = LogoManager.constraints[key],
|
||||||
|
satisfied = constraint.test(img);
|
||||||
|
if (satisfied) {
|
||||||
|
LogoManager.showConstraintSatisfied(constraint);
|
||||||
|
} else {
|
||||||
|
LogoManager.showConstraintNotSatisfied(constraint);
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dialogOptions = {
|
||||||
|
type: 'openFile',
|
||||||
|
accepts: LogoManager.acceptFileTypes
|
||||||
|
};
|
||||||
|
|
||||||
|
chrome.fileSystem.chooseEntry(dialogOptions, function(fileEntry) {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
console.error(chrome.runtime.lastError.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// load and validate selected image
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = function() {
|
||||||
|
validateImage(img).then(function() {
|
||||||
|
resolve(img);
|
||||||
|
}).catch(function(error) {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
img.onerror = function(error) {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
fileEntry.file(function(file) {
|
||||||
|
img.src = "file://" + file.path;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the logo using the loaded font data.
|
||||||
|
*/
|
||||||
|
LogoManager.drawPreview = function() {
|
||||||
|
var $el = LogoManager.elements.$preview;
|
||||||
|
$el.empty();
|
||||||
|
for (var i = SYM.LOGO, I = FONT.constants.MAX_CHAR_COUNT; i < I; i++) {
|
||||||
|
var url = FONT.data.character_image_urls[i];
|
||||||
|
$el.append('<img src="' + url + '" title="0x' + i.toString(16) + '"></img>');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Logo Manager UI.
|
||||||
|
*/
|
||||||
|
LogoManager.init = function() {
|
||||||
|
// cache DOM elements
|
||||||
|
Object.keys(LogoManager.elements).forEach(function(key) {
|
||||||
|
LogoManager.elements[key] = $(LogoManager.elements[key]);
|
||||||
|
});
|
||||||
|
Object.keys(LogoManager.constraints).forEach(function(key) {
|
||||||
|
LogoManager.constraints[key].$el = $(LogoManager.constraints[key].$el);
|
||||||
|
});
|
||||||
|
// resize logo preview area to match tile size
|
||||||
|
var logoWidthPx = LogoManager.constraints.imageSize.expectedWidth,
|
||||||
|
logoHeightPx = LogoManager.constraints.imageSize.expectedHeight;
|
||||||
|
LogoManager.elements.$preview
|
||||||
|
.width(logoWidthPx)
|
||||||
|
.height(logoHeightPx);
|
||||||
|
// inject logo size variables for dynamic translation strings
|
||||||
|
var takeFirst = obj => {
|
||||||
|
if (obj.hasOwnProperty("length") && 0 < obj.length) {
|
||||||
|
return obj[0];
|
||||||
|
} else {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var lang = takeFirst(i18next.options.fallbackLng),
|
||||||
|
ns = takeFirst(i18next.options.defaultNS);
|
||||||
|
i18next.addResourceBundle(lang, ns, {
|
||||||
|
logoWidthPx: logoWidthPx,
|
||||||
|
logoHeightPx: logoHeightPx,
|
||||||
|
}, true, true);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns a canvas image with the character on it
|
* returns a canvas image with the character on it
|
||||||
*/
|
*/
|
||||||
|
@ -346,16 +497,6 @@ FONT.preview = function($el) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FONT.logoPreview = function($el) {
|
|
||||||
$el.empty()
|
|
||||||
.width(FONT.constants.LOGO.TILES_NUM_HORIZ * FONT.constants.SIZES.CHAR_WIDTH)
|
|
||||||
.height(FONT.constants.LOGO.TILES_NUM_VERT * FONT.constants.SIZES.CHAR_HEIGHT);
|
|
||||||
for (var i = SYM.LOGO, I = FONT.constants.MAX_CHAR_COUNT; i < I; i++) {
|
|
||||||
var url = FONT.data.character_image_urls[i];
|
|
||||||
$el.append('<img src="' + url + '" title="0x' + i.toString(16) + '"></img>');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FONT.symbol = function(hexVal) {
|
FONT.symbol = function(hexVal) {
|
||||||
return String.fromCharCode(hexVal);
|
return String.fromCharCode(hexVal);
|
||||||
};
|
};
|
||||||
|
@ -1372,6 +1513,9 @@ TABS.osd.initialize = function (callback) {
|
||||||
|
|
||||||
fontbuttons.append($('<button>', { class: "load_font_file", i18n: "osdSetupOpenFont" }));
|
fontbuttons.append($('<button>', { class: "load_font_file", i18n: "osdSetupOpenFont" }));
|
||||||
|
|
||||||
|
// must invoke before localizePage() since it adds translation keys for expected logo size
|
||||||
|
LogoManager.init();
|
||||||
|
|
||||||
// translate to user-selected language
|
// translate to user-selected language
|
||||||
i18n.localizePage();
|
i18n.localizePage();
|
||||||
|
|
||||||
|
@ -1383,7 +1527,10 @@ TABS.osd.initialize = function (callback) {
|
||||||
animation: false,
|
animation: false,
|
||||||
attach: $('#fontmanager'),
|
attach: $('#fontmanager'),
|
||||||
title: 'OSD Font Manager',
|
title: 'OSD Font Manager',
|
||||||
content: $('#fontmanagercontent')
|
content: $('#fontmanagercontent'),
|
||||||
|
onOpen: function() {
|
||||||
|
LogoManager.resetImageInfo();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.elements-container div.cf_tip').attr('title', i18n.getMessage('osdSectionHelpElements'));
|
$('.elements-container div.cf_tip').attr('title', i18n.getMessage('osdSectionHelpElements'));
|
||||||
|
@ -1833,10 +1980,9 @@ TABS.osd.initialize = function (callback) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// font preview window
|
// font preview window
|
||||||
var $preview = $('.font-preview'),
|
var $preview = $('.font-preview');
|
||||||
$logoPreview = $('#font-logo-preview');
|
|
||||||
|
|
||||||
// init structs once, also clears current font
|
// init structs once, also clears current font
|
||||||
FONT.initData();
|
FONT.initData();
|
||||||
|
|
||||||
var $fontPicker = $('.fontbuttons button');
|
var $fontPicker = $('.fontbuttons button');
|
||||||
|
@ -1847,7 +1993,7 @@ TABS.osd.initialize = function (callback) {
|
||||||
$.get('./resources/osd/' + $(this).data('font-file') + '.mcm', function(data) {
|
$.get('./resources/osd/' + $(this).data('font-file') + '.mcm', function(data) {
|
||||||
FONT.parseMCMFontFile(data);
|
FONT.parseMCMFontFile(data);
|
||||||
FONT.preview($preview);
|
FONT.preview($preview);
|
||||||
FONT.logoPreview($logoPreview);
|
LogoManager.drawPreview();
|
||||||
updateOsdView();
|
updateOsdView();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1859,9 +2005,9 @@ TABS.osd.initialize = function (callback) {
|
||||||
$fontPicker.removeClass('active');
|
$fontPicker.removeClass('active');
|
||||||
FONT.openFontFile().then(function() {
|
FONT.openFontFile().then(function() {
|
||||||
FONT.preview($preview);
|
FONT.preview($preview);
|
||||||
FONT.logoPreview($logoPreview);
|
LogoManager.drawPreview();
|
||||||
updateOsdView();
|
updateOsdView();
|
||||||
});
|
}).catch(error => console.error(error));
|
||||||
});
|
});
|
||||||
|
|
||||||
// font upload
|
// font upload
|
||||||
|
@ -1882,13 +2028,11 @@ TABS.osd.initialize = function (callback) {
|
||||||
if (GUI.connect_lock) { // button disabled while flashing is in progress
|
if (GUI.connect_lock) { // button disabled while flashing is in progress
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openLogoImage().then(function(ctx) {
|
LogoManager.openImage().then(function(ctx) {
|
||||||
FONT.replaceLogoFromImage(ctx);
|
FONT.replaceLogoFromImage(ctx);
|
||||||
FONT.logoPreview($logoPreview);
|
LogoManager.drawPreview();
|
||||||
}).catch(function(error) {
|
LogoManager.showUploadHint();
|
||||||
console.error("error loading image:", error);
|
}).catch(error => console.error(error));
|
||||||
GUI.log(error);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//Switch all elements
|
//Switch all elements
|
||||||
|
|
|
@ -117,35 +117,48 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Font Manager dialog -->
|
||||||
<div id="fontmanagercontent" style="display:none; width:720px;">
|
<div id="fontmanagercontent" style="display:none; width:720px;">
|
||||||
<div class="font-picker" style="margin-bottom: 10px;">
|
<div class="font-picker" style="margin-bottom: 10px;">
|
||||||
<h1 class="tab_title" i18n="osdSetupFontPresets" />
|
<h1 class="tab_title" i18n="osdSetupFontPresets" />
|
||||||
|
<!-- Font preview and list -->
|
||||||
<div class="content_wrapper font-preview"></div>
|
<div class="content_wrapper font-preview"></div>
|
||||||
<div class="fontbuttons">
|
<div class="fontbuttons"></div>
|
||||||
|
<!-- Boot logo setup -->
|
||||||
</div>
|
<h1 class="tab_title" i18n="osdSetupCustomLogoTitle" />
|
||||||
<h1 class="tab_title" i18n="osdSetupLogo" />
|
|
||||||
<div class="helpicon cf_tip" i18n_title="osdSetupReplaceLogoHelp"></div>
|
|
||||||
<div id="font-logo-preview-container" class="content_wrapper">
|
<div id="font-logo-preview-container" class="content_wrapper">
|
||||||
<div id="font-logo-preview">
|
<div id="font-logo-preview">
|
||||||
<!-- this will be resized at runtime -->
|
<!-- this will be resized at runtime -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default_btn" style="width:100%; float:left;
|
<div id="font-logo-info">
|
||||||
">
|
<h3 i18n="osdSetupCustomLogoInfoTitle"></h3>
|
||||||
<a class="replace_logo" i18n="osdSetupReplaceLogo" />
|
<ul>
|
||||||
|
<li id="font-logo-info-size" i18n="osdSetupCustomLogoInfoImageSize"></li>
|
||||||
|
<li id="font-logo-info-colors" i18n="osdSetupCustomLogoInfoColorMap"></li>
|
||||||
|
</ul>
|
||||||
|
<p id="font-logo-info-upload-hint" i18n="osdSetupCustomLogoInfoUploadHint"></p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clear-both"></div>
|
||||||
|
<!-- Replace logo button -->
|
||||||
|
<div class="default_btn" style="width:100%; float:left;">
|
||||||
|
<a class="replace_logo" i18n="osdSetupCustomLogoOpenImageButton" />
|
||||||
|
</div>
|
||||||
|
<!-- Upload progress bar -->
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<a name="progressbar"></a>
|
<a name="progressbar"></a>
|
||||||
<progress class="progress" value="0" min="0" max="100"></progress>
|
<progress class="progress" value="0" min="0" max="100"></progress>
|
||||||
<div class="progressLabel" style="margin-top: -21px; width: 95%; text-align: center; color: white; position: absolute;"></div>
|
<div class="progressLabel" style="margin-top: -21px; width: 95%; text-align: center; color: white; position: absolute;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Upload button -->
|
||||||
<div class="default_btn green" style="width:100%; float:left;
|
<div class="default_btn green" style="width:100%; float:left;
|
||||||
">
|
">
|
||||||
<a class="flash_font active" i18n="osdSetupUploadFont" />
|
<a class="flash_font active" i18n="osdSetupUploadFont" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content_toolbar supported hide" style="left:0;">
|
<div class="content_toolbar supported hide" style="left:0;">
|
||||||
<div class="btn save">
|
<div class="btn save">
|
||||||
<a class="active save" href="#" i18n="osdSetupSave" />
|
<a class="active save" href="#" i18n="osdSetupSave" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue