=== added file 'src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.mouse.js' --- src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.mouse.js 1970-01-01 00:00:00 +0000 +++ src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.mouse.js 2016-06-06 06:02:53 +0000 @@ -0,0 +1,15 @@ +/* +** Module : p2j.mouse.js +** Abstract : CHUI mouse support module +** +** Copyright (c) 2016, Golden Code Development Corporation. +** ALL RIGHTS RESERVED. Use is subject to license terms. +** +** Golden Code Development Corporation +** CONFIDENTIAL +** +** -#- -I- --Date-- ------------------------------Description---------------------------------- +** 001 SBI 20160605 The first version defines the empty sub module. +*/ + +"use strict"; === modified file 'src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.screen.js' --- src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.screen.js 2015-08-11 12:06:47 +0000 +++ src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.screen.js 2016-06-08 00:09:05 +0000 @@ -22,6 +22,7 @@ ** 009 SBI 20150731 Applied "use strict" directive, fixed undeclared variables, ** added end-lines on copy. ** 010 GES 20150716 Dynamically create the canvas that is the "default window". +** 011 SBI 20160607 Fixed the font height detection. */ "use strict"; @@ -401,15 +402,35 @@ font = cfg.font.size + 'px ' + cfg.font.name; bold = 'bold ' + font; - + console.debug("Font name: " + font); ctx.font = font; dx = ctx.measureText('\u2500').width; + // closest integer + dx = (dx + 0.5) | 0; + dy = fontMetrics.cellHeight(font); - canvas.width = cols * dx; + console.debug("dx: " + dx + " dy:" + dy); + + var vertical = fontMetrics.calculatePureTextHeight(font, '\u2502'); + var offset = 0; + if (dy > vertical) + { + offset = dy - vertical; + } + // to cover dy with vertical lines it is required to draw two '\u2502' chars + me.verticalOffset = offset; + + console.debug("verticalOffset=" + me.verticalOffset); + + canvas.width = cols * dx; canvas.height = rows * dy; +// console.debug("cols: " + cols + " rows:" + rows); +// +// console.debug("width: " + canvas.width + " height: " + canvas.height); + ctx.fillStyle = cfg.font.color.b; ctx.fillRect(0, 0, canvas.width, canvas.height); @@ -433,13 +454,14 @@ } // export some values - me.canvasWidth = canvas.width; + me.canvasWidth = canvas.width; me.canvasHeight = canvas.height; - me.charWidth = dx; + me.charWidth = dx; me.charHeight = dy; // container center aligned - document.getElementById(cfg.container).style.width = me.canvasWidth + 'px'; + document.getElementById(cfg.container).style.width = me.canvasWidth + 'px'; + //document.getElementById(cfg.container).style.height = me.canvasHeight + 'px'; canvas.focus(); }; @@ -619,12 +641,19 @@ ctx.save(); ctx.beginPath(); - ctx.rect(x, y, dx, dy); + ctx.rect(x, y - me.verticalOffset, dx, dy + me.verticalOffset); ctx.clip(); - - ctx.fillText(text, x, y, dx); + // TODO to separate border drawings + // to fix vertical border drawings + if (me.verticalOffset > 0 && text.indexOf('\u2502') >= 0) + { + ctx.fillText('\u2502', x, y - me.verticalOffset); + ctx.fillText('\u2502', x, y + me.verticalOffset); + //console.debug(text + " x=" + x + " y=" + y + " f=" + ctx.font + " dx=" + dx + " dy=" + dy); + } + ctx.fillText(text, x, y, dx); - ctx.restore(); + ctx.restore(); }; /** @@ -643,10 +672,13 @@ var width = 128; /** Canvas use to measure metrics. */ - var fontCanvas; + var fontCanvas = document.createElement('canvas'); + fontCanvas.height = height; + fontCanvas.width = width; + /** 2D graphical context. */ - var fontCtx; + var fontCtx = fontCanvas.getContext('2d'); /** * Get font height. @@ -657,66 +689,171 @@ */ me.cellHeight = function(font) { - fontCanvas = document.createElement('canvas'); - fontCanvas.setAttribute('height', height); - fontCanvas.setAttribute('width', width); - fontCtx = fontCanvas.getContext('2d'); - fontCtx.fillStyle = 'black'; - fontCtx.fillRect(0, 0, width, height); + // character height + me.charHeight = calculatePureTextHeight(font, '\u2503Eghy'); + + return me.charHeight; + }; + + /** + * Calculates the pure text height for the given font without antialiasing. + * + * @param {String} + * The string font representation + * @param {String} + * The text to measure its height. + * + * @return The height in pixels that is occupied by the given text for the provided font + * without antialiasing. + */ + function calculatePureTextHeight(font, text) + { + fontCtx.clearRect(0, 0, width, height); fontCtx.textBaseline = 'top'; fontCtx.fillStyle = 'white'; fontCtx.font = font; - fontCtx.fillText('\u2503Eghy', 0, 0); - - var pixels = fontCtx.getImageData(0, 0, width, height).data; - - // row numbers where we first find letter end where it ends + fontCtx.fillText(text, 0, 0); + + var image = fontCtx.getImageData(0, 0, width, height); + var d = calculatePixelsDistribution(image); + //console.debug(d); + var s = calculateMeanAndVariance(d, 0, height, 0); + //console.debug(s); + return findValuableDomain(d, 0, height, s[0], s[1], 0); + }; + + /** + * Calculate pixels horizontal distribution for the given image + * + * @param {ImageData} img + * The provided image to test. + * @return The array built from the average of sqrt(R*R + G*G + B*B) along horizontals. + */ + function calculatePixelsDistribution(img) + { + var awidth = img.width; + var aheight = img.height; + var data = img.data; + var x = 0; + var y = 0; + var w = 0; + var distribution = []; + var count = 0; + var pixelsInBytes = awidth * aheight * 4; + for (var p = 0; p < pixelsInBytes;) + { + if (distribution[y] === undefined) + { + distribution[y] = 0; + } + w = Math.sqrt(data[p] * data[p] + data[p + 1] * data[p + 1] + data[p + 2] * data[p + 2] /*+ data[p + 3] * data[p + 3]*/); + if (w > 0) + { + // console.debug(p + ":" + data[p] + ":" + data[p + 1] + ":" + data[p + 2]) + count++; + distribution[y] += w; + } + x++; + if (x === width) + { + distribution[y] = distribution[y] / (count > 0 ? count : 1); +// distribution[y] = (distribution[y] / count + 0.5) | 0; + y++; + x = 0; + count = 0; + } + p += 4; + }; + return distribution; + } + + /** + * Calculate the mean and the variance for the target distribution along the provided + * segment and the given threshold. + * + * @param {Array} d + * The target distribution. + * @param {Integer} i1 + * The point that defines the distribution domain. + * @param {Integer} i2 + * The point that defines the distribution domain. + * @param {Number} threshold + * Defines the low bound for the distribution values. + * + * @return The 2-elements array filled with the mean and the variance. + */ + function calculateMeanAndVariance(d, i1, i2, threshold) + { + var n = 0; + var mean = 0; + var M2 = 0; + var delta = 0; + for (var i = i1; i < i2; i++) + { + if (d[i] > threshold) + { + n++; + delta = d[i] - mean; + mean += delta / n; + M2 += delta * (d[i] - mean); + } + } + var v; + if (n < 2) + { + v = undefined; + } + else + { + v = M2 / (n - 1); + } + + return [mean, v]; + } + + /** + * Defines the valuable domain for this distribution taken into account its mean and + * its variance throwing out values that are less or equal than the provided threshold. + * + * @param {Array} d + * The target distribution. + * @param {Integer} i1 + * The point that defines the distribution domain. + * @param {Integer} i2 + * The point that defines the distribution domain. + * @param {Number} mean + * The mean of the given distribution d. + * @param {Number} variance + * The variance of the given distribution d. + * @param {Number} threshold + * Defines the low bound for the distribution values. + * + * @return The valuable domain width for the target distribution. + */ + function findValuableDomain(d, i1, i2, mean, variance, threshold) + { var beg = -1; + for (var i = i1; i < i2; i++) + { + if (d[i] > threshold && ((d[i] - mean) * (d[i] - mean)) <= 9 * variance) + { + beg = i; + break; + } + } var end = -1; - - for (var row = 0; row < height; row++) + for (var i = i2 - 1; i >= i1; i--) { - for (var col = 0; col < width; col++) + if (d[i] > threshold && ((d[i] - mean) * (d[i] - mean)) <= 9 * variance) { - var index = (row * width + col) * 4; - - // if pixel is not white (background color) - if (pixels[index] === 0) - { - // we havent met white (font color) pixel - // on the row and the letters was detected - if (col === (width - 1) && beg !== -1) - { - end = row; - row = height; - break; - } - } - else - { - // we find top of letter - if (beg === -1) - { - beg = row; - } - // ..letters body - break; - } + end = i; + break; } } - - // space at top - me.top = beg; - - // character height - me.charHeight = end - beg; - - // cell height top + charHeight - me.cellHeight = end; - - // cell height - return p2j.isWindows ? end : end - 1; - }; + return end - beg + 1; + } + + me.calculatePureTextHeight = calculatePureTextHeight; return me; })(); === modified file 'src/com/goldencode/p2j/ui/client/driver/web/index.html' --- src/com/goldencode/p2j/ui/client/driver/web/index.html 2016-06-03 10:10:16 +0000 +++ src/com/goldencode/p2j/ui/client/driver/web/index.html 2016-06-06 08:10:15 +0000 @@ -131,6 +131,6 @@ - === modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.keyboard.js' --- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.keyboard.js 2016-06-03 18:08:16 +0000 +++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.keyboard.js 2016-06-05 21:05:05 +0000 @@ -103,7 +103,10 @@ */ var doVT100 = function(key, evt) { - if (evt.ctrlKey) + // process COMMAND key for Safari as CTRL key + var metaToCtrl = p2j.isSafari && evt.metaKey; + + if (evt.ctrlKey || metaToCtrl) { // CTRL keys var charCode = p2j.keymap.mapKey(evt); @@ -268,11 +271,15 @@ function onkeypress(evt) { var key = evt.charCode; + + // process COMMAND key for Safari as CTRL key + var metaToCtrl = p2j.isSafari && evt.metaKey; - // prevent Firefox keypress on CTRL-C and CTRL-V - if (p2j.clipboard.enabled && p2j.isFirefox && evt.ctrlKey) + // prevent Firefox keypress on CTRL-C and CTRL-V + // Chrome doesn't generate keypress event for CTRL-C and CTRL-V + if (p2j.clipboard.enabled && (p2j.isFirefox && evt.ctrlKey || metaToCtrl)) { - if (key === 99 || key === 118) + if (key === 99 || key === 118 || (p2j.isSafari && (key === 3 || key === 22))) { return; } @@ -318,7 +325,8 @@ { var key = evt.keyCode; - if (altChar || key === keys.CTRL || key === keys.SHIFT) + if (altChar || key === keys.CTRL || key === keys.SHIFT || key === keys.LEFT_WINDOW || + key === keys.RIGHT_WINDOW) { return; } @@ -327,7 +335,7 @@ { if (evt.location === evt.DOM_KEY_LOCATION_RIGHT) { - altChar = evt.ctrlKey; + altChar = evt.ctrlKey; } return; } @@ -353,9 +361,12 @@ escape = !escape; } - return; + return; }; - + + // process COMMAND key for Safari as CTRL key + var metaToCtrl = p2j.isSafari && evt.metaKey; + var p4code = -1; var charCode = p2j.keymap.mapKey(evt); @@ -413,7 +424,7 @@ else { p4code = -1; - if (evt.ctrlKey) + if (evt.ctrlKey || metaToCtrl) { switch(key) { @@ -860,7 +871,10 @@ // then we can rely on the lastKey that is merged with keys modifiers var charCode = evt.charCode > 0 ? evt.charCode : printedCode; var code = -1; + + // process COMMAND key for Safari as CTRL key var metaToCtrl = p2j.isSafari && meta; + if (ctrl || metaToCtrl) { if (isAlphabeticCharacter(lastKey)) @@ -950,6 +964,8 @@ // In general (lastKey.keyCode === evt.keyCode) is true but if the keys are permuted, // then we can rely on the lastKey that is merged with keys modifiers var code = mappedCode === undefined ? lastKey.keyCode : mappedCode; + + // process COMMAND key for Safari as CTRL key var metaToCtrl = p2j.isSafari && meta; if (ctrl || metaToCtrl) === modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.keymap.js' --- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.keymap.js 2016-06-03 18:08:16 +0000 +++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.keymap.js 2016-06-05 20:49:39 +0000 @@ -798,7 +798,10 @@ { var ctrlCode = -1; - if (evt.ctrlKey || (p2j.isSafari && evt.metaKey)) + // process COMMAND key for Safari as CTRL key + var metaToCtrl = p2j.isSafari && evt.metaKey; + + if (evt.ctrlKey || metaToCtrl) { if (code === 50 || code === 64) //'2' {