=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java'
--- src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java 2015-08-20 14:07:03 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java 2015-08-20 14:14:14 +0000
@@ -126,4 +126,7 @@
/** Restack the z-order of all windows. */
public static final byte MSG_RESTACK_WINDOWS = (byte) 0x95;
+
+ /** Set the stroke style for a window. */
+ public static final byte MSG_SET_STROKE_STYLE = (byte) 0x96;
}
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/index.html'
--- src/com/goldencode/p2j/ui/client/driver/web/index.html 2015-08-12 17:42:50 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/index.html 2015-08-20 12:40:07 +0000
@@ -9,6 +9,7 @@
+
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js'
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js 2015-08-20 14:07:03 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js 2015-08-20 14:15:40 +0000
@@ -24,7 +24,7 @@
** requests.
** 010 GES 20150818 Added more GUI message support including fonts, cursors and z-order.
** Once the web socket has connected, notify the Java side, so that it can start
-** sending requests.
+** sending requests, added line strokes.
*/
"use strict";
@@ -534,6 +534,13 @@
}
p2j.screen.restackZOrderEntries(winids);
break;
+ case 0x96:
+ // set line stroke
+ var strokeStyle = me.readInt32BinaryMessage(message, 1);
+ var strokeWidth = me.readInt32BinaryMessage(message, 5);
+ var wid = me.readInt32BinaryMessage(message, 9);
+ p2j.screen.setLineStroke(strokeStyle, strokeWidth, wid);
+ break;
};
}
else
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java 2015-08-18 19:50:34 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java 2015-08-20 10:02:03 +0000
@@ -17,7 +17,7 @@
** font creation/selection.
** 005 GES 20150817 Removed isOnTop() since it is unnecessary. The saveFocusListeners(),
** restoreFocusListeners() and moveToTop() are only needed for Swing usage and
-** have been removed from this class.
+** have been removed from this class, added line strokes.
*/
package com.goldencode.p2j.ui.client.gui.driver.web;
@@ -362,6 +362,7 @@
websock.setColor(ps.color.getRed(), ps.color.getGreen(), ps.color.getBlue());
break;
case SET_LINE_STROKE:
+ websock.setLineStroke(ps.stroke.ordinal(), Math.round(ps.strokeWidth), getWindowId());
break;
case SET_FONT:
websock.setFont(ps.font.font);
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java 2015-08-20 14:07:03 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java 2015-08-20 14:17:12 +0000
@@ -12,8 +12,8 @@
** 001 GES 20150331 First version which is a placeholder using the common parent code as ChUI.
** 002 GES 20150701 Added messages for a first pass at GUI support,
** implemented an images drawing operation.
-** 003 CA 20150810 Added operations for font, metrics and string drawing. Added z-order
-** support.
+** 003 CA 20150810 Added operations for font, metrics and string drawing. Added z-order,
+** line strokes.
** 004 CA 20150820 Moved the message receiving APIs to parent class.
*/
@@ -1231,6 +1231,31 @@
}
/**
+ * Sends MSG_SET_STROKE_STYLE to order the current window stroke to be changed
+ * on the client side. It sends a window its stroke style and line width. All possible stroke
+ * styles are listed by LineStroke enumeration.
+ *
+ * @param strokeStyle
+ * The known stroke style id.
+ * @param width
+ * The stroke line width.
+ * @param wid
+ * The window id.
+ */
+ public void setLineStroke(int strokeStyle, int width, int wid)
+ {
+ byte[] message = new byte[13];
+
+ message[0] = WebClientMessageTypes.MSG_SET_STROKE_STYLE;
+
+ writeMessageInt32(message, 1, strokeStyle);
+ writeMessageInt32(message, 5, width);
+ writeMessageInt32(message, 9, wid);
+
+ sendBinaryMessage(message);
+ }
+
+ /**
* Draw a string at the specified location.
*
* @param text
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js 2015-08-19 20:05:05 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js 2015-08-20 14:22:24 +0000
@@ -84,6 +84,8 @@
SET_TITLE : 29
};
+ var strokesManager = new LineStrokes();
+
/**
* Constructor for a Window class that represents a Progress 4GL window instance.
*
@@ -138,12 +140,17 @@
// eliminate anti-aliasing of images
this.ctx.imageSmoothingEnabled = false;
+ // the current window stroke style
+ this.strokeStyle = strokesManager.getDefaultStrokeStyle();
+ // the current window stroke width
+ this.strokeWidth = 1;
+
// force all drawing to be inside pixel "cells" instead of "stradling" between two cells
// which is the default; this eliminates much of the worst of the anti-aliasing and
// positioning problems inherent in canvas operations; this will also save off the
// current state of the graphics context so that it can be restored later
this.translate(0.5, 0.5);
- }
+ };
/**
* Cleanup any resources, including any linkages to the window from an owning window.
@@ -353,7 +360,7 @@
this.ctx.rect(x, y, width, height);
this.ctx.clip();
}
- }
+ }
};
/**
@@ -430,7 +437,7 @@
Window.prototype.resize = function(width, height)
{
// save off the previously drawn content
- var oldPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ var oldPixels = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
// this is expensive, but we really do need to change the overall size of the canvas
this.canvas.width = width;
@@ -441,7 +448,7 @@
this.replay();
// re-blit the previously drawn content
- ctx.putImageData(oldPixels, 0, 0);
+ this.ctx.putImageData(oldPixels, 0, 0);
};
/**
@@ -454,6 +461,42 @@
{
this.canvas.style.cursor = style;
};
+
+ /**
+ * Sets the stroke style.
+ *
+ * @param {Number} strokeStyle
+ * The predefined stroke style.
+ */
+ Window.prototype.setStrokeStyle = function(strokeStyle)
+ {
+ this.strokeStyle = strokeStyle;
+ };
+
+ /**
+ * Sets the stroke line width.
+ *
+ * @param {Number} width
+ * The stroke line width.
+ */
+ Window.prototype.setStrokeWidth = function(width)
+ {
+ this.strokeWidth = width;
+ };
+
+ /**
+ * Sets the line stroke.
+ *
+ * @param {Number} strokeStyle
+ * The predefined stroke style.
+ * @param {Number} width
+ * The stroke line width.
+ */
+ Window.prototype.setLineStroke = function(strokeStyle, width)
+ {
+ this.setStrokeStyle(strokeStyle);
+ this.setStrokeWidth(width);
+ };
/**
* Draw the given list of operations in the canvas.
@@ -521,11 +564,11 @@
// in this case, the "y" is the height in which it needs to be vertically centered
y = y / 2;
- ctx.textBaseline = 'middle';
+ this.ctx.textBaseline = 'middle';
}
else
{
- ctx.textBaseline = 'top';
+ this.ctx.textBaseline = 'top';
}
this.ctx.fillText(text, x, y);
@@ -554,16 +597,16 @@
var lheight = p2j.socket.readInt32BinaryMessage(message, idx + offset);
offset = offset + 4;
- var textWidth = p2j.fonts.getTextWidth(this.currentFont, text);
- var textHeight = p2j.fonts.getTextHeight(this.currentFont, text);
+ var textWidth = p2j.fonts.getTextWidth(currentFont, text);
+ var textHeight = p2j.fonts.getTextHeight(currentFont, text);
var widthScale = lwidth / textWidth;
var heightScale = lheight / textHeight;
// scale drawing context to computed width
// this scales the desired structure.x as well so it needs adjusting
- ctx.save();
- ctx.scale(widthScale, heightScale);
+ this.ctx.save();
+ this.ctx.scale(widthScale, heightScale);
var scaleBackWidth = 1 / widthScale;
var scaleBackHeight = 1 / heightScale;
@@ -573,15 +616,15 @@
// in this case, the "y" is the height in which it needs to be vertically centered
y = y / 2;
- ctx.textBaseline = 'middle';
+ this.ctx.textBaseline = 'middle';
}
else
{
- ctx.textBaseline = 'top';
+ this.ctx.textBaseline = 'top';
}
- ctx.fillText(text, x * scaleBackWidth, y * scaleBackHeight);
- ctx.restore();
+ this.ctx.fillText(text, x * scaleBackWidth, y * scaleBackHeight);
+ this.ctx.restore();
break;
case ops.DRAW_PARAGRAPH:
@@ -605,7 +648,7 @@
width = p2j.socket.readInt32BinaryMessage(message, idx + offset);
offset = offset + 4;
- ctx.textBaseline = 'top';
+ this.ctx.textBaseline = 'top';
me.layoutParagraphWorker(text, fontId, x, y, width, true);
@@ -615,7 +658,9 @@
var y1 = p2j.socket.readInt32BinaryMessage(message, idx + 5);
var x2 = p2j.socket.readInt32BinaryMessage(message, idx + 9);
var y2 = p2j.socket.readInt32BinaryMessage(message, idx + 13);
- drawLine(this.ctx, x1, y1, x2, y2, this.rawColor);
+ strokesManager.applyStrokeToPath(this.ctx,
+ this.strokeStyle, this.strokeWidth, this.rawColor,
+ drawLine(this.ctx, x1, y1, x2, y2, this.rawColor));
this.ctx.stroke();
break;
case ops.DRAW_RECT:
@@ -623,7 +668,9 @@
y = p2j.socket.readInt32BinaryMessage(message, idx + 5);
width = p2j.socket.readInt32BinaryMessage(message, idx + 9);
height = p2j.socket.readInt32BinaryMessage(message, idx + 13);
- drawRect(this.ctx, x, y, width, height, this.rawColor, false);
+ strokesManager.applyStrokeToPath(this.ctx,
+ this.strokeStyle, this.strokeWidth, this.rawColor,
+ drawRect(this.ctx, x, y, width, height, this.rawColor, false));
break;
case ops.DRAW_ROUND_RECT:
x = p2j.socket.readInt32BinaryMessage(message, idx + 1);
@@ -658,7 +705,7 @@
imgDataOffset = idx + 22;
loadedImages.set(key, message.subarray(imgDataOffset, imgDataOffset + pixelsInBytes));
}
- drawImage(x, y, width, height, imgData, imgDataOffset);
+ drawImage(this.ctx, x, y, width, height, imgData, imgDataOffset);
break;
case ops.FILL_RECT:
x = p2j.socket.readInt32BinaryMessage(message, idx + 1);
@@ -673,7 +720,7 @@
width = p2j.socket.readInt32BinaryMessage(message, idx + 9);
height = p2j.socket.readInt32BinaryMessage(message, idx + 13);
diameter = p2j.socket.readInt32BinaryMessage(message, idx + 17);
- drawRoundRect(ctx, x, y, width, height, diameter, this.rawColor, true);
+ drawRoundRect(this.ctx, x, y, width, height, diameter, this.rawColor, true);
break;
case ops.FILL_POLYGON:
idx += 1;
@@ -719,14 +766,14 @@
case ops.SET_FONT:
fontId = p2j.socket.readInt32BinaryMessage(message, idx + 1);
- this.setFont(fontId);
+ this.setFont(this.ctx, fontId);
break;
case ops.SET_FONT_STYLE:
var style = p2j.socket.readInt32BinaryMessage(message, idx + 1);
- if (p2j.fonts.setFontStyle(this.currentFont, style))
+ if (p2j.fonts.setFontStyle(currentFont, style))
{
- fname = p2j.fonts.getFontName(this.currentFont);
+ fname = p2j.fonts.getFontName(currentFont);
this.ctx.font = fname;
}
@@ -792,7 +839,7 @@
function isValidWindowId(wid)
{
return (typeof wid === 'number') && (wid % 1 === 0) && wid > 0;
- }
+ };
/**
* Checks if the given value already exists as a window id.
@@ -805,8 +852,8 @@
function isExistingWindowId(wid)
{
return winlist[wid] instanceof Window;
- }
-
+ };
+
/**
* Obtain the specified window.
*
@@ -819,8 +866,8 @@
function getWindow(wid)
{
return winlist[wid] instanceof Window ? winlist[wid] : null;
- }
-
+ };
+
/**
* Find the index of the given window in the z-order list.
*
@@ -855,8 +902,8 @@
}
return found;
- }
-
+ };
+
/**
* Adds the given window to the end of the z-order list, setting the z-order value as needed.
*
@@ -875,7 +922,7 @@
// assign the z-order
win.canvas.style.zIndex = zidx;
- }
+ };
/**
* Removes the given window from the z-order list and resets the z-order values of all
@@ -898,7 +945,7 @@
}
return removeZOrderEntryWorker(found);
- }
+ };
/**
* Removes the given element from the z-order list and resets the z-order values of all
@@ -924,7 +971,7 @@
}
return removed;
- }
+ };
/**
* Moves the given window to the top of the z-order list and resets the z-order values of all
@@ -945,7 +992,7 @@
addZOrderEntry(entry.id, entry.win);
}
- }
+ };
/**
* Directly draw the specified pixel in the given color.
@@ -959,14 +1006,14 @@
* @param {Number[]} color
* Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
*/
- function drawPixel(ctx, x, y, color)
+ Window.prototype.drawPixel = function(ctx, x, y, color)
{
- pixData[0] = color[0];
- pixData[1] = color[1];
- pixData[2] = color[2];
+ this.pixData[0] = color[0];
+ this.pixData[1] = color[1];
+ this.pixData[2] = color[2];
- ctx.putImageData(pixel, x, y);
- }
+ this.ctx.putImageData(pixel, x, y);
+ };
/**
* Draw a line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing.
@@ -985,9 +1032,14 @@
* Y coordinate of the ending pixel to be drawn.
* @param {Number[]} color
* Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
+ *
+ * @return {Array} path
+ * The {x:.,y:.} point per a pixel array that represents the rectangle outerline.
*/
- function drawLine(ctx, x1, y1, x2, y2, color)
+ Window.prototype.drawLine = function(ctx, x1, y1, x2, y2, color)
{
+ // holds the line pixels to draw
+ var path = [];
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
@@ -1004,7 +1056,11 @@
while (true)
{
- drawPixel(ctx, x, y, color);
+ if (strokesManager.isDirectDrawingStrokeStyle(this.strokeStyle))
+ {
+ drawPixel(ctx, x, y, color);
+ }
+ path.push({x : x, y : y});
if (x == x2 && y == y2)
break;
@@ -1023,7 +1079,9 @@
y += yIncr;
}
}
- }
+
+ return path;
+ };
/**
* Fill or stroke the current path on the given context, first using the current path as a
@@ -1052,8 +1110,8 @@
}
ctx.restore();
- }
-
+ };
+
/**
* Draw a rectangle in the given color and dimensions with the line drawing being overwritten
* using direct drawing to eliminate the negative/unwanted effects of alni-aliasing.
@@ -1073,8 +1131,11 @@
* This will be used for the border lines and when in fill mode, also the interior.
* @param {Boolean} fill
* true
to fill the drawn rectangle with the given color.
+ *
+ * @return {Array} path
+ * The {x:.,y:.} point per a pixel array that represents the rectangle outerline.
*/
- function drawRect(ctx, x, y, width, height, color, fill)
+ Window.prototype.drawRect = function(ctx, x, y, width, height, color, fill)
{
// use vector operations for the interior of the rectangle
if (fill)
@@ -1085,15 +1146,20 @@
}
// now overdraw the stroked portion to eliminate anit-aliasing
- drawLine(ctx, x, y, x + width, y, color);
- drawLine(ctx, x, y + 1, x, y + height, color);
- drawLine(ctx, x + width, y + 1, x + width, y + height, color);
- drawLine(ctx, x + 1, y + height, x + width - 1, y + height, color);
- }
+ // to draw rectangle following a clockwise direction
+ var path = drawLine(ctx, x, y, x + width, y, color);
+ Array.prototype.push.apply(path, drawLine(ctx, x + width, y + 1, x + width, y + height, color));
+ Array.prototype.push.apply(path, drawLine(ctx, x + width - 1, y + height, x + 1, y + height, color));
+ Array.prototype.push.apply(path, drawLine(ctx, x, y + height, x, y + 1, color));// close the path
+
+ return path;
+ };
/**
* It draws an image on the canvas.
*
+ * @param {CanvasRenderingContext2D} ctx
+ * The canvas 2D graphics context on which to draw.
* @param {Number} x
* X coordinate of the top left corner.
* @param {Number} y
@@ -1107,7 +1173,7 @@
* @param {Number} imgDataOffset
* The offset of the encoded image data.
*/
- function drawImage(x, y, width, height, imgData, imgDataOffset)
+ Window.prototype.drawImage = function(ctx, x, y, width, height, imgData, imgDataOffset)
{
var img = ctx.createImageData(width, height);
var data = img.data;
@@ -1121,7 +1187,7 @@
data[i + 3] = imgData[j + 3];
}
ctx.putImageData(img, x, y);
- }
+ };
/**
* Convert a standard fillStyle or strokeStyle color into an array of [ R, G, B ] values.
@@ -1162,7 +1228,7 @@
}
return [ r, g, b ];
- }
+ };
/**
* Test if the given argument is an array of 3 integer values.
@@ -1199,7 +1265,7 @@
}
return true;
- }
+ };
/**
* Convert the given array of 3 integer values into an HTML color string.
@@ -1219,7 +1285,7 @@
return "rgb(" + color[0].toString() + ", "
+ color[1].toString() + ", "
+ color[2].toString() + ")";
- }
+ };
/**
* Convert the given array of RGB values into a lighter color in a manner that is compatible
@@ -1254,7 +1320,7 @@
var b = Math.min(Math.floor(bIn / SCALE_FACTOR), 255);
return [ r, g, b ];
- }
+ };
/**
* Convert the given array of RGB values into a darker color in a manner that is compatible
@@ -1277,7 +1343,7 @@
var b = Math.max(0, Math.floor(color[2] * SCALE_FACTOR));
return [ r, g, b ];
- }
+ };
/**
* Draw a rounded rectangle with the given context, dimensions and fill.
@@ -1302,7 +1368,7 @@
* true
to fill the rectangle with the current color, otherwise just
* stroke the rectangle.
*/
- function drawRoundRect(ctx, x, y, width, height, diameter, color, fill)
+ Window.prototype.drawRoundRect = function(ctx, x, y, width, height, diameter, color, fill)
{
var radius = diameter / 2;
@@ -1352,7 +1418,7 @@
drawLine(ctx, rightUpX, rightUpY, rightDownX, rightDownY, color);
drawLine(ctx, bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, color);
drawLine(ctx, leftUpX, leftUpY, leftDownX, leftDownY, color);
- }
+ };
/**
* Draw a slightly shaded "3D" rectangle with the given context, dimensions and fill. In
@@ -1380,7 +1446,7 @@
* @param {Boolean} raise
* true
to draw in raised mode.
*/
- function draw3DRect(ctx, x, y, width, height, color, fill, raised)
+ Window.prototype.draw3DRect = function(ctx, x, y, width, height, color, fill, raised)
{
// save off our colors
var oriFillColor = ctx.fillStyle;
@@ -1422,8 +1488,8 @@
// restore our colors
ctx.fillStyle = oriFillColor;
ctx.strokeStyle = oriStrokeColor;
- }
-
+ };
+
/**
* Draw a closed polygon with the given context, vertices and fill.
*
@@ -1441,7 +1507,7 @@
* true
to fill the rectangle with the current color, otherwise just
* stroke the rectangle.
*/
- function drawPolygon(ctx, xPoints, yPoints, num, color, fill)
+ Window.prototype.drawPolygon = function(ctx, xPoints, yPoints, num, color, fill)
{
var i;
@@ -1462,26 +1528,28 @@
{
drawLine(ctx, xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], color);
}
- }
+ };
/**
* Set the font in the current context. If the current font does not get changed, then this
* will be a no-op.
*
+ * @param {CanvasRenderingContext2D} ctx
+ * The canvas 2D graphics context on which to draw.
* @param {Number} fontId
* The font identifier.
*/
- function setFont(fontId)
+ function setFont(ctx, fontId)
{
- if (fontId != this.currentFont)
+ if (fontId != currentFont)
{
var fname = p2j.fonts.getFontName(fontId);
- this.ctx.font = fname;
+ ctx.font = fname;
- this.currentFont = fontId;
+ currentFont = fontId;
}
- }
+ };
/**
* Find the next split position, so that the sub-text fits the given width.
@@ -1535,7 +1603,7 @@
while (end < txt.length);
return end;
- }
+ };
/**
* Split the word starting on the given index so that it fits the specified width.
@@ -1568,7 +1636,7 @@
}
return end;
- }
+ };
/**
* Find the next occurrence of the character given by the specified regex, starting from the
@@ -1587,7 +1655,7 @@
{
var indexOf = txt.substring(start).search(regex);
return (indexOf >= 0) ? (indexOf + start) : indexOf;
- }
+ };
/**
* Create a new top-level window (and the canvas that backs it).
@@ -1770,13 +1838,16 @@
/**
* Draw text on canvas.
*
- * @param {number} x x coordinate
- * @param {number} y y coordinate
- * @param {string} text text to draw
- * @param {number} a attribute
- * @param {object} v color pairs
+ * @param {CanvasRenderingContext2D} ctx
+ * The canvas 2D graphics context on which to draw.
+ * @param {Number} x
+ * The x coordinate.
+ * @param {Number} y
+ * The y coordinate.
+ * @param {String} text
+ * The text to draw
*/
- var drawText = function(ctx, x, y, text)
+ Window.prototype.drawText = function(ctx, x, y, text)
{
// TODO calc width and height
var width;
@@ -1902,6 +1973,25 @@
};
/**
+ * Sets the line stroke for a window with the given id.
+ *
+ * @param {Number} strokeStyle
+ * The predefined stroke style.
+ * @param {Number} width
+ * The stroke line width.
+ * @param {Number} wid
+ * Denotes the active window id.
+ */
+ me.setLineStroke = function(strokeStyle, width, wid)
+ {
+ var win = getWindow(wid);
+ if (win)
+ {
+ win.setLineStroke(strokeStyle, width);
+ }
+ };
+
+ /**
* Clear the screen.
*/
me.clear = function()
@@ -1941,6 +2031,8 @@
* The method performs a layout operation on the supplied text and returns the resulting
* paragraph height while maintaining the supplied maximum width.
*
+ * @param {CanvasRenderingContext2D} ctx
+ * The canvas 2D graphics context on which to draw.
* @param {String} txt
* The paragraph text.
* @param {Number} font
@@ -1957,7 +2049,7 @@
*
* @return {Number} The paragraph height.
*/
- me.layoutParagraphWorker = function(txt, font, x, y, width, draw)
+ me.layoutParagraphWorker = function(ctx, txt, font, x, y, width, draw)
{
var newLine = true;
var i = 0;
@@ -1965,9 +2057,9 @@
if (draw)
{
// unless we are drawing, there is no need in changing the context font
- this.ctx.save();
+ ctx.save();
- this.setFont(font);
+ this.setFont(ctx, font);
}
var height = 0;
@@ -1992,7 +2084,7 @@
if (draw)
{
- this.ctx.restore();
+ ctx.restore();
}
return height;
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js 1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js 2015-08-20 09:36:41 +0000
@@ -0,0 +1,398 @@
+/*
+** Module : p2j.strokes.js
+** Abstract : GUI-specific screen management
+**
+** Copyright (c) 2014-2015, Golden Code Development Corporation.
+** ALL RIGHTS RESERVED. Use is subject to license terms.
+**
+** Golden Code Development Corporation
+** CONFIDENTIAL
+**
+** -#- -I- --Date-- ------------------------------Description----------------------------------
+** 001 SBI 20150819 The first version defines LineStrokes class as a strokes manager.
+*/
+
+"use strict";
+
+/**
+ * Defines the known stroke styles and methods to draw styled outer lines.
+ */
+function LineStrokes()
+{
+ /**
+ * Joins path segments by extending their outside edges until
+ * they meet.
+ */
+ var JOIN_MITER = 0;
+
+ /**
+ * Joins path segments by rounding off the corner at a radius
+ * of half the line width.
+ */
+ var JOIN_ROUND = 1;
+
+ /**
+ * Joins path segments by connecting the outer corners of their
+ * wide outlines with a straight segment.
+ */
+ var JOIN_BEVEL = 2;
+
+ /**
+ * Ends unclosed subpaths and dash segments with no added
+ * decoration.
+ */
+ var CAP_BUTT = 0;
+
+ /**
+ * Ends unclosed subpaths and dash segments with a round
+ * decoration that has a radius equal to half of the width
+ * of the pen.
+ */
+ var CAP_ROUND = 1;
+
+ /**
+ * Ends unclosed subpaths and dash segments with a square
+ * projection that extends beyond the end of the segment
+ * to a distance equal to half of the line width.
+ */
+ var CAP_SQUARE = 2;
+
+ /**
+ * This is the list of all possible line stoke types.
+ */
+ var LineStrokeEnum =
+ {
+ DEFAULT : 0,
+ SPECIFIED_WIDTH : 1,
+ DOTTED : 2,
+ DOTTED_SMALL : 3,
+ DOTTED_SMALL_THIN : 4
+ };
+
+ var LineStroke =
+ {
+ /** Dotted line specific parameter. */
+ DOT_STEP : 2.0,
+
+ /** Dotted line specific parameter. */
+ DOT_STEP_SMALL : 1.0,
+
+ /** Dotted line width. */
+ DOT_LINE_WIDTH : 1.0,
+
+ /** Dotted thin line width. */
+ DOT_LINE_THIN_WIDTH : 0.5
+ };
+
+ var dotStroke = new BasicStroke(LineStroke.DOT_LINE_WIDTH, CAP_BUTT, JOIN_BEVEL, 0.0,
+ [LineStroke.DOT_STEP, LineStroke.DOT_STEP], LineStroke.DOT_STEP);
+
+ var dotSmallStroke = new BasicStroke(LineStroke.DOT_LINE_WIDTH, CAP_BUTT, JOIN_BEVEL, 0.0,
+ [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL], LineStroke.DOT_STEP_SMALL);
+
+ var dotSmallThinStroke = new BasicStroke(LineStroke.DOT_LINE_THIN_WIDTH, CAP_BUTT,
+ JOIN_BEVEL, 0.0, [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL],
+ LineStroke.DOT_STEP_SMALL);
+
+ var defaultStroke = new BasicStroke(1.0, CAP_SQUARE, JOIN_MITER, 10.0, null, 0.0);
+
+ /** Holds all java script styles of how the ends of lines are drawn. */
+ var caps = [ "butt", "round", "square"];
+
+ /**
+ * Holds all java script styles of how two connecting segments with non-zero lengths
+ * in a shape are joined together.
+ */
+ var joins = [ "miter", "round", "bevel"];
+
+ /**
+ * Holds properties for line drawing styles.
+ *
+ * @param width
+ * The width of lines to draw.
+ * @param cap
+ * The decoration of the line ends.
+ * @param join
+ * The decoration applied where path segments meet.
+ * @param miterlimit
+ * The limit to trim the miter join.
+ * @param dash
+ * The array representing the dashing pattern.
+ * @param dash_phase
+ * The offset to start the dashing pattern.
+ */
+ function BasicStroke(width, cap, join, miterLimit, dash, dash_phase)
+ {
+ this.getWidth = function() { return width; };
+ this.getCap = function() { return caps[cap]; };
+
+ this.getJoin = function() { return joins[join]; };
+ this.getMiterLimit = function() { return miterLimit; };
+
+ this.getDash = function() { return dash; };
+ this.getDashPhase = function() { return dash_phase; };
+ };
+
+ /**
+ * Returns the stroke style object.
+ *
+ * @param {Number} strokeStyle
+ * The stroke style id according to the LineStroke enumeration.
+ * @param {Number} width
+ * The line width.
+ *
+ * @return The basic line stroke object.
+ */
+ function getLineStroke(strokeStyle, width)
+ {
+ switch(strokeStyle)
+ {
+ case LineStrokeEnum.SPECIFIED_WIDTH:
+ return new BasicStroke(width, CAP_SQUARE, JOIN_MITER, 10.0, null, 0.0);
+ case LineStrokeEnum.DOTTED:
+ return dotStroke;
+ case LineStrokeEnum.DOTTED_SMALL:
+ return dotSmallStroke;
+ case LineStrokeEnum.DOTTED_SMALL_THIN:
+ return dotSmallThinStroke;
+ default:
+ return defaultStroke;
+ }
+ };
+
+ /**
+ * Returns the stroke path renderer.
+ *
+ * @param {CanvasRenderingContext2D} context
+ * The canvas renderer.
+ * @param {Number} strokeStyle
+ * The stroke style id according to the LineStroke enumeration.
+ * @param {Number} width
+ * The line width.
+ * @param {Number[]} strokeColor
+ * The array of 3 integer values between 0 and 255 inclusive, representing
+ * a stroke color.
+ *
+ * @return The stroke path renderer.
+ */
+ function getStrokePathRenderer(context, strokeStyle, width, strokeColor)
+ {
+ var basicStroke = getLineStroke(strokeStyle, width);
+ switch(strokeStyle)
+ {
+ case LineStrokeEnum.SPECIFIED_WIDTH:
+ return new WidenPathRenderer(context, basicStroke, strokeColor);
+ case LineStrokeEnum.DOTTED:
+ case LineStrokeEnum.DOTTED_SMALL:
+ case LineStrokeEnum.DOTTED_SMALL_THIN:
+ return new DotsPathRenderer(context, basicStroke, strokeColor);
+ default:
+ return { applyStroke : function (path) {} };
+ }
+ };
+
+ /**
+ * Apply the given stroke style to the JS native canvas renderer.
+ *
+ * @param {CanvasRenderingContext2D} context
+ * The canvas renderer.
+ * @param {Number} strokeStyle
+ * The stroke style id.
+ * @param {Number} width
+ * The line width.
+ */
+ this.apply = function(context, strokeStyle, width)
+ {
+ if (context instanceof CanvasRenderingContext2D)
+ {
+ var basicStroke = getLineStroke(strokeStyle, width);
+ context.lineWidth = basicStroke.getWidth();
+
+ context.lineCap = basicStroke.getCap();
+
+ context.lineJoin = basicStroke.getJoin();
+
+ context.miterLimit = basicStroke.getMiterLimit();
+ if (basicStroke.getDash())
+ {
+ context.setLineDash(basicStroke.getDash());
+ }
+ else
+ {
+ context.setLineDash([]);
+ }
+ context.lineDashOffset = basicStroke.getDashPhase();
+ }
+ }
+
+ /**
+ * Apply the given stroke style to the area outer bounds.
+ *
+ * @param {CanvasRenderingContext2D} context
+ * The canvas renderer.
+ * @param {Number} strokeStyle
+ * The stroke style id.
+ * @param {Number} width
+ * The line width.
+ * @param {Number[]} strokeColor
+ * The array of 3 integer values between 0 and 255 inclusive, representing
+ * a stroke color.
+ * @param {Array} path
+ * The array of points that forms the outline of the target area.
+ */
+ this.applyStrokeToPath = function(context, strokeStyle, width, strokeColor, path)
+ {
+ if (context instanceof CanvasRenderingContext2D)
+ {
+ var renderer = getStrokePathRenderer(context, strokeStyle, width, strokeColor);
+ renderer.applyStroke(path);
+ }
+ }
+
+
+ this.isDirectDrawingStrokeStyle = function(strokeStyle)
+ {
+ return LineStrokeEnum.DEFAULT == strokeStyle;
+ }
+
+ this.getDefaultStrokeStyle = function()
+ {
+ return LineStrokeEnum.DEFAULT;
+ }
+
+ /**
+ * Used to draw dash patterns on lines of pixels.
+ *
+ * @param {CanvasRenderingContext2D} context
+ * The canvas renderer.
+ * @param {Object} basicStroke
+ * The stroke style object.
+ * @param {Number[]} strokeColor
+ * The array of 3 integer values between 0 and 255 inclusive, representing
+ * a stroke color.
+ */
+ function DotsPathRenderer(ctx, basicStroke, strokeColor)
+ {
+ var pixel = ctx.createImageData(1, 1);
+ var pixelData = pixel.data;
+ pixelData[3] = 0xFF;
+
+ /**
+ * Normalizes a dash offset distance according to the given dash pattern.
+ * A normalized dash offset distance is a distance that is cut the corresponding segment
+ * from the dash pattern that is extended periodically in order to cover the target dash
+ * offset.
+ *
+ * @param {Array} dash
+ * The dash array that specifies the number of units to be drawn followed
+ * by the number of units to be skipped.
+ * @param {Number} dashOffset
+ * The offset distance from the first pattern point to the point which becomes
+ * a start point of the dash pattern.
+ *
+ * @return The container {startPhase : phase, startDashOn : dashOn, startIdx : idx},
+ * where the startPhase field holds a normalized dash offset, startDashOn defines
+ * to draw or to skip, the value of startIdx is the current dash pattern index.
+ */
+ function normalize(dash, dashOffset)
+ {
+ var phase = dashOffset;
+ var idx = 0;
+ var dashOn = true;
+ var d;
+ while (phase >= (d = dash[idx]))
+ {
+ phase -= d;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ }
+
+ return {startPhase : phase, startDashOn : dashOn, startIdx : idx};
+ }
+
+ /**
+ * Apply the given stroke to the line of pixels called a path.
+ *
+ * @param {Array} path
+ * The array of points that forms the outline of the target area.
+ */
+ this.applyStroke = function (path)
+ {
+ var dash = basicStroke.getDash();
+ if (!dash || dash.length == 0)
+ {
+ return;
+ }
+ var dashOffset = basicStroke.getDashPhase();
+ var len = dash.length;
+
+ var patternObj = normalize(dash, dashOffset);
+
+ var dashOn = patternObj.startDashOn;
+ var phase = patternObj.startPhase;
+ var idx = patternObj.startIdx;
+ var rest = dash[idx] - phase;
+ for (var i = 0; i < path.length; i++)
+ {
+ var point = path[i];
+ if (rest < 1)
+ {
+ idx = (idx + 1) % len;
+ rest = dash[idx];
+ dashOn = !dashOn;
+ }
+ rest -= 1;
+
+ if (dashOn)
+ {
+ pixelData[0] = strokeColor[0];
+ pixelData[1] = strokeColor[1];
+ pixelData[2] = strokeColor[2];
+ ctx.putImageData(pixel, point.x, point.y);
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Used to widen lines of pixels.
+ *
+ * @param {CanvasRenderingContext2D} context
+ * The canvas renderer.
+ * @param {Object} basicStroke
+ * The stroke style object.
+ * @param {Number[]} strokeColor
+ * The array of 3 integer values between 0 and 255 inclusive, representing
+ * a stroke color.
+ */
+ function WidenPathRenderer(ctx, basicStroke, strokeColor)
+ {
+ var width = basicStroke.getWidth();
+ var image = ctx.createImageData(width, width);
+ var imageData = image.data;
+
+ for (var i = 0; i < 4 * width * width; i += 4)
+ {
+ imageData[i] = strokeColor[0];
+ imageData[i + 1] = strokeColor[1];
+ imageData[i + 2] = strokeColor[2];
+ imageData[i + 3] = 0xFF;
+ }
+
+ /**
+ * To widen the line of pixels called a path according to the stroke style.
+ *
+ * @param {Array} path
+ * The array of points that forms the outline of the target area.
+ */
+ this.applyStroke = function (path)
+ {
+ for (var i = 0; i < path.length; i++)
+ {
+ var point = path[i];
+ ctx.putImageData(image, point.x - (width >> 1), point.y - (width >> 1));
+ }
+ }
+ }
+}
\ No newline at end of file