=== added file 'src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.virtual_desktop.js'
--- src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.virtual_desktop.js 1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.virtual_desktop.js 2015-09-06 23:04:05 +0000
@@ -0,0 +1,15 @@
+/*
+** Module : p2j.virtual_desktop.js
+** Abstract : CHUI-specific virtual desktop module.
+**
+** 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 20150906 The virtual desktop empty module.
+*/
+
+"use strict";
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/index.html'
--- src/com/goldencode/p2j/ui/client/driver/web/index.html 2015-09-05 16:09:44 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/index.html 2015-09-06 21:12:01 +0000
@@ -12,6 +12,7 @@
+
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js 2015-09-05 16:09:44 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js 2015-09-06 22:04:21 +0000
@@ -14,6 +14,18 @@
"use strict";
+/**
+ * Creates the canvas renderer.
+ *
+ * @param {HtmlCanvasElement} canvas
+ * The html canvas element.
+ * @param {CanvasRenderingContext2D} ctx
+ * The canvas 2D graphics context on which to draw.
+ * @param {LinesStroke} strokesManager
+ * The stroke manager
+ * @param {Object} logger
+ * The p2j logger.
+ */
function CanvasRenderer(canvas, ctx, strokesManager, logger)
{
this.canvas = canvas;
=== 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-09-05 16:09:44 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js 2015-09-06 23:31:23 +0000
@@ -17,6 +17,7 @@
** added a drawing image operation.
** 004 GES 20150818 Added more GUI support including fonts, cursors, z-order, mouse events.
* Fixed many problems with the initial implementation. Implemented SET_ICON.
+* Added the draggable task bar implementation.
*/
"use strict";
@@ -132,6 +133,15 @@
var strokesManager = new LineStrokes();
/**
+ * Holds the virtual desktop with task bar and bottom and right drop zones.
+ */
+ var desktop;
+
+ /**
+ * Holds the task bar.
+ */
+ var taskBar;
+ /**
* Constructor for a Window class that represents a Progress 4GL window instance.
*
* @param wid
@@ -694,6 +704,7 @@
loadedImages.set(key, message.subarray(imgDataOffset, imgDataOffset + pixelsInBytes));
}
this.canvasRenderer.drawImage(this.ctx, x, y, width, height, imgData, imgDataOffset);
+ taskBar.draw();
break;
case ops.FILL_ROUND_RECT:
x = p2j.socket.readInt32BinaryMessage(message, idx + 1);
@@ -813,6 +824,7 @@
case ops.SET_TITLE:
var title = p2j.socket.readStringBinaryMessage(message, idx + 1);
this.title = title;
+ taskBar.draw();
// TODO: force taskbar to repaint
break;
case ops.SET_ICON:
@@ -833,7 +845,7 @@
this.iconWidth = iconWidth;
this.iconHeight = iconHeight;
}
-
+ taskBar.setIconForTask(this.id, loadedImages.get(this.iconId));
break;
default:
if (typeof type !== "undefined")
@@ -948,7 +960,7 @@
*/
Window.prototype.iconify = function()
{
- // TODO: implement this
+ taskBar.iconify(this.id);
};
/**
@@ -960,22 +972,23 @@
// TODO: this message needs to be sent by the taskbar, when the window is being deiconified
// this API should just perform whatever actions are required (i.e. show the window, etc)
- var message = new Uint8Array(6);
-
- // message type
- message[0] = 0x10;
- offset = offset + 1;
-
- // 0. the window ID
- p2j.socket.writeInt32BinaryMessage(message, offset, wThis.id);
- offset = offset + 4;
-
- // 1. the iconification state
- message[offset] = 0;
- offset = offset + 1;
-
- // send the mouse event
- p2j.socket.send(message);
+// var message = new Uint8Array(6);
+//
+// // message type
+// message[0] = 0x10;
+// offset = offset + 1;
+//
+// // 0. the window ID
+// p2j.socket.writeInt32BinaryMessage(message, offset, this.id);
+// offset = offset + 4;
+//
+// // 1. the iconification state
+// message[offset] = 0;
+// offset = offset + 1;
+//
+// // send the mouse event
+// p2j.socket.send(message);
+ taskBar.deiconify(this.id);
};
/**
@@ -1324,6 +1337,9 @@
// add to the z-order list
addZOrderEntry(wid, newwin);
+ // creates new task icon widget for new window
+ taskBar.addTaskIcon(newwin);
+
return newwin;
};
@@ -1545,6 +1561,23 @@
};
/**
+ * Sends the active window state to the server.
+ *
+ * @param {Number} windowId
+ * The target windowId
+ */
+ function sendWindowStateActive(windowId)
+ {
+ var message = new Uint8Array(6);
+
+ message[0] = 0x10;
+ p2j.socket.writeInt32BinaryMessage(message, 1, windowId);
+ // 1. the iconification state
+ message[5] = 0;
+ p2j.socket.send(message);
+ }
+
+ /**
* Initialize module.
*
* @param {object} cfg configuration.
@@ -1556,6 +1589,13 @@
// enable all OS events
me.enableOsEvents(true);
+
+ desktop = new VirtualDesktop(
+ sendWindowStateActive,
+ [194, 194, 194],
+ [128, 128, 128],
+ p2j.logger);
+ taskBar = desktop.getTaskBar();
};
/**
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.virtual_desktop.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.virtual_desktop.js 1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.virtual_desktop.js 2015-09-06 23:44:56 +0000
@@ -0,0 +1,593 @@
+/*
+** Module : p2j.virtual_desktop.js
+** Abstract : GUI-specific virtual desktop to create task bar and drop zones
+**
+** 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 20150906 The virtual desktop to create task bar and drop zones.
+*/
+
+"use strict";
+
+
+
+
+
+
+/**
+ * Creates the virtual desktop with dragged task bar and two drop zones: the bottom and the right
+ * according to this css style:
+ *
+ *.right {
+ * position: fixed;
+ * top: 0px;
+ * right: 0px;
+ * height: 100%;
+ * width: 40px;
+ *}
+ *.bottom {
+ * position: fixed;
+ * bottom: 0px;
+ * height: 40px;
+ * width: 100%;
+ *}
+ *.virtualDesktop {
+ * position: fixed;
+ * left: 0px;
+ * top: 0px;
+ *}
+ *.canvas {
+ * position: relative;
+ * width: 100%;
+ * height: 100%;
+ *}
+ *.dock {
+ *}
+ *
+ * @param {Function} taskIconOnClickCallback
+ * The 1-argument function to send the active window state request to the server.
+ * @param {Array} bg
+ * The background task bar color. It is represented by the 3-elements array
+ * filled with red, green and blue values from 0 to 255.
+ * @param {Array} fg
+ * The foreground task bar color for task icons. It is represented by the 3-elements array
+ * filled with red, green and blue values from 0 to 255.
+ * @param {Object} logger
+ * The p2j global application logger.
+ */
+function VirtualDesktop(taskIconOnClickCallback, bg, fg, logger)
+{
+ /** task bar id*/
+ var TASK_BAR_ID = "taskBar";
+ /** drop zone class name*/
+ var DOCK_CLASS_NAME = "dock";
+ /** task bar side */
+ var TASK_BAR_WIDTH = 42;
+
+
+ /** the parent element for the virtual desktop */
+ var desktop = document.createElement("div");
+
+ desktop.style["position"] = "fixed";
+ desktop.style["top"] = "0px";
+ desktop.style["left"] = "0px";
+ var body = document.body;
+ body.appendChild(desktop);
+ var bottom = createBottomDropZone(DOCK_CLASS_NAME, TASK_BAR_WIDTH);
+ var taskBarPeer = createTaskBarPeer(TASK_BAR_ID);
+ bottom.appendChild(taskBarPeer);
+ desktop.appendChild(bottom);
+ desktop.appendChild(createRightDropZone(DOCK_CLASS_NAME, TASK_BAR_WIDTH));
+
+ var taskBar = new TaskBar(taskBarPeer, bg, fg, logger);
+
+ /**
+ * Creates the bottom drop zone.
+ *
+ * @param {String} dockClassName
+ * The drop zone class.
+ * @param {Number} height
+ * The bottom drop zone height.
+ *
+ * @return {HtmlElement}
+ * The parent element for the bottom drop zone.
+ */
+ function createBottomDropZone(dockClassName, height)
+ {
+ var bottom = document.createElement("div");
+ bottom.className = dockClassName;
+
+ bottom.style["position"] = "fixed";
+
+ bottom.style["bottom"] = "0px";
+
+ bottom.style["height"] = height + "px";
+ bottom.style["width"] = "100%";
+ return bottom;
+ };
+
+ /**
+ * Creates the right drop zone.
+ *
+ * @param {String} dockClassName
+ * The drop zone class.
+ * @param {Number} width
+ * The right drop zone width.
+ *
+ * @return {HtmlElement}
+ * The parent element for the right drop zone.
+ */
+ function createRightDropZone(dockClassName, width)
+ {
+ var right = document.createElement("div");
+ right.className = dockClassName;
+ right.style["position"] = "fixed";
+
+ right.style["right"] = "0px";
+ right.style["top"] = "0px";
+
+ right.style["height"] = "100%";
+ right.style["width"] = width + "px";
+ return right;
+ };
+
+ /**
+ * Creates the html element for the draggable task bar.
+ *
+ * @param {String} id
+ * The task bar peer element id.
+ *
+ * @return {HtmlElement}
+ * The task bar peer element.
+ */
+ function createTaskBarPeer(id)
+ {
+ var peer = document.createElement("div");
+ peer.id = id;
+ peer.style["position"] = "relative";
+
+ peer.style["height"] = "100%";
+ peer.style["width"] = "100%";
+ peer.draggable = true;
+ return peer;
+ };
+
+ /**
+ * Gets the task bar.
+ *
+ * @return {TaskBar}
+ * The task bar.
+ */
+ this.getTaskBar = function()
+ {
+ return taskBar;
+ };
+
+
+ /**
+ * Creates the task bar for the given peer element with the provided background and
+ * foreground colors.
+ *
+ * @param {HtmlElement} peer
+ * The task bar peer element.
+ * @param {Array} bg
+ * The background task bar color. It is represented by the 3-elements array
+ * filled with red, green and blue values from 0 to 255.
+ * @param {Array} fg
+ * The foreground task bar color for task icons. It is represented by the 3-elements array
+ * filled with red, green and blue values from 0 to 255.
+ * @param {Object} logger
+ * The p2j global application logger.
+ */
+ function TaskBar(peer, bg, fg, logger)
+ {
+ var DRAGGED_OPACITY = 0.3;
+ var TOP_PADDING = 2;
+ var LEFT_PADDING = 2;
+ var TASK_BAR_TITLE = "Task Bar";
+ var TASK_ICON_WIDTH = 40;
+ var TASK_ICON_HEIGHT = 32;
+
+ var SHIFT = 2;
+
+ var dragged;
+ var canvas = document.createElement('canvas');
+ canvas.className="canvas";
+ canvas.style["height"] = "100%";
+ canvas.style["width"] = "100%";
+
+ peer.appendChild(canvas);
+ var ctx = canvas.getContext('2d', {alpha : true});
+// console.log("peer width = " + peer.offsetWidth);
+// console.log("peer height = " + peer.offsetHeight);
+ var strokesManager = new LineStrokes();
+ var canvasRenderer = new CanvasRenderer(canvas, ctx, strokesManager, logger);
+
+ var taskIcons = [];
+
+ var foreground = fg;
+ var background = bg;
+
+ if (peer)
+ {
+ /** events fired on the draggable target */
+ peer.addEventListener("dragstart", startDragging);
+ peer.addEventListener("dragend", dragEnded);
+ peer.title = "Test";
+ //peer.addEventListener("drag", drag);
+ }
+
+ /**
+ * Layouts task icons according to the current task bar position:
+ * vertical or horizontal.
+ *
+ * @param {Number} width
+ * The task bar width in pixels.
+ * @param {Number} height
+ * The task bar height in pixels.
+ */
+ function doLayout(width, height) {
+ canvas.width = width;
+ canvas.height = height;
+// console.log("canvas width = " + canvas.width);
+// console.log("canvas height = " + canvas.height);
+
+ canvasRenderer.draw3DRect(ctx, 0, 0, width, height, background, true, true);
+ var horizontalLayout;
+ if (width > height)
+ {
+ horizontalLayout = true;
+ }
+ else
+ {
+ horizontalLayout = false;
+ }
+ var x = LEFT_PADDING;
+ var y = TOP_PADDING;
+ for (var i = 0; i < taskIcons.length; i++)
+ {
+ var taskIcon = taskIcons[i];
+ taskIcon.setLocation(x, y);
+ taskIcon.draw();
+ if (horizontalLayout)
+ {
+ x += (SHIFT + taskIcon.width);
+ }
+ else
+ {
+ y += (SHIFT + taskIcon.height);
+ }
+ }
+ }
+
+ /**
+ * Draws the task bar on the canvas.
+ */
+ this.draw = function()
+ {
+ doLayout(peer.offsetWidth, peer.offsetHeight);
+ }
+
+ /**
+ * Adds new task to the task bar.
+ *
+ * @param {Window} win
+ * The window to be represented by a task in the task bar.
+ *
+ * @return {TaskIcon}
+ * The task icon that represents the target window.
+ */
+ function addTaskIcon(win)
+ {
+ var taskIcon = new TaskIcon(win, null, TASK_ICON_WIDTH, TASK_ICON_HEIGHT, foreground);
+ taskIcons.push(taskIcon);
+ return taskIcon;
+ };
+
+ /**
+ * Sets an icon for the task that represents the target window.
+ *
+ * @param {Number} windowId
+ * The target window id.
+ * @param {Array} iconData
+ * It is the binary icon to set. The pixels array with 4-bytes per a pixel that
+ * are red, green, blue and alpha bytes.
+ *
+ * @return {TaskIcon}
+ * The task that represents the target window.
+ */
+ function setIconForTask(windowId, iconData)
+ {
+ var taskIcon = findTaskIcon(windowId);
+ taskIcon.iconData = iconData;
+ return taskIcon;
+ };
+
+ this.addTaskIcon = addTaskIcon;
+ this.setIconForTask = setIconForTask;
+
+ /**
+ * Find the window task that represents the target window.
+ *
+ * @param {Number} windowId
+ * The target window id.
+ *
+ * @return {TaskIcon}
+ * The task that represents the target window.
+ */
+ function findTaskIcon(windowId)
+ {
+ var taskIcon;
+ for (var i = 0; i < taskIcons.length; i++)
+ {
+ var taskIcon = taskIcons[i];
+ if (taskIcon.win.id === windowId)
+ {
+ break;
+ }
+ }
+ return taskIcon;
+ };
+
+ /**
+ * Collapses the given window. Sets the corresponding task icon to be inactive.
+ *
+ * @param {Number} windowId
+ * The target window id.
+ */
+ this.iconify = function(windowId)
+ {
+ var taskIcon = findTaskIcon(windowId);
+ if (taskIcon === undefined)
+ {
+ return;
+ }
+ taskIcon.setActive(false);
+ taskIcon.draw();
+ };
+
+ /**
+ * Restores the window. Sets the corresponding task icon to be active.
+ *
+ * @param {Number} windowId
+ * The target window id.
+ */
+ this.deiconify = function(windowId)
+ {
+ var taskIcon = findTaskIcon(windowId);
+ if (taskIcon === undefined)
+ {
+ return;
+ }
+ taskIcon.setActive(true);
+ taskIcon.draw();
+ };
+
+ function startDragging(event) {
+ event.dataTransfer.setData('text/plain',null);
+ dragged = event.target;
+ event.target.style.opacity = DRAGGED_OPACITY;
+ }
+
+ function dragEnded(event) {
+ event.target.style.opacity = 1;
+ }
+
+ function drag( event ) {
+ }
+
+ /* events fired on the drop targets */
+ document.addEventListener("dragover",
+ function( event )
+ {
+ event.preventDefault();
+ }, false);
+
+ document.addEventListener("dragenter",
+ function( event )
+ {
+ var cls = event.target.className;
+ if ( cls.indexOf(DOCK_CLASS_NAME) >= 0) {
+ event.target.style["background"] = getTransparentColor(background, 0.5);;
+ }
+ }, false);
+
+ document.addEventListener("dragleave",
+ function( event )
+ {
+ var cls = event.target.className;
+ if ( cls.indexOf(DOCK_CLASS_NAME) >= 0 ) {
+ event.target.style["background"] = getTransparentColor(background, 0.0);;
+ }
+ }, false);
+
+ document.addEventListener("drop",
+ function( event )
+ {
+ var cls = event.target.className;
+ if ( cls.indexOf(DOCK_CLASS_NAME) >= 0) {
+ var parent = dragged.parentNode;
+ parent.removeChild(dragged);
+ try {
+ event.target.appendChild(dragged);
+ parent.style["background"] = getTransparentColor(background, 0.0);
+ }
+ catch(e)
+ {
+ parent.addChild(dragged);
+ }
+ doLayout(peer.offsetWidth, peer.offsetHeight);
+ }
+ event.preventDefault();
+ }, false);
+
+ /**
+ * Returns rgba(r,g,b,a) string representation for the target color
+ * with the target transparency.
+ *
+ * @param {Number[]} c
+ * Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
+ * @param {Number} transparency
+ * The transparency from 0.0 to 1.0.
+ *
+ * @return {String}
+ * The 'rgba(r,g,b,a)' string representation.
+ */
+ function getTransparentColor(c, transparency)
+ {
+ var parameters = [];
+ Array.prototype.push.apply(parameters, c);
+ parameters.push(transparency);
+ return "rgba(" + parameters.join() + ")";
+ }
+
+ /**
+ * Creates the task icon widget that represents the target window on the task bar.
+ *
+ * @param {Window} win
+ * The window to be represented by a task in the task bar.
+ * @param {Array} iconData
+ * It is the binary icon to set. The pixels array with 4-bytes per a pixel that
+ * are red, green, blue and alpha bytes.
+ * @param {Number} w
+ * The task icon widget width in pixels.
+ * @param {Number} h
+ * The task icon widget height in pixels.
+ * @param {Number[]} c
+ * The task icon widget color. Array of 3 integer values between 0
+ * and 255 inclusive, representing an RGB color.
+ */
+ function TaskIcon(win, iconData, w, h, c)
+ {
+ this.win = win;
+ this.iconData = iconData;
+ this.width = w;
+ this.height = h;
+ this.color = c;
+ var that = this;
+ var active = false;
+ this.x = 0;
+ this.y = 0;
+
+ this.setLocation = setLocation;
+ this.setActive = setActive;
+ this.isActive = isActive;
+ this.draw = draw;
+
+ /**
+ * Sets the widget location.
+ */
+ function setLocation(x, y)
+ {
+ this.x = x;
+ this.y = y;
+ };
+
+ /**
+ * Sets an active state.
+ */
+ function setActive(value)
+ {
+ active = value;
+ };
+
+ /**
+ * Is active?
+ */
+ function isActive()
+ {
+ return active;
+ };
+
+ /**
+ * Draw the widget on the task bar canvas.
+ */
+ function draw()
+ {
+ var c;
+ if (active)
+ {
+ c = canvasRenderer.lightenColor(that.color);
+ }
+ else
+ {
+ c = that.color;
+ }
+ canvasRenderer.draw3DRect(ctx, that.x, that.y, that.width, that.height, c, true, !active);
+ if (that.iconData)
+ {
+ var iconWidth = that.win.iconWidth;
+ var iconHeight = that.win.iconHeight;
+ canvasRenderer.drawImage(ctx, that.x, that.y + (that.height - iconHeight) / 2,
+ iconWidth, iconHeight, that.iconData, 0);
+ }
+ };
+
+ /**
+ * Tests the mouse pointer inside the widgets bounds.
+ */
+ function testMousePointerInside(event)
+ {
+ var rect = peer.getBoundingClientRect();
+ var x_rel = event.clientX - rect.left;
+ var y_rel = event.clientY - rect.top;
+ return isInOrder(that.x, x_rel, that.x + that.width)
+ && isInOrder(that.y, y_rel, that.y + that.height);
+ };
+
+ /**
+ * Returns true iff a <= b <= c
+ */
+ function isInOrder(a, b, c)
+ {
+ if (a > b || b > c)
+ {
+ return false;
+ }
+ return true;
+ };
+
+ /**
+ * Adds the "on click" widget action. If window is inactive, sets the active state and
+ * sends the request to server in order to change the window state.
+ */
+ peer.addEventListener("click", function(event) {
+ if (testMousePointerInside(event) && !that.isActive())
+ {
+ that.setActive(true);
+ if (taskIconOnClickCallback)
+ {
+ taskIconOnClickCallback(that.win.id);
+ }
+ that.draw();
+ }
+ });
+ peer.addEventListener("mouseenter", function(event) {
+ if (testMousePointerInside(event))
+ {
+ peer.title = (that.win.title !== null && that.win.title !== udefined)
+ ? that.win.title : " ";
+ }
+ });
+// peer.addEventListener("mouseover", function(event) {
+// if (testMousePointerInside(event))
+// {
+// peer.title = that.win.title;
+// }
+// });
+ peer.addEventListener("mouseleave", function(event) {
+ if (testMousePointerInside(event))
+ {
+ peer.title = TASK_BAR_TITLE;
+ }
+ });
+ }
+ }
+}
+
+