This commit is contained in:
adrianvic 2023-12-21 14:33:34 -03:00
commit 59426d62fb
102 changed files with 42796 additions and 0 deletions

2
AppxBlockMap.xml Normal file

File diff suppressed because one or more lines are too long

26
AppxManifest.xml Normal file
View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest">
<Identity Name="Microsoft.PaintPlay" Version="1.0.0.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" ProcessorArchitecture="neutral" />
<Properties>
<!-- TODO: Windows 8 Apps bug 92 Add localization support -->
<DisplayName>PaintPlay</DisplayName>
<Description>PaintPlay</Description>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Res\storeLogo.png</Logo>
</Properties>
<Prerequisites>
<OSMinVersion>6.2</OSMinVersion>
<OSMaxVersionTested>6.2</OSMaxVersionTested>
</Prerequisites>
<Resources>
<Resource Language="en-US" />
</Resources>
<Applications>
<Application Id="Microsoft.PaintPlay" StartPage="HTML\Main.html">
<VisualElements DisplayName="PaintPlay" Logo="Res\logo.png" SmallLogo="Res\smallLogo.png" Description="Paint" ForegroundText="light" BackgroundColor="#FFFFFF" InitialRotationPreference="landscapeAndFlipped">
<DefaultTile WideLogo="Res\wideLogo.png" />
<SplashScreen Image="Res\splashScreen.png" BackgroundColor="#414141" />
</VisualElements>
</Application>
</Applications>
</Package>

BIN
AppxSignature.p7x Normal file

Binary file not shown.

5
CSS/Main.css Normal file
View file

@ -0,0 +1,5 @@
.main-content
{
height: 100%;
width: 100%;
}

18
CSS/PaintView.css Normal file
View file

@ -0,0 +1,18 @@
.paintviewGrid
{
display: -ms-grid;
-ms-grid-columns: 1fr;
-ms-grid-rows: 1fr;
height: 100%;
width: 100%;
}
.canvas
{
-ms-grid-column: 1;
-ms-grid-row: 1;
border: solid 20px #000000;
overflow: hidden;
}

View file

@ -0,0 +1,17 @@
.Canvas
{
margin-left: 100px;
margin-top: 100px;
}
#paintCanvas
{
background: rgb(242, 242, 222);
height: 100%;
width: 100%;
}
.pannable
{
overflow-x: scroll !important;
}

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<title>Canvas</title>
<link rel="stylesheet" href="Canvas.css" />
<script src="/WinJS/js/base.js"></script>
<script src="/JS/Global.js"></script>
<!-- canvas control files -->
<script src="/Controls/Paint/Math/Point.js"></script>
<script src="/Controls/Paint/Math/Vector.js"></script>
<script src="/Controls/Paint/Graphics/Canvas.js"></script>
<script src="/Controls/Paint/Graphics/Color.js"></script>
<script src="/Controls/Paint/Graphics/Path.js"></script>
<script src="/Controls/Paint/Graphics/Texture.js"></script>
<script src="/Controls/Paint/Tools/Crayon.js"></script>
<script src="/Controls/Paint/Tools/Marker.js"></script>
<script src="/Controls/Paint/Tools/Neon.js"></script>
<script src="/Controls/Paint/Tools/Eraser.js"></script>
<script src="/Controls/Paint/Tools/Bristle.js"></script>
<script src="/Controls/Paint/Tools/Brush.js"></script>
<script src="/Controls/Paint/Tools/Pipe.js"></script>
<script src="/Controls/Paint/Painter.js"></script>
<script src="ToolCards.js"></script>
<script src="Canvas.js"></script>
</head>
<body>
<canvas id="paintCanvas"></canvas>
</body>
</html>

493
Controls/Canvas/Canvas.js Normal file
View file

@ -0,0 +1,493 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
/// <reference path="Paint.js" />
/// <reference path="Painter.js" />
(function (AppNS) {
"use strict";
var WinUtils = WinJS.Utilities;
// Enum of pointer event information
var pointerInfo = {
// Pointer type
touch: 2,
pen: 3,
mouse: 4,
// Button pressed
noButtons: 0,
leftButton: 1,
rightButton: 2,
middleButton: 4,
};
var layoutState = Windows.UI.ViewManagement.ApplicationLayoutState;
function fragmentLoad(root, state) {
// Set up canvas dimensions
var canvas = root.querySelector("#paintCanvas");
canvas.height = state.canvasHeight - state.canvasBorder;
canvas.style.height = canvas.height + "px";
canvas.width = state.canvasWidth - state.canvasBorder * 2;
canvas.style.width = canvas.width + "px";
var eventHost = document.createElement("div");
var pointerDown = [];
var Painter = AppNS.Painter;
var mainPainter = new Painter.Painter(canvas);
var canvasBlocked = false;
var classes = { pannable: "pannable" };
var undoBlobPrefix = "undoBlob-";
// Initialize canvas with saved blob
if (state.canvasBlobName) {
Windows.Storage.ApplicationData.current.localFolder.getFileAsync(state.canvasBlobName)
.then(function (file) {
var url = URL.createObjectURL(file, false);
var img = document.createElement("img");
img.addEventListener("load", function () {
canvas.getContext("2d").drawImage(img, 0, 0);
});
img.src = url;
});
}
// Initialize undo stack
if (state.undoBlobNames) {
for (var i = 0, len = state.undoBlobNames.length; i < len; i++) {
var blobName = state.undoBlobNames[i];
Windows.Storage.ApplicationData.current.localFolder.getFileAsync(blobName)
.then(function (file) {
var url = URL.createObjectURL(file, false);
var img = document.createElement("img");
var tempCanvas = document.createElement("canvas");
tempCanvas.height = canvas.height;
tempCanvas.width = canvas.width;
img.addEventListener("load", function () {
var context = tempCanvas.getContext("2d");
context.drawImage(img, 0, 0);
mainPainter.canvas.history.push(context.getImageData(0, 0, mainPainter.canvas.domCanvas.offsetWidth, mainPainter.canvas.domCanvas.offsetHeight));
mainPainter.canvas.maxIndex++;
mainPainter.canvas.index++;
});
img.src = url;
});
}
}
AppNS.CanvasManager.loadAllTools(mainPainter);
// Initialize canvas
var toolName = state.toolName || AppNS.CanvasManager.ToolNames.Marker;
var toolCard = AppNS.CanvasManager.ToolCards[toolName];
mainPainter.toolName = toolName;
mainPainter.tool.width = state.width || toolCard.supportedSizes[toolCard.defaultSizeIndex];
if (state.toolOptionValueIndex || state.toolOptionValueIndex === 0) {
mainPainter.tool[toolCard.optionKey] = toolCard.optionValues[state.toolOptionValueIndex];
}
function downListener(event) {
if (!pointerDown[event.pointerId] && (leftClick(event) || notMouse(event)) && !canvasBlocked) {
mainPainter.drawStart(dataFromEvent(event));
pointerDown[event.pointerId] = true;
}
}
function moveListener(event) {
if (pointerDown[event.pointerId] && !canvasBlocked) {
mainPainter.draw(dataFromEvent(event));
}
}
function upListener(event) {
if (pointerDown[event.pointerId] && !canvasBlocked) {
mainPainter.drawStop(dataFromEvent(event));
AppNS.ToolbarManager.showUndo();
pointerDown[event.pointerId] = false;
}
}
function dataFromEvent(event) {
var data = {};
data.x = event.offsetX;
data.y = event.offsetY;
data.id = event.pointerId;
return data;
}
function notMouse(event) {
return (event.pointerType !== pointerInfo.mouse);
}
function leftClick(event) {
return (event.pointerType === pointerInfo.mouse && event.button === pointerInfo.leftButton);
}
// Event listeners for the canvas
canvas.addEventListener("MSPointerDown", downListener);
canvas.addEventListener("MSPointerOver", downListener);
canvas.addEventListener("MSPointerMove", moveListener);
canvas.addEventListener("MSPointerOut", upListener);
canvas.addEventListener("MSPointerUp", upListener);
WinJS.Namespace.defineWithParent(AppNS, "CanvasManager", {
color: {
get: function () {
/// <summary>
/// Gets the current color string value
/// </summary>
return mainPainter.color.toString();
},
set: function (newColor) {
/// <summary>
/// Sets the current color string value
/// </summary>
/// <param name='newColor'>
/// The string value for the color
/// </param>
var color = new Painter.Graphics.Color();
color.fromString(newColor);
mainPainter.color = color;
}
},
clearCanvas: function () {
/// <summary>
/// Resets the canvas to a blank state
/// </summary>
mainPainter.canvas.clear();
AppNS.ToolbarManager.showUndo();
},
undoCanvas: function () {
/// <summary>
/// Undoes the last stroke
/// </summary>
if (mainPainter.canvas.canUndo()) {
mainPainter.canvas.undo();
}
AppNS.ToolbarManager.hideUndo();
},
canUndo: function () {
/// <summary>
/// Returns whether or not another undo action can be executed
/// </summary>
/// <return>
/// Boolean representing whether or not another undo action can be executed
/// </return>
return mainPainter.canvas.canUndo();
},
redoCanvas: function () {
/// <summary>
/// Redoes the last stroke
/// </summary>
if (mainPainter.canvas.canRedo()) {
mainPainter.canvas.redo();
}
AppNS.ToolbarManager.showUndo();
},
toolWidth: {
get: function () {
/// <summary>
/// Sets current tool
/// </summary>
/// <param name='newBrush'>
/// The string value for the tool
/// </param>
return mainPainter.tool.width;
},
set: function (newWidth) {
/// <summary>
/// Sets the current tool width
/// </summary>
/// <param name='newWidth'>
/// The width value in pixels
/// </param>
mainPainter.tool.width = newWidth;
}
},
getToolProperty: function (optionKey) {
/// <summary>
/// Gets the tool specific property
/// </summary>
/// <param name='optionKey'>
/// The property key to be returned
/// </param>
/// <return>
/// The value currently assigned to the property. Can be any type.
/// </return>
return mainPainter.tool[optionKey];
},
setToolProperty: function (optionKey, optionValue) {
/// <summary>
/// Sets the tool specific property
/// </summary>
/// <param name='optionKey'>
/// The property key to be set
/// </param>
/// <param name='optionValue'>
/// The value to be set
/// </param>
mainPainter.tool[optionKey] = optionValue;
},
tool: {
get: function () {
/// <summary>
/// Returns the current tool
/// </summary>
/// <returns>
/// Tool
/// </returns>
return mainPainter.tool;
},
set: function (newBrush) {
/// <summary>
/// Sets current tool
/// </summary>
/// <param name='newBrush'>
/// The string value for the tool
/// </param>
mainPainter.tool = newBrush;
}
},
canvasBitmap: {
get: function () {
/// <summary>
/// Returns the current image data on the canvas
/// </summary>
/// <returns>
/// ImageData
/// </returns>
return mainPainter.canvas.context.getImageData(0, 0, mainPainter.canvas.domCanvas.offsetWidth, mainPainter.canvas.domCanvas.offsetHeight);
},
set: function (imageData) {
/// <summary>
/// Sets the image data displayed on the canvas
/// </summary>
/// <param name='imageData'>
/// ImageData object to be displayed
/// </param>
mainPainter.canvas.context.putImageData(imageData, 0, 0);
}
},
getScaledCanvasBlob: function (height, width) {
/// <summary>
/// Returns the a scaled canvas blob
/// </summary>
/// <param name='height'>
/// Height of the new canvas blob
/// </param>
/// <param name='width'>
/// Width of the new canvas blob
/// </param>
/// <returns>
/// Blob
/// </returns>
var newCanvas = document.createElement("canvas");
var context = newCanvas.getContext("2d");
newCanvas.width = width;
newCanvas.height = height;
context.drawImage(mainPainter.canvas.domCanvas, 0, 0, width, height);
return newCanvas.msToBlob();
},
canvasBlob: {
get: function () {
/// <summary>
/// Returns the current image data on the canvas as a blob
/// </summary>
/// <returns>
/// Blob
/// </returns>
return mainPainter.canvas.domCanvas.msToBlob();
}
},
undoBlobNames: {
get: function () {
/// <summary>
/// Returns an array with the names identifying the undo blobs indexed chronologically
/// </summary>
/// <returns>
/// Array of strings
/// </returns>
var blobNames = [];
for (var i = mainPainter.canvas.minIndex; i < mainPainter.canvas.index; i++) {
blobNames.push(undoBlobPrefix + (i - mainPainter.canvas.minIndex));
}
return blobNames;
}
},
undoBlobs: {
get: function () {
/// <summary>
/// Returns an object with the undo stack blobs
/// </summary>
/// <returns>
/// Object in which keys are the blob names strings and values are blobs
/// </returns>
var blobs = {};
for (var i = mainPainter.canvas.minIndex; i < mainPainter.canvas.index; i++) {
var tempCanvas = document.createElement("canvas");
tempCanvas.height = mainPainter.canvas.domCanvas.height;
tempCanvas.width = mainPainter.canvas.domCanvas.width;
tempCanvas.getContext("2d").putImageData(mainPainter.canvas.history[i], 0, 0);
blobs[undoBlobPrefix + (i - mainPainter.canvas.minIndex)] = tempCanvas.msToBlob();
}
return blobs;
}
},
// Saves the current canvas to a file in the pictures library.
// File name will be 'Painting <date>'.
saveCanvas: function () {
var filename = "Painting.png";
AppNS.Utils.writeBlobToPicturesFolderAsync(this.canvasBlob, filename);
},
canvasBlocked: {
set: function (cBlocked) {
/// <summary>
/// Sets whether the drawing on canvas is disabled or enabled
/// </summary>
/// <param name='cBlocked'>
/// Boolean representing wether or not the canvas is blocked
/// </param>
if (typeof cBlocked === "boolean") {
canvasBlocked = cBlocked;
}
},
get: function () {
/// <summary>
/// Returns whether the drawing on canvas is disabled or enabled
/// </summary>
/// <returns>
/// Boolean
/// </returns>
return canvasBlocked;
}
},
canvasPannable: {
get: function () {
/// <summary>
/// Returns whether or not the canvas is pannable
/// </summary>
/// <returns>
/// Boolean
/// </returns>
return root.className.indexOf(classes.pannable) !== -1;
},
set: function (isPannable) {
/// <summary>
/// Enables or disables panning on the canvas
/// </summary>
/// <param name='isPannable'>
/// Boolean representing wether or not the canvas is pannable
/// </param>
if (isPannable) {
WinUtils.addClass(root, classes.pannable);
} else {
WinUtils.removeClass(root, classes.pannable);
}
}
},
changeLayout: function (newLayout) {
/// <summary>
/// Changes the canvas layout to a specified layout such as snap or fill
/// </summary>
// Reposition scroll for snap and fill view
if (newLayout !== layoutState.fullScreen) {
root.scrollLeft = (canvas.width - window.innerWidth) / 2;
}
},
addEventListener: function (eventName, eventCallback, capture) {
/// <summary>
/// Registers an event handler for the specified event type
/// </summary>
/// <param name='eventName'>
/// The type of event type to register
/// </param>
/// <param name='eventCallback'>
/// The event handler function to associate with the event
/// </param>
/// <param name='capture'>
/// A Boolean value that specifies the event phase to add the event handler for:
/// true
/// Register the event handler for the capturing phase
/// false
/// Register the event handler for the bubbling phase
/// </param>
/// <returns>
/// None
/// </returns>
eventHost.addEventListener(eventName, eventCallback, capture);
},
removeEventListener: function (eventName, eventCallback, capture) {
/// <summary>
/// Removes an event handler that the addEventListener method registered
/// </summary>
/// <param name='eventName'>
/// The event type that the event handler is registered for
/// </param>
/// <param name='eventCallback'>
/// The event handler function to remove
/// </param>
/// <param name='capture'>
/// A Boolean value that specifies the event phase to add the event handler for:
/// true
/// Remove the capturing phase event handler
/// false
/// Remove the bubbling phase event handler
/// </param>
/// <returns>
/// None
/// </returns>
eventHost.removeEventListener(eventName, eventCallback, capture);
},
// Raises an event to listeners
_fireEvent: function (eventName, payload) {
if (document.createEvent) {
var eventObject = document.createEvent("Event");
eventObject.initEvent(eventName, true, false);
if (payload) {
eventObject.payload = payload;
}
eventHost.dispatchEvent(eventObject);
}
}
});
};
WinJS.Namespace.defineWithParent(AppNS, "CanvasManager", {
fragmentLoad: fragmentLoad,
});
})(Microsoft.Paint);

View file

@ -0,0 +1,107 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
var supportedSizes = [60, 40, 30, 20, 10, 3];
// Create texture image for crayon
var textureImage = document.createElement("img");
textureImage.src = "../Controls/Paint/Res/crayon_texture.png";
WinJS.Namespace.defineWithParent(AppNS, "CanvasManager", {
ToolNames: {
Eraser: "eraser",
Marker: "marker",
Brush: "brush",
Neon: "neon",
Pipe: "pipe",
Crayon: "crayon"
},
ToolCards: {
marker: {
toolClass: AppNS.Painter.Tools.Marker,
label: "Marker", // TODO: Win8Apps WORK 92: Add localization support
optionKey: "opacity",
optionValues: [1, 0.85, 0.7, 0.5, 0.35, 0.2],
defaultOptionIndex: 1,
defaultSizeIndex: 4,
optionLabel: "Transparency", // TODO: Win8Apps WORK 92: Add localization support
supportedSizes: supportedSizes
},
brush: {
toolClass: AppNS.Painter.Tools.Brush,
label: "Brush", // TODO: Win8Apps WORK 92: Add localization support
optionKey: "fade",
optionValues: [0, 1000, 700, 400, 200, 100],
defaultOptionIndex: 0,
defaultSizeIndex: 3,
optionLabel: "Fade", // TODO: Win8Apps WORK 92: Add localization support
supportedSizes: supportedSizes
},
neon: {
toolClass: AppNS.Painter.Tools.Neon,
label: "Neon", // TODO: Win8Apps WORK 92: Add localization support
optionKey: "glow",
optionValues: [70, 55, 40, 25, 10, 0],
defaultOptionIndex: 4,
defaultSizeIndex: 3,
optionLabel: "Glow", // TODO: Win8Apps WORK 92: Add localization support
supportedSizes: supportedSizes
},
pipe: {
toolClass: AppNS.Painter.Tools.Pipe,
label: "3D", // TODO: Win8Apps WORK 92: Add localization support
optionKey: "height",
optionValues: [6, 5, 4, 3, 2, 1],
defaultOptionIndex: 4,
defaultSizeIndex: 3,
optionLabel: "Depth", // TODO: Win8Apps WORK 92: Add localization support
supportedSizes: supportedSizes
},
crayon: {
toolClass: AppNS.Painter.Tools.Crayon,
label: "Crayon", // TODO: Win8Apps WORK 92: Add localization support
optionKey: "density",
optionValues: [2, 1.75, 1.5, 1.25, 1.0, .75],
defaultOptionIndex: 1,
defaultSizeIndex: 4,
optionLabel: "Density", // TODO: Win8Apps WORK 92: Add localization support
supportedSizes: supportedSizes,
textureImage: textureImage
},
eraser: {
toolClass: AppNS.Painter.Tools.Eraser,
label: "Eraser", // TODO: Win8Apps WORK 92: Add localization support
supportedSizes: supportedSizes,
defaultSizeIndex: 4
}
},
// Loads all available tools into the given painter
loadAllTools: function (painter) {
var cards = AppNS.CanvasManager.ToolCards;
var names = AppNS.CanvasManager.ToolNames;
for (var name in cards) {
var card = cards[name];
var tool = new card.toolClass();
tool.width = card.supportedSizes[card.defaultSizeIndex];
if (name !== names.Eraser) {
tool[card.optionKey] = card.optionValues[card.defaultOptionIndex];
}
painter.loadTool(tool, name);
if (name === names.Crayon) {
// Create texture image for crayon
var textureImage = new Image(40, 40);
var crayonTool = tool;
textureImage.addEventListener("load", function () {
crayonTool.setTexture(textureImage);
});
textureImage.src = "../Controls/Paint/Res/crayon_texture.png";
}
}
}
});
})(Microsoft.Paint);

View file

@ -0,0 +1,28 @@
.colorpicker
{
display: inline;
position: relative;
}
.colorpicker-color
{
padding: 0;
position: absolute;
z-index: 1;
/*
-ms-transition-property: width, height, left, bottom;
-ms-transition-duration: 0.1s;
*/
}
.colorpicker-selectedColor
{
box-shadow: 0px 0px 0px 1px rgb(64, 64, 64), 0px 0px 0px 1px white inset;
z-index: 999;
}
.colorpicker-animatedColor
{
-ms-transition-property: width, height, left, bottom;
-ms-transition-duration: 0.1s;
}

View file

@ -0,0 +1,349 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (BaseNS) {
var WinUtils = WinJS.Utilities;
WinJS.Namespace.defineWithParent(BaseNS, "Paint", {
// ColorPicker class
ColorPicker: WinJS.Class.define(function (host, colors, options) {
/// <summary>
/// Initialize and render a ColorPicker
/// </summary>
/// <param name='host'>
/// DOM element that will host the color picker
/// </param>
/// <param name='colors'>
/// Array of css-style colors represented as strings
/// </param>
/// <param name='options' optional='true'>
/// Object of options
/// </param>
this._host = host;
this._colors = colors;
this._options = options || {};
this._colorDomElements = [];
this._colorBlockClassName = "colorpicker-color";
this._previousMouseMoveX = false;
// Set up options
this._options.height = this._options.height || 50;
this._options.width = this._options.width || 600;
this._options.separation = this._options.separation || 0;
this._options.selectedHeight = (this._options.selectedHeightGrowth * this._options.height) || this._options.height;
this._colorBlockWidth = this._options.width / this._colors.length;
this._options.selectedWidth = (this._options.selectedWidthGrowth * this._colorBlockWidth) || this._options.colorBlockWidth;
this._options.hoverWidth = (this._options.hoverWidthGrowth * this._colorBlockWidth) || this._options.colorBlockWidth;
this._options.hoverHeight = (this._options.hoverHeightGrowth * this._options.height) || this._options.height;
this._options.bottomPosition = this._options.bottomPosition || 0;
this._options.affectedNeighbors = this._options.affectedNeighbors || 0;
this._direction = { left: 0, right: 1 };
// Create container
this._colorPickerContainer = document.createElement("div");
this._colorPickerContainer.className = "colorpicker";
// Create color block for each color
for (var i = 0, len = this._colors.length; i < len; i++) {
var colorBlock = document.createElement("button");
colorBlock.className = this._colorBlockClassName;
colorBlock.style.height = this._options.height + "px";
colorBlock.style.width = this._colorBlockWidth + "px";
colorBlock.style.left = i * this._colorBlockWidth + "px";
colorBlock.style.bottom = this._options.bottomPosition + "px";
colorBlock.style.minWidth = colorBlock.style.width;
colorBlock.id = i;
if (i !== len - 1) {
colorBlock.style.marginRight = this._options.separation;
}
colorBlock.style.background = this._colors[i];
this._down = false;
var that = this;
// Set up color block event listeners
colorBlock.addEventListener("MSPointerDown", function (event) {
that._pointerDown = true;
if (that._currentSelection) {
that._unselectColorBlock(that._currentSelection);
}
that._expandColorBlock(event.currentTarget, false, true);
that._currentHover = event.currentTarget;
});
colorBlock.addEventListener("MSPointerUp", function (event) {
if (that._pointerDown) {
that._pointerDown = false;
that._unselectColorBlock(that._currentSelection);
that._contractColorBlock(that._currentHover, false, true);
that._selectColorBlock(that._currentHover);
that._currentSelection = that._currentHover;
that._currentHover = null;
that._colorSelected = true;
}
});
colorBlock.addEventListener("mouseover", function (event) {
that._unselectColorBlock(that._currentSelection);
that._selectColorBlock(event.currentTarget);
that._expandColorBlock(event.currentTarget, false, true);
that._currentHover = event.currentTarget;
});
colorBlock.addEventListener("mousemove", function (event) {
var currentId = parseInt(event.currentTarget.id);
if (that._currentHover) {
if (that._currentHover !== event.currentTarget) {
that._unselectColorBlock(that._currentSelection);
if (that._currentHover) {
that._contractColorBlock(that._currentHover, false, true);
}
that._expandColorBlock(event.currentTarget, false, true);
that._currentHover = event.currentTarget;
} else if ((event.offsetX > that._options.hoverWidth - (that._options.hoverWidth / 6) && currentId < that._colors.length - 1) &&
that._previousMouseMoveX && (that._previousMouseMoveX < event.offsetX)) {
that._contractColorBlock(that._currentHover, false, true);
that._expandColorBlock(that._colorDomElements[currentId + 1], false, true);
that._currentHover = that._colorDomElements[currentId + 1];
that._previousMouseMoveX = 0;
} else if ((event.offsetX < that._options.hoverWidth / 6 && currentId > 0) &&
that._previousMouseMoveX && (that._previousMouseMoveX > event.offsetX)) {
that._contractColorBlock(that._currentHover, false, true);
that._expandColorBlock(that._colorDomElements[currentId - 1], false, true);
that._currentHover = that._colorDomElements[currentId - 1];
that._previousMouseMoveX = 0;
} else {
that._previousMouseMoveX = event.offsetX;
}
}
});
colorBlock.addEventListener("MSTransitionEnd", function (event) {
if (parseInt(event.currentTarget.style.height) === that._options.height) { // If it is a contraction transition
if (!this._pointerDown && that._colorSelected) {
that._fireEvent("colorselected", { color: that._currentSelection.style.background, colorId: parseInt(that._currentSelection.id) });
that._colorSelected = false;
}
event.currentTarget.style.zIndex = 1;
}
WinUtils.removeClass(event.currentTarget, "colorpicker-animatedColor");
});
colorBlock.addEventListener("mouseout", function (event) {
if (event.relatedTarget.className.indexOf(that._colorBlockClassName) === -1) {
that._contractColorBlock(event.currentTarget, false, true);
if (that._currentHover) {
that._contractColorBlock(that._currentHover, false, true);
}
if (that._pointerDown) {
that._pointerDown = false;
that._unselectColorBlock(that._currentSelection);
that._unselectColorBlock(that._currentHover);
that._currentSelection = event.currentTarget;
that._fireEvent("colorselected", { color: that._currentSelection.style.background, colorId: parseInt(that._currentSelection.id) });
}
that._selectColorBlock(that._currentSelection);
that._currentHover = null;
}
});
this._colorPickerContainer.appendChild(colorBlock);
this._colorDomElements[i] = colorBlock;
}
host.appendChild(this._colorPickerContainer);
},
{
addEventListener: function (eventName, eventCallback, capture) {
/// <summary>
/// Registers an event handler for the specified event type
/// </summary>
/// <param name='eventName'>
/// The type of event type to register
/// </param>
/// <param name='eventCallback'>
/// The event handler function to associate with the event
/// </param>
/// <param name='capture'>
/// A Boolean value that specifies the event phase to add the event handler for:
/// true
/// Register the event handler for the capturing phase
/// false
/// Register the event handler for the bubbling phase
/// </param>
/// <returns>
/// None
/// </returns>
this._host.addEventListener(eventName, eventCallback, capture);
},
removeEventListener: function (eventName, eventCallback, capture) {
/// <summary>
/// Removes an event handler that the addEventListener method registered
/// </summary>
/// <param name='eventName'>
/// The event type that the event handler is registered for
/// </param>
/// <param name='eventCallback'>
/// The event handler function to remove
/// </param>
/// <param name='capture'>
/// A Boolean value that specifies the event phase to add the event handler for:
/// true
/// Remove the capturing phase event handler
/// false
/// Remove the bubbling phase event handler
/// </param>
/// <returns>
/// None
/// </returns>
this._host.removeEventListener(eventName, eventCallback, capture);
},
selectColor: function (color) {
this._currentSelection = this._colorDomElements[color];
this._selectColorBlock(this._currentSelection);
this._fireEvent("colorselected", { color: this._colorDomElements[color].style.background, colorId: color });
},
width: {
set: function (newWidth) {
this._colorBlockWidth = newWidth / this._colors.length;
for (var i = 0, len = this._colors.length; i < len; i++) {
var colorBlock = this._colorDomElements[i];
colorBlock.style.width = this._colorBlockWidth + "px";
colorBlock.style.left = i * this._colorBlockWidth + "px";
colorBlock.style.minWidth = colorBlock.style.width;
if (this._selectedColor) {
this._selectColorBlock(this._selectedColor);
}
}
}
},
// Raises an event to listeners
_fireEvent: function (eventName, payload) {
if (document.createEvent) {
var eventObject = document.createEvent("Event");
eventObject.initEvent(eventName, true, false);
if (payload) {
eventObject.payload = payload;
}
this._host.dispatchEvent(eventObject);
}
},
// Expands a specified color block element
_expandColorBlock: function (colorBlockElement, animated, animateNeighbors) {
var currentId = parseInt(colorBlockElement.id);
var newLeft = (currentId * this._colorBlockWidth) - (this._options.hoverWidth - this._colorBlockWidth) / 2;
if (animated) {
WinUtils.addClass(colorBlockElement, "colorpicker-animatedColor");
}
colorBlockElement.style.zIndex = 999;
colorBlockElement.style.width = this._options.hoverWidth + "px";
colorBlockElement.style.height = this._options.hoverHeight + "px";
colorBlockElement.style.bottom = this._options.bottomPosition - (this._options.hoverHeight - this._options.height) / 2 + "px";
colorBlockElement.style.left = newLeft + "px";
WinUtils.addClass(colorBlockElement, "colorpicker-selectedColor");
if (animated) {
WinUtils.removeClass(colorBlockElement, "colorpicker-animatedColor");
}
for (var i = 0, widthCount = 0; i < this._options.affectedNeighbors; i++) {
var newHeight = this._options.hoverHeight - (((this._options.hoverHeight - this._options.height) / (this._options.affectedNeighbors + 1)) * (i + 1));
var newWidth = this._options.hoverWidth - (((this._options.hoverWidth - this._colorBlockWidth) / (this._options.affectedNeighbors + 1)) * (i + 1));
if (this._colorDomElements[currentId + i + 1]) {
this._colorDomElements[currentId + i + 1].zIndex = 1;
this._colorDomElements[currentId + i + 1].style.height = newHeight + "px";
this._colorDomElements[currentId + i + 1].style.bottom = this._options.bottomPosition - (newHeight - this._options.height) / 2 + "px";
if (animateNeighbors && this._colorDomElements[currentId + i + 1] !== this._lastExpansion) {
WinUtils.addClass(this._colorDomElements[currentId + i + 1], "colorpicker-animatedColor");
}
}
if (this._colorDomElements[currentId - i - 1]) {
this._colorDomElements[currentId - i - 1].style.height = newHeight + "px";
this._colorDomElements[currentId - i - 1].style.bottom = this._options.bottomPosition - (newHeight - this._options.height) / 2 + "px";
if (animateNeighbors && this._colorDomElements[currentId - i - 1] !== this._lastExpansion) {
WinUtils.addClass(this._colorDomElements[currentId - i - 1], "colorpicker-animatedColor");
}
}
widthCount += newWidth;
}
},
// Contracts a specified color block element
_contractColorBlock: function (colorBlockElement, animated, animateNeighbors) {
var currentId = parseInt(colorBlockElement.id);
if (animated) {
WinUtils.addClass(colorBlockElement, "colorpicker-animatedColor");
}
colorBlockElement.style.width = this._colorBlockWidth + "px";
colorBlockElement.style.height = this._options.height + "px";
colorBlockElement.style.bottom = this._options.bottomPosition + "px";
colorBlockElement.style.left = (currentId * this._colorBlockWidth) + "px";
WinUtils.removeClass(colorBlockElement, "colorpicker-selectedColor");
if (animated) {
WinUtils.removeClass(colorBlockElement, "colorpicker-animatedColor");
}
for (var i = 0; i < this._options.affectedNeighbors; i++) {
if (this._colorDomElements[currentId + i + 1]) {
if (animateNeighbors) {
WinUtils.addClass(this._colorDomElements[currentId + i + 1], "colorpicker-animatedColor");
}
this._colorDomElements[currentId + i + 1].style.height = this._options.height + "px";
this._colorDomElements[currentId + i + 1].style.bottom = this._options.bottomPosition + "px";
}
if (this._colorDomElements[currentId - i - 1]) {
if (animateNeighbors) {
WinUtils.addClass(this._colorDomElements[currentId - i - 1], "colorpicker-animatedColor");
}
this._colorDomElements[currentId - i - 1].style.height = this._options.height + "px";
this._colorDomElements[currentId - i - 1].style.bottom = this._options.bottomPosition + "px";
}
}
if (!animated) {
colorBlockElement.style.zIndex = 1;
}
this._lastExpansion = colorBlockElement;
},
// Applies selection style to a specified color block
_selectColorBlock: function (colorBlockElement) {
var currentId = parseInt(colorBlockElement.id);
WinUtils.addClass(colorBlockElement, "colorpicker-selectedColor");
colorBlockElement.style.height = this._options.selectedHeight + "px";
colorBlockElement.style.width = this._options.selectedWidth + "px";
colorBlockElement.style.bottom = this._options.bottomPosition - (this._options.selectedHeight - this._options.height) / 2 + "px";
colorBlockElement.style.left = (currentId * this._colorBlockWidth) - (this._options.selectedWidth - this._colorBlockWidth) / 2 + "px";
colorBlockElement.style.zIndex = 999;
},
// Applies selection style to a specified color block
_unselectColorBlock: function (colorBlockElement) {
var currentId = parseInt(colorBlockElement.id);
WinUtils.removeClass(colorBlockElement, "colorpicker-selectedColor");
colorBlockElement.style.height = this._options.height + "px";
colorBlockElement.style.width = this._colorBlockWidth + "px";
colorBlockElement.style.bottom = this._options.bottomPosition + "px";
colorBlockElement.style.left = (currentId * this._colorBlockWidth) + "px";
colorBlockElement.style.zIndex = 1;
}
})
});
})(Microsoft);

View file

@ -0,0 +1,104 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
var Canvas = WinJS.Class.define(
// Constructor
function (domCanvas) {
this.domCanvas = domCanvas;
this.context = domCanvas.getContext("2d");
this.depth = 10;
this.history = [];
this.index = 0;
this.minIndex = 0;
this.maxIndex = 0;
this.history[this.index] = this.context.getImageData(0, 0, this.domCanvas.width, this.domCanvas.height);
},
// Variables and Methods
{
// Returns the color of the pixel at the given position
getColorAt: function (color, x, y) {
var imgData = this.context.getImageData(x, y, 1, 1);
color.fromData(imgData.data);
},
// Draws a circle using the current fill style at the given position with
// the given radius.
drawCircle: function (x, y, r) {
this.context.beginPath();
this.context.arc(x, y, r, 0, Math.PI * 2, true);
this.context.closePath();
this.context.fill();
},
// Saves the current state of the canvas, deleting all previously undone (future or forward) state.
saveState: function () {
this.index++;
this.maxIndex = this.index;
if (this.maxIndex - this.minIndex > this.depth) {
this.history[this.minIndex] = null;
this.minIndex = this.maxIndex - this.depth;
}
this.history[this.index] = this.context.getImageData(0, 0, this.domCanvas.width, this.domCanvas.height);
},
// Loads the state stored at the given index into the canvas
loadState: function (i) {
if (i >= this.minIndex && i <= this.maxIndex) {
this.index = i;
this.context.putImageData(this.history[this.index], 0, 0);
} else {
throw new Error("PaintPlay - Error: Index out of bounds");
}
},
// Returns true if able to undo (still some past actions)
canUndo: function () {
return this.index > this.minIndex;
},
// Returns true if able to redo (still some future actions)
canRedo: function () {
return this.index < this.maxIndex;
},
// Undoes the last action (goes back one step in state history)
undo: function () {
if (this.canUndo()) {
this.loadState(this.index - 1);
}
},
// Redoes the next action (goes forward one step in state history)
redo: function () {
if (this.canRedo()) {
this.loadState(this.index + 1);
}
},
// Clears the canvas.
clear: function () {
this.context.clearRect(0, 0, this.domCanvas.width, this.domCanvas.height);
this.saveState();
},
// Returns an image object containing the current state of the canvas.
getImage: function () {
var img = new Image();
var imgSrc = this.domCanvas.toDataURL("image/png");
img.src = imgSrc;
return img;
},
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Graphics", {
Canvas: Canvas
});
})(Microsoft.Paint);

View file

@ -0,0 +1,146 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Color class represents a color in RGBA format.
var Color = WinJS.Class.define(
// Constructor
function (r, g, b, a) {
this.red = this.clip(r) || 0; // Red value (0-255)
this.green = this.clip(g) || 0; // Green value (0-255)
this.blue = this.clip(b) || 0; // Blue value (0-255)
this.alpha = this.clipAlpha(a) || 0; // Alpha value (0.0-1.0)
this.blendAmount = 0.8; // The speed of the Blending algorithm
},
// Variables and Functions
{
// Clips the value to between 255 and 0
clip: function (value) {
value = Math.round(value);
if (value > 255) {
return 255;
} else if (value < 0) {
return 0;
} else {
return value;
}
},
// Clips the alpha value to between 0 and 1.0
clipAlpha: function (alpha) {
if (alpha > 1.0) {
return this.clip(alpha) / 255;
} else if (alpha < 0.0 || isNaN(alpha)) {
return 0.0;
} else {
return alpha;
}
},
// Scales this color by a constant
scale: function (constant) {
this.red = this.clip(Math.round(this.red * constant));
this.green = this.clip(Math.round(this.green * constant));
this.blue = this.clip(Math.round(this.blue * constant));
},
// Sets this color to the given rgba values
fromRGBA: function (r, g, b, a) {
this.red = this.clip(r);
this.green = this.clip(g);
this.blue = this.clip(b);
this.alpha = this.clipAlpha(a);
},
// Sets this color to the pixel array info
fromData: function (data) {
this.fromRGBA(data[0], data[1], data[2], data[3]);
},
// Sets this color to the given color
fromColor: function (color) {
this.fromRGBA(color.red, color.green, color.blue, color.alpha);
},
/// <summary>Sets this color to be the color described by the formatted string.</summary>
/// <param name="str" type="String">
/// Str is a formatted string representation of a color. It must be one of the following formats:
/// rgba: "rgba({r}, {g}, {b}, {a})"
/// rgb (alpha auto set to 1.0): "rgb({r}, {g}, {b})"
/// Hex (alpha auto set to 1.0): "#{rr}{gg}{bb}"
/// </param>
fromString: function (str) {
if (str.indexOf("rgba") === 0) {
var strData = str.slice(5, -1);
var data = strData.split(",");
this.red = this.clip(parseInt(data[0]));
this.green = this.clip(parseInt(data[1]));
this.blue = this.clip(parseInt(data[2]));
this.alpha = this.clipAlpha(parseFloat(data[3]));
} else if (str.indexOf("rgb") === 0) {
var strData = str.slice(4, -1);
var data = strData.split(",");
this.red = this.clip(parseInt(data[0]));
this.green = this.clip(parseInt(data[1]));
this.blue = this.clip(parseInt(data[2]));
this.alpha = 1.0;
} else if (str.indexOf("#") === 0) {
this.red = this.clip(parseInt(str.slice(1, 3), 16));
this.green = this.clip(parseInt(str.slice(3, 5), 16));
this.blue = this.clip(parseInt(str.slice(5, 7), 16));
this.alpha = 1.0;
}
},
// Returns a new copy of this color
copy: function () {
var r = this.red;
var g = this.green;
var b = this.blue;
var a = this.alpha;
return new AppNS.Painter.Graphics.Color(r, g, b, a);
},
// Sets this color to be a weighted average of this color and the given color.
// A good weight is 80% this color, 20% new color.
blendWith: function (color) {
if (color.alpha > 0.01) { // Make sure the color we're blending with exists, don't want to blend with invisible ink!
this.red = Math.floor(this.red * this.blendAmount + color.red * (1 - this.blendAmount));
this.green = Math.floor(this.green * this.blendAmount + color.green * (1 - this.blendAmount));
this.blue = Math.floor(this.blue * this.blendAmount + color.blue * (1 - this.blendAmount));
this.alpha = this.alpha * this.blendAmount + color.alpha * (1 - this.blendAmount);
}
},
// Lightens this color by the given amount
lighten: function (amount) {
this.red += this.clip((255 - this.red) * amount);
this.green += this.clip((255 - this.green) * amount);
this.blue += this.clip((255 - this.blue) * amount);
},
// Darkens this color by the given amount
darken: function (amount) {
this.red -= this.clip(this.red * amount);
this.green -= this.clip(this.green * amount);
this.blue -= this.clip(this.blue * amount);
},
// Returns the Color in a String representation of the form "rgba(<r>, <g>, <b>, <a>)"
toString: function () {
return "rgba(" + this.red + "," + this.green + "," + this.blue + "," + this.alpha + ")";
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Graphics", {
Color: Color
});
})(Microsoft.Paint);

View file

@ -0,0 +1,294 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
var Path = WinJS.Class.define(
// Constructor
function (data) {
// Params
this.minDist = 3; // Minumum distance before a point is added to the path
this.weight = 0.3; // Bezier weight of control points
this.p1 = null; // The first point
this.p2 = null; // The second point
this.p3 = null; // The third point (most recent)
this.box1 = null; // Touch bounding box data for the first point
this.box2 = null; // Touch bounding box data for the second point
this.box3 = null; // Touch bounding box data for the third point
this.dist = 0; // Current distance between the start and end points of the bezier curve
this.wStart = 0; // The width of the line at the beginning of the curve
this.wEnd = 0; // The width of the line at the end of the curve
this.dirStart = new AppNS.Painter.Math.Vector(0, 0); // Direction at beginning of curve
this.dirEnd = new AppNS.Painter.Math.Vector(0, 0); // Direction at the end of curve
this.perpStart = new AppNS.Painter.Math.Vector(0, 0); // Perpendicular at beginning of curve
this.perpEnd = new AppNS.Painter.Math.Vector(0, 0); // Perpendicular at end of curve
this.pStart = new AppNS.Painter.Math.Point(0, 0); // Point at beginning of curve
this.cpStart = new AppNS.Painter.Math.Point(0, 0); // Bezier control point at beginning of curve
this.cpEnd = new AppNS.Painter.Math.Point(0, 0); // Bezier control point at end of curve
this.pEnd = new AppNS.Painter.Math.Point(0, 0); // Point at end of curve
this.newPoint = false; // True if the there is a new point added to the path
if (data.x || data.y) {
this.p3 = new AppNS.Painter.Math.Point(data.x, data.y); // The third point (most recent)
} else {
throw new Error("PaintPlay - Error: Path object requires x and y data info.");
}
if (data.w && data.h) {
this.box3 = new AppNS.Painter.Math.Vector(data.w, data.h);
}
},
// Variables and Methods
{
// True if there is information necessary to draw the start of a curve (2 points)
starting: {
get: function () {
return (this.newPoint && this.numPoints() === 2);
}
},
// True if this path is new (1 point)
created: {
get: function () {
return (this.numPoints() === 1);
}
},
// True if this path is drawable (3 points)
drawable: {
get: function () {
return (this.newPoint && this.numPoints() === 3);
}
},
numPoints: function () {
if (this.p1) {
return 3;
} else if (this.p2) {
return 2;
} else if (this.p3) {
return 1;
} else {
return 0;
}
},
// Adds the given point to the path
addPoint: function (data) {
// Add the new point if mouse moved far enough
if (data.x || data.y) {
var p = new AppNS.Painter.Math.Point(data.x, data.y);
} else {
throw new Error("PaintPlay - Error: Path object requires x and y data info.");
}
if (data.w && data.h) {
var box = new AppNS.Painter.Math.Vector(data.w, data.h);
}
if (this.p3.distanceTo(p) > this.minDist) {
this.newPoint = true;
// Reset the points of the curve
this.p1 = this.p2;
this.p2 = this.p3;
this.p3 = p;
this.box1 = this.box2;
this.box2 = this.box3;
this.box3 = box;
// If only have two points, initialize first direction vector
if (!this.p1) {
// Find the current distance
this.dist = this.p2.distanceTo(this.p3);
// Initialize tangent info
this.dirEnd.fromPoints(this.p2, this.p3);
this.dirEnd.normalize();
this.perpEnd.fromVector(this.dirEnd);
this.perpEnd.toPerp();
this.perpEnd.normalize();
} else {
// otherwise, we have all three points
// Find the current distance
this.dist = this.p1.distanceTo(this.p2);
// Set start and end tangent info
this.dirStart.fromVector(this.dirEnd);
this.dirEnd.fromPoints(this.p1, this.p3);
this.dirEnd.normalize();
// Set perpendicular vectors from start and end tangents
this.perpStart.fromVector(this.perpEnd);
this.perpEnd.fromVector(this.dirEnd);
this.perpEnd.toPerp();
this.perpEnd.normalize();
}
} else {
this.newPoint = false;
}
},
// Calculates the end Bezier curve info
calculateEndBezier: function (offsetStart, offsetEnd, inertia) {
if (this.p2 && this.p3) {
// If offset given, use it
var c2 = offsetStart || 0;
var c3 = offsetEnd || 0;
inertia = inertia || 0;
var dir3 = new AppNS.Painter.Math.Vector();
dir3.fromPoints(this.p2, this.p3);
dir3.normalize();
var perp3 = new AppNS.Painter.Math.Vector();
perp3.fromVector(dir3);
perp3.toPerp();
perp3.normalize();
// First bezier point
this.pStart.fromPoint(this.p2);
this.pStart.scaleAdd(this.perpEnd, c2);
// Last bezier point
this.pEnd.fromPoint(this.p3);
this.pEnd.scaleAdd(perp3, c3);
this.pEnd.scaleAdd(dir3, inertia);
var dist = this.pStart.distanceTo(this.pEnd);
// First control point
this.cpStart.fromPoint(this.pStart);
this.cpStart.scaleAdd(this.dirEnd, dist * this.weight);
// Second control point
this.cpEnd.fromPoint(this.pEnd);
this.cpEnd.scaleAdd(dir3, -1 * dist * this.weight);
}
},
calculateInertia: function (inertia, dist, min, max) {
var cInertia = dist * inertia;
if (cInertia < min) {
cInertia = min;
} else if (cInertia > max) {
cInertia = max;
}
return cInertia;
},
calculateStartCurve: function (offsetTop, offsetBottom, inertia, minInertia, overlap) {
if (this.p2 && this.p3) {
// If offset given, use it
var cTop = offsetTop || 0;
var cBottom = offsetBottom || 0;
var cOverlap = overlap || 0;
var cInertia = -this.calculateInertia(inertia, this.dist, minInertia, 4 * minInertia);
// First bezier point
this.pStart.fromPoint(this.p2);
this.pStart.scaleAdd(this.dirEnd, cOverlap);
this.pStart.scaleAdd(this.perpEnd, -1 * cBottom);
// Last bezier point
this.pEnd.fromPoint(this.p2);
this.pEnd.scaleAdd(this.dirEnd, cOverlap);
this.pEnd.scaleAdd(this.perpEnd, cTop);
// First control point
this.cpStart.fromPoint(this.pStart);
this.cpStart.scaleAdd(this.dirEnd, cInertia);
// Second control point
this.cpEnd.fromPoint(this.pEnd);
this.cpEnd.scaleAdd(this.dirEnd, cInertia);
}
},
calculateStopCurve: function (offsetTop, offsetBottom, inertia, minInertia, overlap) {
if (this.p2 && this.p3) {
// If offset given, use it
var cTop = offsetTop || 0;
var cBottom = offsetBottom || 0;
var cOverlap = overlap || 0;
var cInertia = this.calculateInertia(inertia, this.dist, minInertia, 4 * minInertia);
// First bezier point
this.pStart.fromPoint(this.p2);
this.pStart.scaleAdd(this.dirEnd, -cOverlap);
this.pStart.scaleAdd(this.perpEnd, -1 * cBottom);
// Last bezier point
this.pEnd.fromPoint(this.p2);
this.pEnd.scaleAdd(this.dirEnd, -cOverlap);
this.pEnd.scaleAdd(this.perpEnd, cTop);
// First control point
this.cpStart.fromPoint(this.pStart);
this.cpStart.scaleAdd(this.dirEnd, cInertia);
// Second control point
this.cpEnd.fromPoint(this.pEnd);
this.cpEnd.scaleAdd(this.dirEnd, cInertia);
}
},
// Calculates the Bezier curve info.
// Offsets are the number of pixels perpendicular to main points (shifts curve up or down).
calculateBezier: function (offsetStart, offsetEnd, overlap) {
// If offset given, use it
var c1 = offsetStart || 0;
var c2 = offsetEnd || 0;
var c3 = overlap || 0;
// First bezier point
this.pStart.fromPoint(this.p1);
this.pStart.scaleAdd(this.dirStart, -c3);
this.pStart.scaleAdd(this.perpStart, c1);
// Last bezier point
this.pEnd.fromPoint(this.p2);
this.pEnd.scaleAdd(this.dirEnd, c3);
this.pEnd.scaleAdd(this.perpEnd, c2);
var dist = this.pStart.distanceTo(this.pEnd);
// First control point
this.cpStart.fromPoint(this.pStart);
this.cpStart.scaleAdd(this.dirStart, dist * this.weight);
// Second control point
this.cpEnd.fromPoint(this.pEnd);
this.cpEnd.scaleAdd(this.dirEnd, -1 * dist * this.weight);
},
// Calculates the line width based on touch-box data
calculateWidth: function () {
if (this.box1 && this.box2) {
this.wStart = this.box1.componentIn(this.perpStart);
this.wEnd = this.box2.componentIn(this.perpEnd);
} else {
this.wStart = 10;
this.wEnd = 30;
}
}
});
WinJS.Namespace.defineWithParent(AppNS, "Painter.Graphics", {
Path: Path
});
})(Microsoft.Paint);

View file

@ -0,0 +1,87 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// A Texture has an image that is processed and given to a canvas object
var Texture = WinJS.Class.define(
// Constructor
function (image) {
onload = onload || function () {};
// The canvas containing the colored texture
this.size = 40;
this.colorCanvas = document.createElement("canvas");
this.colorCanvas.height = this.size;
this.colorCanvas.width = this.size;
this.ctx = this.colorCanvas.getContext("2d");
// The ImageData object used to draw pixels on colored texture
this.copyCanvas = document.createElement("canvas");
this.copyCanvas.height = this.size;
this.copyCanvas.width = this.size;
this.copyCtx = this.copyCanvas.getContext("2d");
this.copy = this.copyCtx.createImageData(this.size, this.size);
// The canvas containing the scaled texture
this.textureCanvas = document.createElement("canvas");
this.textureCtx = this.textureCanvas.getContext("2d");
this.textureColor = new AppNS.Painter.Graphics.Color();
this.textureCanvas.width = this.size;
this.textureCanvas.height = this.size;
this.texturePattern = null;
// The original image of the texture
this.ctx.drawImage(image, 0, 0);
this.imageData = this.ctx.getImageData(0, 0, this.size, this.size);
},
// Variables and Methods
{
/// <summary>
/// Updates the canvas with the given zoom and color
/// </summary>
/// <param type="Microsoft.Paint.Painter.Graphics.Color" name="color">
/// The color of the pixels in the texture.
/// </param>
/// <param type="number" name="zoom">
/// How much the texture is zoomed in. Zoom = 1 means normal size,
/// Zoom = 2 means zoomed in 2x, etc.
/// </param>
update: function (color, zoom) {
this.textureColor.fromColor(color);
this.textureCanvas.width = zoom * this.size;
this.textureCanvas.height = zoom * this.size;
this.replacePixels(this.textureColor);
this.texturePattern = this.ctx.createPattern(this.textureCanvas, "repeat");
},
// Replaces all pixels with pixels of the given color.
// Opacity is taken from the texture though.
replacePixels: function (color) {
for (var x = 0; x < this.size; x++) {
for (var y = 0; y < this.size; y++) {
var k = (y * this.size + x) * 4;
var alpha = this.imageData.data[k + 3];
this.copy.data[k + 0] = color.red;
this.copy.data[k + 1] = color.green;
this.copy.data[k + 2] = color.blue;
this.copy.data[k + 3] = alpha;
}
}
this.ctx.putImageData(this.copy, 0, 0);
this.textureCtx.globalCompositeOperation = "copy";
this.textureCtx.drawImage(this.colorCanvas, 0, 0, this.size, this.size, 0, 0, this.textureCanvas.width, this.textureCanvas.height);
},
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Graphics", {
Texture: Texture
});
})(Microsoft.Paint);

View file

@ -0,0 +1,77 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Point class represents a point in 2-Dimensional space using Cartesian Coordinates.
var Point = WinJS.Class.define(
// Constructor
function (x, y) {
// The position of the point in 2d space, cartesian coords
this.x = x || 0;
this.y = y || 0;
},
// Variables and Functions
{
// Returns the distance between this and another point
distanceTo: function (point) {
var dx = point.x - this.x;
var dy = point.y - this.y;
return Math.sqrt(dx * dx + dy * dy);
},
// Creates a Vector pointing from this point to point p
createVectorTo: function (point) {
return new AppNS.Painter.Math.Vector(point.x - this.x, point.y - this.y);
},
// Sets this point to the result of adding the Vector v to this point
add: function (vector) {
this.x = this.x + vector.x;
this.y = this.y + vector.y;
},
// Sets this point to this point translated by the scaled vector
scaleAdd: function (vector, constant) {
this.x = this.x + (vector.x * constant);
this.y = this.y + (vector.y * constant);
},
// Sets this point to the result of subtracting the Vector v from this point
sub: function (vector) {
this.x = this.x - vector.x;
this.y = this.y - vector.y;
},
// Returns true if this point is the same as p
equals: function (point) {
return this.x === point.x && this.y === point.y;
},
// Sets this point to the given x and y coords
fromXY: function (x, y) {
this.x = x;
this.y = y;
},
// Sets this point to the given point
fromPoint: function (point) {
this.x = point.x;
this.y = point.y;
},
// Returns a copy of this point
copy: function () {
return new AppNS.Painter.Math.Point(this.x, this.y);
}
});
WinJS.Namespace.defineWithParent(AppNS, "Painter.Math", {
Point: Point
});
})(Microsoft.Paint);

View file

@ -0,0 +1,143 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Vector class represents a position-less vector in 2-Dimensional space.
// A Vector has direction and length, both represented in the form of change in x and change in y.
var Vector = WinJS.Class.define(
// Constructor
function (x, y) {
this.x = x || 0; // The x-component of this vector
this.y = y || 0; // The y-component of this vector
},
// Variables and Functions
{
// The length of this vector, as calculated by it's x and y components
length: {
get: function () {
return Math.sqrt(this.x * this.x + this.y * this.y);
},
set: function (length) {
this.normalize();
this.scale(length);
}
},
// Return the dot product of this vector and v
dot: function (vector) {
return this.x * vector.x + this.y * vector.y;
},
// Sets this vector to the given x and y
fromXY: function (x, y) {
this.x = x;
this.y = y;
},
// Set this vector to the given vector
fromVector: function (vector) {
this.x = vector.x;
this.y = vector.y;
},
// Create a vector from point1 pointing towards point2
fromPoints: function (point1, point2) {
this.x = point2.x - point1.x;
this.y = point2.y - point1.y;
},
// Rotates this vector by 90 degrees counter-clockwise, making it perpendicular to what it was
toPerp: function () {
var temp = this.x;
this.x = -1 * this.y
this.y = temp;
},
// Rotates this vector counter-clockwise by angle in radians
rotate: function (angle) {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var x = this.x;
var y = this.y;
this.x = x * cos - y * sin;
this.y = x * sin + y * cos;
},
// Scales this vector by a constant
scale: function (constant) {
this.x = this.x * constant;
this.y = this.y * constant;
},
// Returns the angle in radians between this vector and v
angle: function (vector) {
var l1 = this.length;
var l2 = vector.length;
if (l1 !== 0 && l2 !== 0) {
var val = this.dot(vector) / (l1 * l2);
val = val > 1.0 ? 1.0 : val;
val = val < -1.0 ? -1.0 : val;
return Math.acos(val);
}
},
// Returns the slope (dy/dx) of this vector
getSlope: function () {
return this.y / this.x;
},
// Normalizes (sets to length 1) this vector
normalize: function () {
var length = this.length;
if (length !== 0) {
this.scale(1 / length);
}
},
// Sets this vector to the result of subtracting the given vector from this
sub: function (vector) {
this.x = this.x - vector.x;
this.y = this.y - vector.y;
},
// Sets this vector to the result of adding the given vector to this
add: function (vector) {
this.x = this.x + vector.x;
this.y = this.y + vector.y;
},
// Returns true if this vector is equal to another
equals: function (vector) {
return this.x === vector.x && this.y === vector.y;
},
// Returns a copy of this vector
copy: function () {
return new AppNS.Painter.Math.Vector(this.x, this.y);
},
// Projects this vector onto the given direction.
// Note: the length of the direction vector is irrelevant.
project: function (vector) {
var direction = vector.copy();
var length = this.componentIn(direction);
direction.length = length;
this.fromVector(direction);
},
// Returns the length of the component of this vector in the given vector's direction
componentIn: function (vector) {
return this.dot(vector) / vector.length;
}
});
WinJS.Namespace.defineWithParent(AppNS, "Painter.Math", {
Vector: Vector
});
})(Microsoft.Paint);

151
Controls/Paint/Painter.js Normal file
View file

@ -0,0 +1,151 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
var Painter = WinJS.Class.define(
// Constructor
function (domCanvas) {
this.paths = []; // The set of paths being built from
this.pathCounted = []; // Array of boolean flags to tell if a path has been counted or not
this.pathCount = 0; // Current count of active paths (number of fingers on the canvas)
this.toolName = "marker"; // The currently selected tool's name
this.tools = {}; // All of the tools used by this Painter
this.canvas = new AppNS.Painter.Graphics.Canvas(domCanvas); // The current canvas this Painter is attached to
this._currentColor = new AppNS.Painter.Graphics.Color(0,0,0,1); // The current color selected
this.loadTool(new AppNS.Painter.Tools.Marker(), "marker"); // Every Painter has the Marker by default
},
// Variables and Functions
{
// The currently selected tool
tool: {
get: function () {
if (this.tools.hasOwnProperty(this.toolName)) {
return this.tools[this.toolName];
} else {
return null;
}
},
set: function (newTool) {
if (this.tools.hasOwnProperty(newTool)) {
this.toolName = newTool;
} else {
throw new Error("PaintPlay - Error: No such tool.");
}
}
},
color: {
get: function () {
return this._currentColor;
},
set: function (newColor) {
this._currentColor.fromColor(newColor);
this.updateTools();
}
},
updateTools: function () {
for (var tool in this.tools){
if (this.tools[tool].update) {
this.tools[tool].update(this);
}
}
},
// Adds the given tool with the given string name to the Painter.
// Default Painter has only a marker (simple line drawer).
loadTool: function (tool, name) {
this.tools[name] = tool;
this.updateTools();
},
/// <summary>
/// Begins drawing the path with the current tool.
/// </summary>
/// <param name="data" type="data">
/// The data parameter is an object with the following properties:
/// - x (required, number): the x position on the canvas
/// - y (required, number): the y position on the canvas
/// - w (optional, number from [0, inf)): the width of the touch input box
/// - h (optional, number from [0, inf)): the height of the touch input box
/// - id (optional, number): the ID of this path, usually taken from the touch input's pointerId
/// </param>
drawStart: function (data) {
if (this.canvas) {
var id = data.id || 0;
this.paths[id] = new AppNS.Painter.Graphics.Path(data);
this.pathCounted[id] = false;
if (this.tool.renderStart) {
this.tool.renderStart(this.paths[id], this);
}
}
},
/// <summary>
/// Begins drawing the path with the current tool.
/// </summary>
/// <param name="data" type="data">
/// The data parameter is an object with the following properties:
/// - x (required, number): the x position on the canvas
/// - y (required, number): the y position on the canvas
/// - w (optional, number from [0, inf)): the width of the touch input box
/// - h (optional, number from [0, inf)): the height of the touch input box
/// - id (optional, number): the ID of this path, usually taken from the touch input's pointerId
/// </param>
draw: function (data) {
var id = data.id || 0;
var path = this.paths[id];
if (!this.pathCounted[id]) {
this.pathCount++;
this.pathCounted[id] = true;
}
if (path && this.canvas) {
path.addPoint(data);
this.tool.render(path, this);
}
},
/// <summary>
/// Begins drawing the path with the current tool.
/// </summary>
/// <param name="data" type="data">
/// The data parameter is an object with the following properties:
/// - x (required, number): the x position on the canvas
/// - y (required, number): the y position on the canvas
/// - w (optional, number from [0, inf)): the width of the touch input box
/// - h (optional, number from [0, inf)): the height of the touch input box
/// - id (optional, number): the ID of this path, usually taken from the touch input's pointerId
/// </param>
drawStop: function (data) {
var id = data.id || 0;
var path = this.paths[id];
if (path && this.canvas) {
path.addPoint(data);
if (this.pathCounted[id]) {
this.pathCount--;
this.pathCounted[id] = false;
}
this.tool.render(path, this);
if (this.tool.renderStop) {
this.tool.renderStop(path, this);
}
if (this.pathCount === 0) {
this.canvas.saveState();
}
}
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter", {
Painter: Painter
});
})(Microsoft.Paint);

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -0,0 +1,25 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// A Bristle simulates the bristle on a brush.
var Bristle = WinJS.Class.define(
// Constructor
function () {
this.color = new AppNS.Painter.Graphics.Color(); // The color of the bristle
this.width = 2; // The bristle width is 2px
},
// Variables and Methods
{}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Bristle: Bristle
});
})(Microsoft.Paint);

View file

@ -0,0 +1,176 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Brush tool simulates a PaintBrush, with color blending and paint loss over distance.
var Brush = WinJS.Class.define(
// Constructor
function () {
this.blends = false; // Sets whether or not this brush blends with underlying color
this.fade = 1000; // How quickly the brush fades, in pixels (0 = no fade)
this.numBristles = 0; // Number of bristles on each side of the brush.
this.bristles = []; // All of the Brush Bristles
this.pxPerBristle = 3; // The width of each bristle
this.maxA = 1.0; // Maximum beginning opacity
this.minA = 0.8; // Minimum beginning opacity
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
this._width = 0;
this.width = 20;
},
// Variables and Methods
{
// The width of the brush, to be approximated using bristles
width: {
get: function () {
return this._width;
},
set: function (w) {
this.numBristles = Math.floor(0.3 * w / this.pxPerBristle);
if (this.numBristles <= 0) {
this.numBristles = 0;
}
this._width = (2 * this.numBristles + 1) * this.pxPerBristle;
}
},
// Begins rendering the beginning of the path
renderStart: function (path, painter) {
var ctx = painter.canvas.context;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1.0;
var startColor = painter.color.copy();
startColor.alpha = this.maxA;
ctx.fillStyle = startColor.toString();
for (var i = -this.numBristles; i <= this.numBristles; i++) {
this.bristles[i] = new AppNS.Painter.Tools.Bristle();
this.bristles[i].color.fromColor(startColor);
this.bristles[i].width = this.pxPerBristle + 0.5;
}
},
// Renders the given path using the current Marker style
render: function (path, painter) {
var ctx = painter.canvas.context;
// If just starting the path, draw semicircle
if (path.starting) {
path.calculateStartCurve(this.width / 2, this.width / 2, 3, this.width);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
if (path.drawable) {
// Colors
var blendColor = new AppNS.Painter.Graphics.Color();
var oldColor = new AppNS.Painter.Graphics.Color();
// Draw each simulated bristle as a bezier curve
for (var i = -this.numBristles; i <= this.numBristles; i++) {
// The color at the beginning of the stroke segment
oldColor.fromColor(this.bristles[i].color);
var offsetStart = i * this.pxPerBristle;
var offsetEnd = i * this.pxPerBristle;
path.calculateBezier(offsetStart, offsetEnd, Math.pow(oldColor.alpha, 2) * 0.25);
// Blend bristle's color with canvas color
if (this.blends) {
painter.canvas.getColorAt(blendColor, path.cpStart.x, path.cpStart.y);
this.bristles[i].color.blendWith(blendColor);
}
// Update opacity
var currA = this.bristles[i].color.alpha;
var perturb = 0;
if (this.fade) { // Cause the brush to lose ink over distance
perturb = Math.random() * -(Math.pow(0.2 * i / (this.numBristles + 1), 4) + path.dist / this.fade);
currA = currA + perturb;
} else { // Cause the brush to randomly gain or lose ink per bristle, within minA and maxA
currA = Math.random() * (this.maxA - this.minA) + this.minA;
}
this.bristles[i].color.alpha = this.bristles[i].color.clipAlpha(currA);
this.bristles[i].width = this.pxPerBristle + Math.pow(oldColor.alpha, 2) * 0.5;
// Create a linear gradient from the start of the stoke segment to the end,
// giving a smooth transition of color.
var gradient = ctx.createLinearGradient(path.pStart.x, path.pStart.y, path.pEnd.x, path.pEnd.y);
gradient.addColorStop(0, oldColor.toString());
gradient.addColorStop(1, this.bristles[i].color.toString());
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.lineWidth = this.bristles[i].width;
ctx.strokeStyle = gradient;
ctx.stroke();
}
}
},
// Stops the path with the current style
renderStop: function (path, painter) {
var ctx = painter.canvas.context;
if (path.created || path.starting) {
painter.canvas.drawCircle(path.p3.x, path.p3.y, this.width / 2);
} else {
// Colors
var blendColor = new AppNS.Painter.Graphics.Color();
var oldColor = new AppNS.Painter.Graphics.Color();
// Draw each simulated bristle as a bezier curve
for (var i = -this.numBristles; i <= this.numBristles; i++) {
var offsetStart = i * this.pxPerBristle;
var offsetEnd = i * this.pxPerBristle;
path.calculateEndBezier(offsetStart, offsetEnd, 20);
// The color at the beginning of the stroke segment
oldColor.fromColor(this.bristles[i].color);
// Blend bristle's color with canvas color
if (this.blends) {
painter.canvas.getColorAt(blendColor, path.cpStart.x, path.cpStart.y);
this.bristles[i].color.blendWith(blendColor);
}
// Update opacity
this.bristles[i].color.alpha = 0;
// Create a linear gradient from the start of the stoke segment to the end,
// giving a smooth transition of color.
var gradient = ctx.createLinearGradient(path.pStart.x, path.pStart.y, path.pEnd.x, path.pEnd.y);
gradient.addColorStop(0, oldColor.toString());
gradient.addColorStop(1, this.bristles[i].color.toString());
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.lineWidth = this.bristles[i].width;
ctx.strokeStyle = gradient;
ctx.stroke();
}
}
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Brush: Brush
});
})(Microsoft.Paint);

View file

@ -0,0 +1,146 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The crayon tool uses textures to generate a crayon/pencil/chalk like effect
var Crayon = WinJS.Class.define(
// Constructor
function () {
this._density = 0.5; // The default density is 50% color
this._color = new AppNS.Painter.Graphics.Color(0,0,0,255);
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
this.width = 30; // The default line manual width
this.texture = null;
},
// Variables and Methods
{
density: {
get: function () {
return this._density;
},
set: function (d) {
this._density = d;
if (this.texture) {
this.texture.update(this._color, this._density);
}
}
},
// Starts rendering the given path using the current style
renderStart: function (path, painter) {
var ctx = painter.canvas.context;
ctx.fillStyle = this.texture.texturePattern;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1.0;
},
// Renders the given path using the current style
render: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If just starting the path, draw semicircle
if (path.starting) {
path.calculateStartCurve(wEnd / 2, wEnd / 2, 3, wEnd);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
this.fillCrayon(ctx);
}
if (path.drawable) {
// Start at first point of shape, then bezier to second
ctx.beginPath();
path.calculateBezier(wStart / 2, wEnd / 2);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateBezier(-1 * wStart / 2, -1 * wEnd / 2);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
// Set fill Style and fill shape
this.fillCrayon(ctx);
}
},
// Renders the end of the path with the current style
renderStop: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If haven't drawn starting effect yet
if (path.created || path.starting) {
ctx.beginPath();
ctx.arc(path.p3.x, path.p3.y, wEnd / 2, 0, Math.PI * 2, true);
ctx.closePath();
this.fillCrayon(ctx);
} else { // Otherwise, draw a curve to end the path
path.calculateStopCurve(wEnd / 2, wEnd / 2, 3, wEnd);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
this.fillCrayon(ctx);
}
},
fillCrayon: function (ctx) {
// Set fill Style and fill shape
ctx.fillStyle = this.texturePattern;
ctx.save();
var rand = Math.random();
ctx.rotate(rand * 2 * Math.PI);
ctx.translate(rand * 10, rand * 10);
ctx.fill();
ctx.restore();
},
update: function (painter) {
this._color = painter.color.copy();
if (this.texture) {
this.texture.update(this._color, this._density);
}
},
setTexture: function (textureImage) {
this.texture = new AppNS.Painter.Graphics.Texture(textureImage);
this.texture.update(this._color, this._density);
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Crayon: Crayon
});
})(Microsoft.Paint);

View file

@ -0,0 +1,101 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Marker tool is the simplest tool.
// It simply connect users points smoothly with a solid color, usually slightly transparent.
var Eraser = WinJS.Class.define(
// Constructor
function () {
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
this.width = 20; // The default line manual width
},
// Variables and Methods
{
// Begins rendering the beginning of the path
renderStart: function (path, painter) {
var ctx = painter.canvas.context;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
ctx.globalCompositeOperation = "destination-out";
ctx.globalAlpha = 1;
ctx.fillStyle = "rgba(0,0,0,1)";
// Start effect
var x = path.p3.x;
var y = path.p3.y;
painter.canvas.drawCircle(x, y, this.width / 2);
},
// Renders the given path using the current Marker style
render: function (path, painter) {
if (path.drawable) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth) {
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// Start at first point of shape, then bezier to second
ctx.beginPath();
path.calculateBezier(wStart / 2, wEnd / 2, 0.5);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateBezier(-1 * wStart / 2, -1 * wEnd / 2, 0.5);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
ctx.fill();
}
},
// Begins rendering the beginning of the path
renderStop: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// Start at first point of shape, then bezier to second
ctx.beginPath();
path.calculateEndBezier(wStart / 2, wEnd / 2);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateEndBezier(-1 * wStart / 2, -1 * wEnd / 2);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
ctx.fill();
painter.canvas.drawCircle(path.p3.x, path.p3.y, this.width / 2);
},
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Eraser: Eraser
});
})(Microsoft.Paint);

View file

@ -0,0 +1,108 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Marker tool is the simplest tool.
// It simply connect users points smoothly with a solid color, usually slightly transparent.
var Marker = WinJS.Class.define(
// Constructor
function () {
this.opacity = 0.85; // The default opacity is 85%
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
this.width = 30; // The default line manual width is 1px
},
// Variables and Methods
{
// Renders the beginning of the path
renderStart: function (path, painter) {
var ctx = painter.canvas.context;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = this.opacity;
ctx.fillStyle = painter.color.toString();
},
// Renders the given path using the current Marker style
render: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If just starting the path, draw semicircle
if (path.starting) {
path.calculateStartCurve(wEnd / 2, wEnd / 2, 3, wEnd, Math.pow(this.opacity, 2) * 0.22);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
if (path.drawable) {
// Start at first point of shape, then bezier to second
ctx.beginPath();
path.calculateBezier(wStart / 2, wEnd / 2, Math.pow(this.opacity, 2) * 0.22);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateBezier(-1 * wStart / 2, -1 * wEnd / 2, Math.pow(this.opacity, 2) * 0.22);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
// Set fill Style and fill shape
ctx.fill();
}
},
// Renders the end of the path with the current style
renderStop: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If haven't drawn starting effect yet
if (path.created || path.starting) {
painter.canvas.drawCircle(path.p3.x, path.p3.y, wEnd / 2);
} else {
// Otherwise, draw a curve to end the path
path.calculateStopCurve(wEnd / 2, wEnd / 2, 3, wEnd, Math.pow(this.opacity, 2) * 0.22);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Marker: Marker
});
})(Microsoft.Paint);

View file

@ -0,0 +1,105 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Neon tool has a glow effect
var Neon = WinJS.Class.define(
// Constructor
function () {
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
this.width = 20; // The default line manual width
this.glow = 20; // The amount of shadow blur used to generate the glow
},
// Variables and Methods
{
// Begins rendering the beginning of the path
renderStart: function (path, painter) {
var ctx = painter.canvas.context;
ctx.fillStyle = painter.color.toString();
ctx.shadowColor = painter.color.toString();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = this.glow;
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1.0;
},
// Renders the given path using the current style
render: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth) {
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If just starting the path, draw semicircle
if (path.starting) {
path.calculateStartCurve(wEnd / 2, wEnd / 2, 3, wEnd);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
if (path.drawable) {
// Start at first point of shape, then bezier to second
ctx.beginPath();
path.calculateBezier(wStart / 2, wEnd / 2, 0.5);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateBezier(-wStart / 2, -wEnd / 2, 0.5);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
ctx.fill();
}
},
// Renders the end of the path with the current style
renderStop: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If haven't drawn starting effect yet
if (path.created || path.starting) {
painter.canvas.drawCircle(path.p3.x, path.p3.y, wEnd / 2);
} else {
// Otherwise, draw a curve to end the path
path.calculateStopCurve(wEnd / 2, wEnd / 2, 3, wEnd);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Neon: Neon
});
})(Microsoft.Paint);

View file

@ -0,0 +1,221 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
'use strict';
// The Pipe tool has a 3D look to it
var Pipe = WinJS.Class.define(
// Constructor
function () {
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
this.width = 20; // The default line manual width
this.height = 6; // The 'height' of the 3D pipe look, in pixels
this.maxHeight = 6;
this.numBristles = 0; // Number of bristles on each side of the pipe
this.bristles = []; // All of the pipe bristles
this.pxPerBristle = 1; // The width of each bristle in pixels
this.middleBristle = new AppNS.Painter.Tools.Bristle();
},
// Variables and Methods
{
// Begins rendering the beginning of the path
renderStart: function (path, painter) {
var color = new AppNS.Painter.Graphics.Color();
color.fromColor(painter.color);
// If the color is dark, we lighten it
if (color.red + color.green + color.blue < 255 * 3 / 2) {
color.lighten(0.2);
}
// Inner Bristles
this.numBristles = Math.floor(0.25 * this.width / this.pxPerBristle);
if (this.numBristles <= 0) {
this.numBristles = 1;
}
for (var i = 0; i < this.numBristles; i++) {
this.bristles[i] = new AppNS.Painter.Tools.Bristle();
this.bristles[i].color.fromColor(color);
this.bristles[i].color.scale(1 - ((i + 1) / this.numBristles) * (this.height / this.maxHeight));
this.bristles[i].width = this.pxPerBristle;
}
// Large inner bristle
this.middleBristle.width = this.width - (this.numBristles * this.pxPerBristle * 2);
this.middleBristle.color.fromColor(color);
var ctx = painter.canvas.context;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1.0;
},
// Renders the given path using the current style
render: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth) {
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
var outerStart = this.middleBristle.width / 2;
var outerEnd = this.middleBristle.width / 2;
if (path.starting) {
// Draw each simulated bristle as a bezier curve
for (var i = this.numBristles - 1; i >= 0; i--) {
var offsetStart = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
var offsetEnd = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
ctx.strokeStyle = this.bristles[i].color.toString();
ctx.fillStyle = this.bristles[i].color.toString();
ctx.lineWidth = this.bristles[i].width;
// Draw the Bristle
path.calculateStartCurve(offsetStart, offsetEnd, 3, wEnd);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
// Draw middle
path.calculateStartCurve(this.middleBristle.width / 2, this.middleBristle.width / 2, 3, wEnd);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fillStyle = this.middleBristle.color.toString();
ctx.fill();
}
if (path.drawable) {
ctx.lineWidth = this.pxPerBristle + 0.5;
// Draw each simulated bristle as a bezier curve
for (var i = this.numBristles - 1; i >= 0; i--) {
var offsetStart = (i + 0.5) * this.pxPerBristle + outerStart;
var offsetEnd = (i + 0.5) * this.pxPerBristle + outerEnd;
var overlap = 1.5 * (1 - i / this.numBristles);
// Draw the middle bristle.
// Start at first point of shape, then bezier to second.
ctx.beginPath();
path.calculateBezier(offsetStart, offsetEnd, overlap);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateBezier(-offsetStart, -offsetEnd, overlap);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
// Set fill Style and fill shape
ctx.fillStyle = this.bristles[i].color.toString();
ctx.fill();
}
// Draw the middle bristle.
// Start at first point of shape, then bezier to second.
ctx.beginPath();
path.calculateBezier(outerStart, outerEnd, 2);
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
// Line to third point of shape, then bezier to fourth, then close the path
path.calculateBezier(-outerStart, -outerEnd, 2);
ctx.lineTo(path.pEnd.x, path.pEnd.y);
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
ctx.closePath();
// Set fill Style and fill shape
ctx.fillStyle = this.middleBristle.color.toString();
ctx.fill();
}
},
// Renders the end of the path with the current style
renderStop: function (path, painter) {
var ctx = painter.canvas.context;
// Get start and end widths for the stroke part
var wStart = this.width;
var wEnd = this.width;
if (this.autoWidth){
path.calculateWidth();
wStart = path.wStart;
wEnd = path.wEnd;
}
// If haven't drawn starting effect yet
if (path.created || path.starting) {
var x = path.p3.x;
var y = path.p3.y;
// Draw bristles
for (var i = this.numBristles - 1; i >= 0; i--) {
var radius = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
// Draw the Bristle
ctx.fillStyle = this.bristles[i].color.toString();
painter.canvas.drawCircle(x, y, radius);
}
// Draw middle
ctx.fillStyle = this.middleBristle.color.toString();
painter.canvas.drawCircle(x, y, this.middleBristle.width / 2);
} else { // Otherwise, draw a curve to end the path
// Draw each simulated bristle as a bezier curve
for (var i = this.numBristles - 1; i >= 0; i--) {
var offsetStart = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
var offsetEnd = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
var overlap = 1.5 * (1 - i / this.numBristles);
ctx.fillStyle = this.bristles[i].color.toString();
ctx.lineWidth = this.bristles[i].width;
// Draw the Bristle
path.calculateStopCurve(offsetStart, offsetEnd, 3, wEnd, overlap);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fill();
}
// Draw middle
path.calculateStopCurve(this.middleBristle.width / 2, this.middleBristle.width / 2, 3, wEnd, 2);
ctx.beginPath();
ctx.moveTo(path.pStart.x, path.pStart.y);
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
ctx.closePath();
ctx.fillStyle = this.middleBristle.color.toString();
ctx.fill();
}
}
}
);
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
Pipe: Pipe
});
})(Microsoft.Paint);

View file

@ -0,0 +1,133 @@
#command_toolbar_clear
{
border: none;
}
.win-commandBar-stack-horiz button
{
border: none;
font-family: "Segoe UI";
font-size: 9pt;
width: 100px;
}
.win-commandBar-stack-horiz button:hover
{
background: rgb(17,17,17);
}
.win-commandBar-rule-horiz
{
display: none;
}
.win-commandBar-horiz
{
margin-left: 30px;
}
#brush-flyout
{
background: rgb(242, 242, 222);
border: solid 2px rgb(17,17,17);
border-bottom: none;
color: rgb(17,17,17);
margin: 0 !important;
padding: 0;
width: 260px;
}
#size-flyout
{
background: rgb(242, 242, 222);
border: solid 2px rgb(17,17,17);
border-bottom: none;
color: rgb(17,17,17);
margin: 0 !important;
padding: 0;
width: 260px;
}
#option-flyout
{
background: rgb(242, 242, 222);
border: solid 2px rgb(17,17,17);
border-bottom: none;
color: rgb(17,17,17);
margin: 0 !important;
padding: 0;
width: 260px;
}
.toolbar-flyout
{
background: rgb(242, 242, 222);
border: solid 2px rgb(17,17,17);
border-bottom: none;
color: rgb(17,17,17);
margin: 0 !important;
width: 260px;
}
.brush-preview
{
height: 50px;
width: 100%;
}
.selectedPreview
{
background: #CFDDE3;
}
.brush-width-thin
{
height: 50px;
width: 260px;
}
.brush-width-thin canvas
{
height: 100%;
width: 100%;
}
.brush-width-thick
{
height: 100px;
width: 260px;
}
.colorpickerContainer
{
margin-left: 30px;
margin-right: 17px;
}
.pan-mode-toggle
{
color: #212121;
display: none;
font-family: "Segoe UI Semilight";
font-size: 20pt;
height: 50px;
text-align: center;
vertical-align: middle;
}
.toolbar-flyout-background
{
background-color: rgba(0, 0, 0, 0);
bottom: 0;
position: absolute;
z-index: 1002;
}
.canvas-flyout-background
{
background-color: rgba(0, 0, 0, 0);
left: 0;
position: absolute;
top: 0;
z-index: 1000;
}

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<title>Toolbar</title>
<link rel="stylesheet" href="/JS/CommandBar/CommandBar.css" />
<link rel="stylesheet" href="/JS/CommandBar/Flyout.css" />
<link rel="stylesheet" href="/Controls/ColorPicker/ColorPicker.css" />
<link rel="stylesheet" href="Toolbar.css" />
<script src="/WinJS/js/base.js"></script>
<script src="/WinJS/js/ui.js"></script>
<script src="/JS/Global.js"></script>
<script src="/JS/CommandBar/Flyout.js"></script>
<script src="/JS/CommandBar/CommandBar.js"></script>
<script src="/Controls/ColorPicker/ColorPicker.js"></script>
<script src="/Controls/Paint/Tools/Bristle.js"></script>
<script src="/Controls/Paint/Tools/Eraser.js"></script>
<script src="/Controls/Paint/Tools/Brush.js"></script>
<script src="/Controls/Paint/Painter.js"></script>
<script src="ToolbarColors.js"></script>
<script src="Toolbar.js"></script>
</head>
<body>
<div id="brush-flyout" data-win-control="WinJS.UI.Flyout" data-win-options="{ autoHide: 0, lightDismiss: false }">
</div>
<div id="size-flyout" data-win-control="WinJS.UI.Flyout" data-win-options="{ autoHide: 0, lightDismiss: false }">
</div>
<div id="option-flyout" data-win-control="WinJS.UI.Flyout" data-win-options="{ autoHide: 0, lightDismiss: false }">
</div>
<div id="more-flyout" data-win-control="WinJS.UI.Flyout" data-win-options="{ autoHide: 0, lightDismiss: false }">
<button id="undo-button">Undo</button> <!-- TODO: Win8Apps WORK 92: Add localization support -->
<button id="clear-button">Clear</button> <!-- TODO: Win8Apps WORK 92: Add localization support -->
</div>
<div id="appBar" class="appBar" data-win-control="WinJS.UI.AppBar" data-win-options="{ position: 'bottom', transient: true, autoHide: 0, lightDismiss: false }">
<div class="commandBar">
</div>
</div>
</body>
</html>

1092
Controls/Toolbar/Toolbar.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (BaseNS) {
WinJS.Namespace.defineWithParent(BaseNS, "Paint", {
ToolbarManager: {
ToolbarColors: [
"rgb(0, 0, 0)",
"rgb(128, 128, 128)",
"rgb(166, 166, 166)",
"rgb(217, 217, 217)",
"rgb(255, 255, 255)",
"rgb(253, 233, 217)",
"rgb(255, 204, 153)",
"rgb(153, 102, 51)",
"rgb(102, 51, 0)",
"rgb(128, 0, 0)",
"rgb(255, 0, 0)",
"rgb(255, 102, 0)",
"rgb(255, 192, 0)",
"rgb(255, 215, 47)",
"rgb(255, 255, 0)",
"rgb(255, 255, 153)",
"rgb(204, 255, 102)",
"rgb(153, 255, 151)",
"rgb(0, 204, 0)",
"rgb(0, 128, 0)",
"rgb(51, 153, 102)",
"rgb(0, 176, 240)",
"rgb(0, 0, 255)",
"rgb(0, 0, 153)",
"rgb(79, 0, 158)",
"rgb(112, 48, 160)",
"rgb(153, 102, 255)",
"rgb(255, 153, 255)",
"rgb(255, 51, 153)",
"rgb(204, 0, 153)"
]
}
});
})(Microsoft);

9
HTML/GalleryView.html Normal file
View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<title></title>
</head>
<body>
</body>
</html>

46
HTML/Main.html Normal file
View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<title>Paint</title>
<!-- JS Toolkits references -->
<script src="/WinJS/js/base.js"></script>
<script src="/WinJS/js/ui.js"></script>
<script src="/WinJS/js/binding.js"></script>
<script src="/WinJS/js/controls.js"></script>
<script src="/WinJS/js/animations.js"></script>
<script src="/WinJS/js/uicollections.js"></script>
<script src="/WinJS/js/wwaapp.js"></script>
<link rel="stylesheet" href="/WinJS/css/ui-dark.css" />
<!-- Paint references -->
<link rel="stylesheet" href="/CSS/Main.css" />
<script src="/JS/Global.js"></script>
<script src="/JS/Utils.js"></script>
<script src="/JS/Tiles.js"></script>
<script src="/JS/ViewCards.js"></script>
<script src="/JS/StateManager.js"></script>
<script src="/JS/ViewManager.js"></script>
<script src="/JS/KeyManager.js"></script>
<script src="/JS/Sharing.js"></script>
<script src="/JS/Main.js"></script>
</head>
<body data-design-activate="defaultPage.activated">
<section class="main-content">
</section>
<div id="Paint.Customization" style="visibility:hidden" data-win-control="WinJS.UI.SettingsPane" data-win-options="{width:'narrow',label:'Customize'}">
<div class="win-label">
<button onclick="WinJS.UI.SettingsPane.show()" class="win-backbutton"></button>
Customize
</div>
<div class="win-content">
<strong>Tiles</strong>
<p>Update the PaintPlay tile with the current canvas</p>
<button id="setCurrentTileSetting" onclick="Microsoft.Paint.Tiles.setCurrentCanvasAsTile()">Set tile</button>
<button id="clearTileSetting" onclick="Microsoft.Paint.Tiles.clearTile()">Clear tile</button>
</div>
</div>
</body>
</html>

21
HTML/PaintView.html Normal file
View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>PaintView</title>
<link rel="stylesheet" href="/CSS/PaintView.css" />
<script src="/WinJS/js/base.js"></script>
<script src="/JS/Global.js"></script>
<script src="/JS/PaintView.js"></script>
</head>
<body>
<div class="paintviewGrid">
<div class="canvas" id="canvas">
</div>
<div class="toolbar" id="toolbar">
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,173 @@
.win-commandBar-horiz
{
font-size: 10pt;
margin: 0px 36px 0px 36px;
}
.win-commandBar-horiz[appLayout='0']
{
margin: 0px;
}
.win-commandBar-stack-vert button
{
width: 100%;
}
.win-commandBar-stack-horiz[stack='left']
{
float: left;
}
.win-commandBar-stack-horiz[stack='right']
{
float: right;
}
.win-commandBar-stack-test
{
position: absolute;
visibility: hidden;
}
.win-commandBar-group-horiz
{
display: inline;
}
.minimized *[data-win-minimize]
{
display: none !important;
}
.win-commandBar-command-horiz
{
background-color: transparent;
border: none;
color: #FFFFFF;
height: 88px;
margin: 0px;
padding: 14px 0px 10px 0px !important;
text-align: center;
width: 100px;
}
.win-commandBar-command-horiz div.commandLabel
{
display: inline-block;
font-family: Segoe UI;
font-size: 10pt;
margin-top: 5px;
padding: 0px;
text-align: center;
width: 88px;
}
.win-commandBar-command-horiz img.commandIcon
{
height: 40px;
width: 40px;
}
.win-commandBar-command-vert
{
display: block;
float: none !important;
}
.win-commandBar-hostedCommand-horiz
{
display: inline;
}
.minimized .win-commandBar-rule-horiz
{
margin-bottom: 0px;
}
.win-commandBar-rule-vert
{
background-color: #707070;
height: 1px;
width: 100%;
}
.win-commandBar-rule-horiz
{
background-color: #707070;
border: 0px;
display: inline-block;
height: 40px;
margin: 10px 29px 21px 28px;
padding: 0px;
width: 1px;
}
.win-commandBar-tooltip
{
background-color: #FFFFFF;
border: 1px solid #2A2A2A;
display: inline-block;
max-width: 360px;
min-width: 200px;
padding: 3px 12px 6px 12px;
}
/*
This is the container for the tooltip heading, e.g. "Play Now (Ctrl+P)",
where "Play Now is the title and "(Ctrl+P)" is the shortcut.
*/
.win-commandBar-tooltip-heading
{
display: -ms-box;
overflow: hidden;
}
/*
This is the command title, which can use all of the extra space left once
the shortcut is rendered. If the title is too long to fit in that space
and the tooltip reaches its maximum width, the title is truncated with
an ellipsis.
*/
.win-commandBar-tooltip-title
{
-ms-box-flex: 1;
padding-right: 5px;
}
/*
This is an empty div that keeps the shortcut div pushed against the right
side of the title div.
*/
.win-commandBar-tooltip-flex
{
-ms-box-flex: 1000;
}
.win-commandBar-tooltip-description
{
line-height: 14px;
}
.win-tooltip
{
line-height: normal;
padding: 0px;
background-color: transparent;
border: none;
}
.win-appbar
{
line-height: normal;
}
.win-appbar[transparent='true']
{
background-color: transparent;
}
.win-commandBar-flyout
{
padding: 0px;
}

1821
JS/CommandBar/CommandBar.js Normal file

File diff suppressed because it is too large Load diff

26
JS/CommandBar/Flyout.css Normal file
View file

@ -0,0 +1,26 @@
.win-mediaFlyout
{
border: none;
line-height: normal;
padding: 0px;
}
.win-mediaFlyout-content
{
opacity: 0;
visibility: hidden;
z-index: 1001; /* Should be 1 higher than the background */
}
.win-mediaFlyout-background
{
background-color: rgba(0, 0, 0, 0);
background-image: url(Res/1x1.gif);
background-size: 100%;
height: 100vh;
left: 0;
top: 0;
visibility: hidden;
width: 100vw;
z-index: 1000; /* Z-index of AppBar is 999, flyout needs to be higher */
}

319
JS/CommandBar/Flyout.js Normal file
View file

@ -0,0 +1,319 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
/// <reference path="WinLib/Js/animations.js" />
/// <reference path="WinLib/Js/base.js" />
/// <reference path="WinLib/Js/ui.js" />
(function (WinNS) {
var Utilities = WinJS.Utilities;
var WinUI = WinJS.UI;
var Animation = WinJS.UI.Animation;
var elementIsInvalid = "Invalid argument: Control expects a valid DOM element as the first argument.";
var systemMargin = 20; // flyout cannot get closer than 45px to the edge of the screen
var Controls = WinJS.Namespace.defineWithParent(WinNS, "MediaApp.Controls", {
Anchor: {
topLeft: "topLeft",
topRight: "topRight",
bottomRight: "bottomRight",
bottomLeft: "bottomLeft"
},
Flyout: WinJS.Class.define(function (element, options) {
if (!element) {
throw new Error(elementIsInvalid);
}
// Configure host element
if (this === window || this === Controls) {
var flyout = WinUI.getControl(element);
if (flyout) {
return flyout;
} else {
return new Controls.Flyout(element, options);
}
}
// Attach the JS object to the host DOM element.
WinUI.setControl(element, this);
this._anchor = "topLeft";
this._content = null;
this._position = { x: 0, y: 0 };
this._element = element;
Utilities.addClass(this.element, "win-mediaFlyout");
// Process options
this.anchor = options.anchor;
this.position = options.position;
// Create UI elements
var that = this;
this._backgroundDiv = document.createElement("div");
this._backgroundDiv.className = "win-mediaFlyout-background";
this._backgroundDiv.style.position = "absolute";
this._backgroundDiv.addEventListener("click", function () {
that.dismiss();
}, false);
this._contentDiv = document.createElement("div");
this._contentDiv.className = "win-mediaFlyout-content";
this._contentDiv.role = "dialog";
this._contentDiv.setAttribute("aria-label", options.ariaLabel || "Dialog");
this._contentDiv.style.position = "absolute";
this._contentDiv.addEventListener("focus", function () {
that._fireEvent("focus", null);
}, false);
this._escPressed = function (event) {
if (event.key === "Esc") {
event.stopPropagation();
window.removeEventListener("keypress", arguments.callee, false);
that.dismiss();
}
};
this.element.appendChild(this._contentDiv);
this.element.appendChild(this._backgroundDiv);
},
{
// Public properties
element: {
get: function () {
return this._element;
}
},
content: {
get: function () {
return this._content;
},
set: function (val) {
var oldSize = { height: this.height, width: this.width };
if (this._content) {
document.body.appendChild(this._content);
}
this._content = val;
var newSize = { height: this.height, width: this.width };
this._fireEvent("contentupdate", null);
if (oldSize.height !== newSize.height ||
oldSize.width !== newSize.width) {
this._fireEvent("resize", null);
}
}
},
height: {
get: function () {
return this._content ? this._content.offsetHeight : 0;
}
},
width: {
get: function () {
return this._content ? this._content.offsetWidth : 0;
}
},
anchor: {
get: function () {
return this._anchor;
},
set: function (val) {
if (Controls.Anchor[val]) {
this._anchor = val;
}
}
},
position: {
get: function () {
return this._position;
},
set: function (val) {
if (val && typeof val.x === "number") {
this._position.x = val.x;
}
if (val && typeof val.y === "number") {
this._position.y = val.y;
}
}
},
// Public methods
show: function MediaFlyout_show() {
if (this._content) {
Utilities.empty(this._contentDiv);
this._contentDiv.appendChild(this._content);
var posX = 0,
posY = 0,
viewportWidth = window.innerWidth,
viewportHeight = window.innerHeight;
posX = this._position.x || 0;
posY = this._position.y || 0;
// Make sure the target position is within the margins
if (posX < systemMargin) {
posX = systemMargin;
} else if (posX > viewportWidth - systemMargin) {
posX = viewportWidth - systemMargin;
}
if (posY < systemMargin) {
posY = systemMargin;
} else if (posY > viewportHeight - systemMargin) {
posY = viewportHeight - systemMargin;
}
// Compute the upper left corner coords
switch (this._anchor) {
case Controls.Anchor.topRight:
posX -= this.width;
break;
case Controls.Anchor.bottomRight:
posX -= this.width;
posY -= this.height;
break;
case Controls.Anchor.bottomLeft:
posY -= this.height;
break;
}
// Ensure a good on-screen fit
if (this._anchor === Controls.Anchor.topLeft || this._anchor === Controls.Anchor.bottomLeft) {
if (posX + this.width > viewportWidth - systemMargin) {
// If it will fit, flip horizontally
if (posX - this.width > systemMargin) {
posX -= this.width;
} else {
// Otherwise, size the container and make it scroll
this._contentDiv.style.width = viewportWidth - posX - systemMargin + "px";
this._contentDiv.style.overflow = "auto";
}
}
}
if (this._anchor === Controls.Anchor.topLeft || this._anchor === Controls.Anchor.topRight) {
if (posY + this.height > viewportHeight - systemMargin) {
// If it will fit, flip vertically
if (posY - this.height > systemMargin) {
posY -= this.height;
} else {
// Otherwise, size the container and make it scroll
this._contentDiv.style.height = viewportHeight - posY - systemMargin + "px";
this._contentDiv.style.overflow = "auto";
}
}
}
if (this._anchor === Controls.Anchor.bottomLeft || this._anchor === Controls.Anchor.bottomRight) {
if (posY < systemMargin) {
// If it will fit, flip vertically
if (posY + this.height < viewportHeight - systemMargin) {
posY += this.height;
} else {
// Otherwise, size the container and make it scroll
this._contentDiv.style.height = posY - systemMargin + "px";
this._contentDiv.style.overflow = "auto";
}
}
}
if (this._anchor === Controls.Anchor.topRight || this._anchor === Controls.Anchor.bottomRight) {
if (posX < systemMargin) {
// If it will fit, flip horizontally
if (posX + this.width < viewportWidth - systemMargin) {
posX += this.width;
} else {
// Otherwise, size the container and make it scroll
this._contentDiv.style.width = posX - systemMargin + "px";
this._contentDiv.style.overflow = "auto";
}
}
}
this._contentDiv.style.left = posX + "px";
this._contentDiv.style.top = posY + "px";
this._contentDiv.style.opacity = 1;
this._contentDiv.style.visibility = "visible";
this._backgroundDiv.style.visibility = "visible";
var that = this;
window.addEventListener("keypress", that._escPressed, false);
Animation.showPopup(this._contentDiv, { top: "0px", left: "0px" })
.then(function () {
that._fireEvent("show", null);
});
}
},
dismiss: function MediaFlyout_dismiss() {
this._contentDiv.style.opacity = 0;
this._contentDiv.style.visibility = "hidden";
this._backgroundDiv.style.visibility = "hidden";
var that = this;
// TODO: restore once animations complete correctly
/// Animation.hidePopup(this._contentDiv, { top: "0px", left: "0px" })
/// .then(function () {
/// that._fireEvent("dismiss", null);
/// });
this._fireEvent("dismiss", null);
},
addEventListener: function MediaFlyout_addEventListener(type, listener, useCapture) {
this.element.addEventListener(type, listener, useCapture);
},
removeEventListener: function MediaFlyout_removeEventListener(type, listener, useCapture) {
this.element.removeEventListener(type, listener, useCapture);
},
// Private methods
// Raises an event to external listeners with the specified name and payload
_fireEvent: function MediaFlyout_fireEvent(eventName, payload) {
if (document.createEvent) {
var eventObject = document.createEvent("Event");
eventObject.initEvent(eventName, true, false);
if (payload !== undefined) {
eventObject.payload = payload;
}
this.element.dispatchEvent(eventObject);
}
}
})
});
})(WinJS);

9
JS/Global.js Normal file
View file

@ -0,0 +1,9 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function () {
// Define app namespace
WinJS.Namespace.define("Microsoft.Paint", {
});
})();

29
JS/KeyManager.js Normal file
View file

@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
"use strict";
function keyHandler(event) {
switch (event.keyCode) {
case 14: // ctrl-n: Clear/New canvas
AppNS.CanvasManager.clearCanvas();
break;
case 19: // ctrl-s: Save canvas
AppNS.CanvasManager.saveCanvas();
break;
case 25: // ctrl-y: Redo
AppNS.CanvasManager.redoCanvas();
break;
case 26: // ctrl-z: Undo
AppNS.CanvasManager.undoCanvas();
break;
}
console.log("Key Pressed: " + event.keyCode);
}
WinJS.Namespace.defineWithParent(AppNS, "KeyManager", {
keyHandler: keyHandler,
});
})(Microsoft.Paint);

41
JS/Main.js Normal file
View file

@ -0,0 +1,41 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
/// <reference path="ViewManager.js" />
(function (AppNS) {
"use strict";
var appLayout = Windows.UI.ViewManagement.ApplicationLayout.getForCurrentView();
var viewManager = null;
function activated(e) {
var Display = Windows.Graphics.Display;
Display.DisplayProperties.autoRotationPreferences = Display.DisplayOrientations.landscape | Display.DisplayOrientations.landscapeFlipped;
if (!AppNS.Utils.isLaunched) {
window.addEventListener("keypress", Microsoft.Paint.KeyManager.keyHandler);
viewManager = new AppNS.ViewManager(document.querySelector(".main-content"), AppNS.ViewCards);
viewManager.load(AppNS.ViewNames.PaintView);
WinJS.Namespace.defineWithParent(AppNS, "Utils", {
isLaunched: true
});
}
};
appLayout.addEventListener("layoutchanged", function (event) {
// Adding this to the end of the thread queue to give the window manager a chance to reset the window data.
msSetImmediate(function () {
viewManager.changeViewsLayout(event.layout);
});
});
Windows.UI.WebUI.WebUIApplication.addEventListener("suspending", function () {
viewManager.persistViewStates();
});
document.addEventListener("DOMContentLoaded", function () {
WinJS.UI.processAll();
});
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", activated);
WinJS.Application.start();
})(Microsoft.Paint);

80
JS/PaintView.js Normal file
View file

@ -0,0 +1,80 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
// <reference path="../WinJS/js/ui.js" />
(function (AppNS) {
"use strict";
var canvasBlobName = "canvasBlob";
function fragmentLoad(root, state) {
if (!state) {
state = {};
}
var canvasHost = root.querySelector(".canvas"), toolbarHost = root.querySelector(".toolbar");
canvasHost.innerHTML = "";
toolbarHost.innerHTML = "";
state.toolbarHeight = toolbarHost.offsetHeight;
state.canvasHeight = canvasHost.offsetHeight;
if (Windows.Graphics.Display.DisplayProperties.currentOrientation === Windows.Graphics.Display.DisplayOrientations.landscape ||
Windows.Graphics.Display.DisplayProperties.currentOrientation === Windows.Graphics.Display.DisplayOrientations.landscapeFlipped) {
state.canvasWidth = window.screen.width;
state.toolbarWidth = window.screen.width;
} else {
state.canvasWidth = window.screen.height;
state.toolbarWidth = window.screen.height;
}
state.canvasBorder = 20;
WinJS.UI.Fragments.clone("/Controls/Canvas/Canvas.html")
.then(function (frag) {
canvasHost.appendChild(frag);
AppNS.CanvasManager.fragmentLoad(canvasHost, state);
document.body.focus();
})
.then(function () {
return WinJS.UI.Fragments.clone("/Controls/Toolbar/Toolbar.html");
})
.then(function (frag) {
toolbarHost.appendChild(frag);
AppNS.ToolbarManager.fragmentLoad(toolbarHost, state);
document.body.focus();
});
};
function getViewData() {
var ToolbarManager = AppNS.ToolbarManager;
var CanvasManager = AppNS.CanvasManager;
var viewData = {
colorId: ToolbarManager.colorId,
toolName: ToolbarManager.toolName,
width: CanvasManager.toolWidth,
toolOptionValueIndex: ToolbarManager.optionValueIndex,
currentSizePreviewIndexes: ToolbarManager.currentSizePreviewIndexes,
currentOptionPreviewIndexes: ToolbarManager.currentOptionPreviewIndexes,
undoBlobNames: CanvasManager.undoBlobNames,
canvasBlobName: canvasBlobName
};
return viewData;
};
function getViewBlobs() {
var viewBlobs = AppNS.CanvasManager.undoBlobs;
viewBlobs[canvasBlobName] = AppNS.CanvasManager.canvasBlob;
return viewBlobs;
}
function changeLayout(newLayout) {
AppNS.ToolbarManager.changeLayout(newLayout);
AppNS.CanvasManager.changeLayout(newLayout);
};
WinJS.Namespace.defineWithParent(AppNS, "PaintView", {
fragmentLoad: fragmentLoad,
getViewData: getViewData,
getViewBlobs: getViewBlobs,
changeLayout: changeLayout
});
})(Microsoft.Paint);

35
JS/Sharing.js Normal file
View file

@ -0,0 +1,35 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
var _onDeferredBitmapRequested = function SharingHandler_onDeferredFileItemsRequested(sender, event) {
/// <summary>
/// Delayed handling provider for the bitmap.
/// </summary>
/// <param name='sender'>
/// Windows.ApplicationModel.DataTransfer.DataPackage object.
/// </param>
/// <param name='event'>
/// Windows.ApplicationModel.DataTransfer.DataProviderArgs object.
/// </param>
var stream = AppNS.CanvasManager.canvasBlob.msRandomAccessStream;
var deferral = event.deferral;
var dataPackage = deferral.dataPackage;
dataPackage.setBitmap(stream);
deferral.complete();
};
var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
dataTransferManager.addEventListener("datarequested", function (event) {
// Set sharing properties
var data = event.request.data;
data.properties.title = "My PaintPlay Drawing"; // TODO: Win8Apps WORK 92: Add localization support
data.properties.description = "Check out what I drew with PaintPlay!"; // TODO: Win8Apps WORK 92: Add localization support
data.setDataProvider(Windows.ApplicationModel.DataTransfer.StandardDataFormats.bitmap, function (sender, event) {
_onDeferredBitmapRequested(sender, event);
});
});
})(Microsoft.Paint);

194
JS/StateManager.js Normal file
View file

@ -0,0 +1,194 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
/// <reference path="Global.js"/>
/// <reference path="Utilities.js"/>
(function (AppNS) {
// Error strings for logging purposes
var invalidKeyError = "Invalid argument: The specified key is not a non-empty string.";
var invalidValueError = "Invalid argument: The specified value is not valid.";
var storeValueError = "Error storing value '{0}' for key '{1}': '{2}'";
var getValueError = "Error getting value for key '{0}': '{1}'";
var removeError = "Error removing key '{0}': '{1}'";
// Local scope objects
var emptyFunction = function () {};
var localSettings = Windows.Storage.ApplicationData.current.localSettings.values;
// Etw with default noop handlers
var etw = {
stateManagerStoreValueStart: emptyFunction,
stateManagerStoreValueEnd: emptyFunction,
stateManagerGetValueStart: emptyFunction,
stateManagerGetValueEnd: emptyFunction
};
function validateKey(key) {
/// <summary>
/// Check if the given key is a non-empty string
/// </summary>
return (typeof key === "string" && key !== "");
};
/// <summary>
/// Static methods for manipulating persisted states in key/value pairs
/// </summary>
WinJS.Namespace.defineWithParent(AppNS, "StateManager", {
storeValue: function (key, value) {
/// <summary>
/// Stores the given key/value pair
/// </summary>
/// <param name='key'>
/// The name of the key the value is associated with
/// </param>
/// <param name='value'>
/// The value to store
/// </param>
/// <returns>
/// true if successful; false otherwise.
/// </returns>
if (!validateKey(key)) {
throw new Error(invalidKeyError);
}
if (value === undefined || value === null) {
throw new Error(invalidValueError);
}
etw.stateManagerStoreValueStart(key);
var succeeded = false;
try {
var valueToStore = "";
if (typeof value === "object") {
valueToStore = JSON.stringify(value);
} else {
valueToStore = value.toString();
}
localSettings.insert(key, valueToStore);
succeeded = true;
} catch (error) {
window.console.log("StateManager.storeValue", storeValueError.format([value, key, error]));
}
etw.stateManagerStoreValueEnd(key);
return succeeded;
},
getValueAsString: function (key) {
/// <summary>
/// Retrieves the value for the given key
/// </summary>
/// <param name='key'>
/// The name of the key to retrieve the value
/// </param>
/// <returns>
/// The string value associated with the given key,
/// or null if the key is not found or error.
/// </returns>
if (!validateKey(key)) {
throw new Error(invalidKeyError);
}
etw.stateManagerGetValueStart(key);
var value = null;
try {
value = localSettings.lookup(key);
} catch (error) {
window.console.log("StateManager.getValueAsString", getValueError.format([key, error]));
}
etw.stateManagerGetValueEnd(key);
return value;
},
getValueAsObject: function (key) {
/// <summary>
/// Retrieves the value for the given key and returns it as a JSON object
/// </summary>
/// <param name='key'>
/// The name of the key to retrieve the value
/// </param>
/// <returns>
/// The JSON value associated with the given key,
/// or null if the key is not found or error.
/// </returns>
if (!validateKey(key)) {
throw new Error(invalidKeyError);
}
etw.stateManagerGetValueStart(key);
var value = null;
try {
value = JSON.parse(localSettings.lookup(key));
} catch (error) {
window.console.log("StateManager.getValueAsObject", getValueError.format([key, error]));
}
etw.stateManagerGetValueEnd(key);
return value;
},
remove: function (key) {
/// <summary>
/// Removes the given key from the store
/// </summary>
/// <param name='key'>
/// The name of the key to be removed
/// </param>
/// <returns>
/// true if the key is successfully removed or not present; false otherwise.
/// </returns>
if (!validateKey(key)) {
throw new Error(invalidKeyError);
}
var succeeded = false;
try {
localSettings.remove(key);
succeeded = true;
} catch (error) {
window.console.log("StateManager.remove", removeError.format([key, error]));
}
return succeeded;
},
clear: function () {
/// <summary>
/// Clear all settings
/// </summary>
localSettings.clear();
},
init: function (etwProvider) {
/// <summary>
/// Initializes state manager
/// </summary>
/// <param name='etwProvider'>
/// etwProvider is a reference to the ETW provider for logging events.
/// </param>
if (etwProvider) {
etw.stateManagerStoreValueStart = etwProvider.stateManagerStoreValueStart || etw.stateManagerStoreValueStart;
etw.stateManagerStoreValueEnd = etwProvider.stateManagerStoreValueEnd || etw.stateManagerStoreValueEnd;
etw.stateManagerGetValueStart = etwProvider.stateManagerGetValueStart || etw.stateManagerGetValueStart;
etw.stateManagerGetValueEnd = etwProvider.stateManagerGetValueEnd || etw.stateManagerGetValueEnd;
}
}
});
})(Microsoft.Paint);

59
JS/Tiles.js Normal file
View file

@ -0,0 +1,59 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
var Notifications = Windows.UI.Notifications;
WinJS.Namespace.defineWithParent(AppNS, "Tiles", {
setCurrentCanvasAsTile: function () {
/// <summary>
/// Sets the tile to the current content of the canvas
/// </summary>
var fileName = "canvasImage.png";
var altText = "canvas image"; // TODO: Win8Apps WORK 92: Add localization support
// Get wide image template
var tileXml = Notifications.TileUpdateManager.getTemplateContent(Notifications.TileTemplateType.tileWideImage);
function configureTileImage(tileXml, fileName) {
var tileImageAttributes = tileXml.getElementsByTagName("image");
tileImageAttributes[0].setAttribute("src", "localfolder://" + fileName);
tileImageAttributes[0].setAttribute("alt", altText);
}
// Get scaled canvas blob with 20% height and width
var scaledCanvasBlob = AppNS.CanvasManager.getScaledCanvasBlob(document.getElementById("paintCanvas").height * 0.2, document.getElementById("paintCanvas").width * 0.2);
// Write canvas blob to local folder
AppNS.Utils.writeBlobToLocalFolderAsync(scaledCanvasBlob, fileName).then(function (file) {
// Set image attribute
configureTileImage(tileXml, file.fileName);
// Get square template
var squareTileXml = Notifications.TileUpdateManager.getTemplateContent(Notifications.TileTemplateType.tileSquareImage);
// Set square image attribute
configureTileImage(squareTileXml, file.fileName);
// Include the square template into the notification
var node = tileXml.importNode(squareTileXml.getElementsByTagName("binding").item(0), true);
tileXml.getElementsByTagName("visual").item(0).appendChild(node);
// Create the notification from the XML
var tileNotification = new Notifications.TileNotification(tileXml);
// Send the notification to the app's default tile
Notifications.TileUpdateManager.createTileUpdaterForApplication().update(tileNotification);
}, function () { });
},
clearTile: function () {
/// <summary>
/// Returns tile to the default
/// </summary>
Notifications.TileUpdateManager.createTileUpdaterForApplication().clear();
}
});
})(Microsoft.Paint);

39
JS/Utils.js Normal file
View file

@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (AppNS) {
WinJS.Namespace.defineWithParent(AppNS, "Utils", {
writeBlobToLocalFolderAsync: function (blob, filename) {
/// <summary>
/// Writes a blob to the local applicaton folder
/// </summary>
/// <param name='blob'>
/// Blob object to be saved
/// </param>
/// <param name='filename'>
/// String representing the name of the output file
/// </param>
return new WinJS.Promise(function (complete, error) {
// Create file
Windows.Storage.ApplicationData.current.localFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting)
.then(function (file) {
// Open the returned file in order to copy the data
file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {
var output = stream.getOutputStreamAt(0);
// Get the IInputStream stream from the blob object
var input = blob.msRandomAccessStream.getInputStreamAt(0);
// Copy the stream from the blob to the File stream
Windows.Storage.Streams.RandomAccessStream.copy(input, output);
output.flushAsync().then(function () {
complete(file);
}, error);
}, error);
}, error);
});
}
});
})(Microsoft.Paint);

19
JS/ViewCards.js Normal file
View file

@ -0,0 +1,19 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
(function (BaseNS) {
WinJS.Namespace.defineWithParent(BaseNS, "Paint", {
ViewNames: {
PaintView: "PaintView",
SnapView: "SnapView"
},
});
WinJS.Namespace.defineWithParent(BaseNS, "Paint", {
ViewCards: {
PaintView: { uri: "/HTML/PaintView.html", setupFunction: "Microsoft.Paint.PaintView.fragmentLoad", namespace: "Microsoft.Paint.PaintView" },
SnapView: { uri: "/HTML/SnapView.html", setupFunction: "Microsoft.Paint.SnapView.fragmentLoad", namespace: "Microsoft.Paint.PaintView" }
}
});
})(Microsoft);

108
JS/ViewManager.js Normal file
View file

@ -0,0 +1,108 @@
////////////////////////////////////////////////////////////
//// © Microsoft. All rights reserved. ////
////////////////////////////////////////////////////////////
/// <reference path="../WinJS/js/base.js" />
/// <reference path="../WinJS/js/ui.js" />
(function (BaseNS) {
var AppNS = WinJS.Namespace.defineWithParent(BaseNS, "Paint", {
ViewManager: WinJS.Class.define(function (host, views) {
this._host = host;
this._loadedViews = [];
if (typeof views === "object") {
this._views = views;
} else {
throw new Error("views parameter must be object");
}
},
{
// Public members
load: function(view, state) {
/// <summary>
/// Load a view into the main section
/// </summary>
/// <param name='view'>
/// String key for the view to be loaded
/// </param>
/// <param name='state' optional='true'>
/// State object to be passed to the view
/// </param>
if (this._views[view]) {
var that = this;
if (this._views[view].uri) {
WinJS.UI.Fragments.clone(this._views[view].uri, state)
.then(function (frag) {
that._host.appendChild(frag);
if(that._views[view].setupFunction) {
var setup = WinJS.Utilities.getMember(that._views[view].setupFunction, null);
var persistedData = AppNS.StateManager.getValueAsObject(view);
setup(that._host, persistedData);
that._loadedViews.push(view);
}
document.body.focus();
});
} else {
throw new Error("View does not have a uri property");
}
} else {
throw new Error("View is not defined in the view list");
}
},
persistViewStates: function () {
/// <summary>
/// Persists the loaded view states
/// </summary>
var persistedData = {};
for (var viewIndex in this._loadedViews) {
var view = this._loadedViews[viewIndex];
var viewNamespace = WinJS.Utilities.getMember(this._views[view].namespace);
if (viewNamespace) {
var getViewData = viewNamespace.getViewData;
var getViewBlobs = viewNamespace.getViewBlobs;
if (getViewData && typeof getViewData === "function") {
var viewBlobs = getViewBlobs();
var viewData = getViewData();
// Write blobs to local storage
for (var blob in viewBlobs) {
AppNS.Utils.writeBlobToLocalFolderAsync(viewBlobs[blob], blob)
.then(function () { }, function () { });
}
// Persist data
AppNS.StateManager.storeValue(view, viewData);
} else {
throw new Error("View does not implement getViewData function");
}
} else {
throw new Error("Invalid namespace for view");
}
}
},
changeViewsLayout: function (newLayout) {
/// <summary>
/// Changes the layout that the views are displaying
/// </summary>
for (var viewIndex in this._loadedViews) {
var view = this._loadedViews[viewIndex];
var viewNamespace = WinJS.Utilities.getMember(this._views[view].namespace);
if (viewNamespace) {
var changeLayout = viewNamespace.changeLayout;
if (changeLayout && typeof changeLayout === "function") {
changeLayout(newLayout);
} else {
throw new Error("View does not implement changeLayout function");
}
} else {
throw new Error("Invalid namespace for view");
}
}
}
}
)});
})(Microsoft);

10
JSCop.targets Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild" Condition="$(RunJSCop) == 'true'">
<ItemGroup>
<JSItems Include="@(Content)" Condition="%(Content.Extension)=='.js' AND %(Content.JSCOP) != 'false'"/>
</ItemGroup>
<Message Text="JSItems = @(JSItems, ',')" Importance="high"/>
<Exec Command="\\bpt-scratch\JSCop\Win8Current\bin\js50.exe analyze /disable:JS2026,JS2045,JS2073,JS2074,JS2076,JS3054,JS3056,JS3057,JS3058,JS3092 @(JSItems->'/file:%(FullPath)', ' ')" />
</Target>
</Project>

BIN
Res/brushIcon40px.hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/brushIcon40px.press.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/brushIcon40px.rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
Res/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
Res/moreIcon40px.hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/moreIcon40px.press.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
Res/moreIcon40px.rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/newIcon40px.hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

BIN
Res/newIcon40px.press.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

BIN
Res/newIcon40px.rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Res/optionIcon40px.rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
Res/sizeIcon40px.hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/sizeIcon40px.press.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Res/sizeIcon40px.rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/smallLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
Res/splashScreen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
Res/storeLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

BIN
Res/undoIcon40px.hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
Res/undoIcon40px.press.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Res/undoIcon40px.rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
Res/wideLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

2093
WinJS/Css/ui-dark.css Normal file

File diff suppressed because it is too large Load diff

2102
WinJS/Css/ui-light.css Normal file

File diff suppressed because it is too large Load diff

1296
WinJS/js/animations.js Normal file

File diff suppressed because it is too large Load diff

1482
WinJS/js/base.js Normal file

File diff suppressed because it is too large Load diff

1347
WinJS/js/binding.js Normal file

File diff suppressed because it is too large Load diff

5621
WinJS/js/controls.js vendored Normal file

File diff suppressed because it is too large Load diff

228
WinJS/js/res.js Normal file
View file

@ -0,0 +1,228 @@
/// <loc filename="metadata\res_loc_oam.xml" format="messagebundle" />
/// <reference path='base.js' />
/*
© Microsoft. All rights reserved.
This library is supported for use in Windows Tailored Apps only.
Build: 6.2.8093.0
Version: 0.5
*/
(function (WinJS, undefined) {
var readyComplete = false;
var resourceMap;
var resourceLoader;
function processAllImpl(rootElement) {
WinJS.Resources._processAllImpl(rootElement);
return WinJS.Promise.wrap();
}
WinJS.Namespace.defineWithParent(WinJS, "Resources", {
_parseResourceSyntax: function (str){
var objs = [];
var chunks = str.split(";");
for(var i = 0, l = chunks.length; i < l; i++){
var chunk = chunks[i];
if(chunk.trim() !== ""){
var index = chunk.indexOf(":");
if (index !== -1){
var prop = chunk.substring(0, index);
var ref = chunk.substring(index + 1);
objs.push({destination: prop.trim(), source: ref.trim() });
}else {
if (WinJS.validation){
this._throwError("InvalidMarkup");
}
}
}
}
return objs;
},
_throwError : function(errorId) {
var hardCodedErrors = {
"InvalidMarkup":"Invalid markup",
"FailToFindItem":"Fail to find item:{0}",
"UndefinedProperty":"Undefined property name:{0}",
"InvalidValueForProperty":"Invalid value:[{0}] for given property:[{1}]",
"TooDeepLoop":"Nested loop more than {0} is not supported",
"NoItem":"no resource for given source: {0}",
"NoActionAllowed":"action is not allowed in the data-win-res syntax"
};
var message = hardCodedErrors[errorId];
if (message) {
for (var i = 1, l = arguments.length; i < l; i++){
message = message.replace("{" + (i-1) + "}", arguments[i]);
}
}else {
message = "unknown error";
}
throw message;
},
_setMember: function (props, root, data) {
var parts = props.split(".");
var ob = root;
var prop = parts[0];
for (var i = 1, len = parts.length; i < len; i++) {
if (ob[parts[ i-1]] === undefined) {
ob[parts[i-1] ] = {} ;
}
ob = ob[parts[i-1]] ;
prop = parts[i];
}
ob[prop] = data.value;
if ((data.lang !== undefined) &&
(ob.lang !== undefined) &&
(ob.lang !== data.lang) ) {
ob.lang = data.lang;
}
},
_getString : function (key) {
/// <summary locid="1">
/// Search resources through MRT resources
/// </summary>
/// <param name="key" locid="2">
/// Requested resource id for searching
/// </param>
if (!resourceLoader){
if (window.Windows && Windows.ApplicationModel && Windows.ApplicationModel.Resources) {
resourceLoader = new Windows.ApplicationModel.Resources.ResourceLoader();
}
}
return resourceLoader && resourceLoader.getString(key);
},
_getValue : function (key) {
/// <summary>
/// Search resources through MRT resources
/// </summary>
/// <param name='key'>
/// Requested resource id for searching
/// </param>
if (!resourceMap){
if (window.Windows && Windows.ApplicationModel && Windows.ApplicationModel.Resources) {
var mainResourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.current.mainResourceMap;
resourceMap = mainResourceMap.getSubtree('Resources');
}
}
if (resourceMap){
var resCandidate = resourceMap.getValue(key);
var langValue = "";
var qualifiers = resCandidate.qualifiers;
for (var i = 0, len = resCandidate.qualifiers.size; i < len; i++){
if (qualifiers[i].qualifierName === "Language"){
langValue = qualifiers[i].qualifierValue;
break;
}
}
return {value:resCandidate.toString(), lang:langValue};
}
},
_processAllImpl: function(rootElement, count){
rootElement = rootElement || document.body;
var count = count || 0;
if (count < 4) {
var elements = rootElement.querySelectorAll('[data-win-res]');
if (count == 0) {
if (rootElement.getAttribute) {
var elem = rootElement.getAttribute('data-win-res');
if (elem) {
elements.push(elem);
}
}
}
if (elements.length === 0) {
return;
}
for (var i = 0, len = elements.length; i < len; i++) {
var e = elements[i];
var decls = this._parseResourceSyntax(e.getAttribute('data-win-res'));
for (var k = 0, l = decls.length ; k < l; k++){
var decl = decls[k];
var data = false;
try {
data = this._getValue(decl.source);
} catch(err) {
if (WinJS.validation) {
throw err;
}
}
if (data) {
this._setMember(decl.destination, e, data);
if (decl.destination === "innerHTML") {
this._processAllImpl(e, count + 1);
}
}else {
if (WinJS.validation) {
this._throwError("NoItem", decl.source);
}
}
}
}
}
else if (WinJS.validation){
this._throwError("TooDeepLoop", 3);
}
},
processAll: function (rootElement) {
/// <summary locid="3">
/// Process resources tag that reads its syntax and replace strings
/// with localized strings
/// </summary>
/// <param name="rootElement" locid="4">
/// Element to start searching at, if not specified, the entire document is searched.
/// </param>
if (!readyComplete) {
return WinJS.Utilities.ready().then(function () {
readyComplete = true;
return processAllImpl(rootElement);
});
}
else {
return processAllImpl(rootElement);
}
}
});
})(WinJS);

2929
WinJS/js/ui.js Normal file

File diff suppressed because it is too large Load diff

17673
WinJS/js/uicollections.js Normal file

File diff suppressed because it is too large Load diff

716
WinJS/js/wwaapp.js Normal file
View file

@ -0,0 +1,716 @@
/// <loc filename="metadata\wwaapp_loc_oam.xml" format="messagebundle" />
/// <reference path='base.js' />
/// <reference path='wwaapp.js' />
/// <reference winrt='true' />
/*
© Microsoft. All rights reserved.
This library is supported for use in Windows Tailored Apps only.
Build: 6.2.8093.0
Version: 0.5
*/
(function (global, WinJS, undefined) {
var checkpointET = "checkpoint",
unloadET = "unload",
mainwindowactivatedET = "mainwindowactivated",
activatedET = "activated",
loadedET = "loaded",
readyET = "ready",
errorET = "error";
var pendingDrain;
function dispatchEvent(eventRecord) {
var promise = WinJS.Promise.as();
eventRecord.setPromise = function (p) {
promise = promise.then(function() { return p; });
};
eventRecord.detail = eventRecord.detail || {};
if (typeof(eventRecord.detail) === "object") {
eventRecord.detail.setPromise = eventRecord.setPromise;
}
try {
if (listeners._listeners) {
l = listeners._listeners[eventRecord.type];
if (l) {
l.forEach(function dispatchOne(e) { e.listener(eventRecord); });
}
}
// Fire built in listeners last, for checkpoint this is important
// as it lets our built in serialization see any mutations to
// app.sessionState
//
var l = builtInListeners[eventRecord.type];
if (l) {
l.forEach(function dispatchOne(e) { e(eventRecord); });
}
}
catch (err) {
queueEvent({type:errorET, detail:err});
}
return promise.then(function() {
if (eventRecord._deferral) {
eventRecord._deferral.complete();
}
});
}
function drainQueue(queue) {
pendingDrain = true;
if (queue.length === 0) {
if (eventQueue.length > 0) {
return drainQueue(copyAndClearQueue());
}
pendingDrain = false;
return WinJS.Promise.as(queue);
}
function drainNext() {
return drainQueue(queue.slice(1));
}
function drainError(err) {
queueEvent({type:errorET, detail:err});
return drainNext();
}
return dispatchEvent(queue[0]).
then(drainNext, drainError);
}
function queueEvent(eventRecord) {
/// <summary locid="1">
/// Queue an event to be processed by the WinJS.Application
/// </summary>
/// <param name="eventRecord" type="object" locid="2">
/// The event record is expected to have a type property which will be
/// used as the event name when dispatching on the WinJS.Application
/// event queue. The entire object will be provided to event listeners
/// in the detail property of the event.
/// </param>
eventQueue.push(eventRecord);
if (running && !pendingDrain) {
drainQueue(copyAndClearQueue());
}
}
function copyAndClearQueue() {
var queue = eventQueue;
eventQueue = [];
return queue;
}
var ListenerType = WinJS.Class.mix(WinJS.Class.define(null), WinJS.Utilities.eventMixin);
var listeners = new ListenerType();
var builtInListeners = {
mainwindowactivated: [
function (e) {
queueEvent({type: activatedET, detail: e.detail});
}
],
activated: [
function () {
queueEvent({ type: readyET });
}
],
checkpoint: [
function(e) {
// comes from state.js
WinJS.Application._oncheckpoint(e);
}
]
};
var eventQueue = [ ];
var running = false;
// loaded == DOMContentLoaded
// mainwindowactivated == after WinRT Activated
// ready == after all of the above
//
var useWinRT = false;
if (window.Windows && Windows.UI) {
useWinRT = true;
var wui = Windows.UI.WebUI.WebUIApplication;
wui.addEventListener("activated", function (e) {
WinJS.Application._loadState(e).then(function () {
queueEvent({type: mainwindowactivatedET, detail: e});
});
});
function suspendingHandler(e) {
WinJS.Application.queueEvent({type:checkpointET, _deferral: e.suspendingOperation.getDeferral() });
}
wui.addEventListener("suspending", suspendingHandler, false);
}
document.addEventListener("DOMContentLoaded", function (e) {
queueEvent({ type: loadedET });
if (!useWinRT) {
var activatedArgs = {
arguments: "",
kind: "Windows.Launch",
previousExecutionState: 0 //Windows.ApplicationModel.Activation.ApplicationExecutionState.NotRunning
// UNDONE: tileId: e.tileId,
// UNDONE: splashScreen: e.splashScreen,
};
WinJS.Application._loadState(activatedArgs).then(function () {
queueEvent({ type: mainwindowactivatedET, detail:activatedArgs});
});
}
}, false);
window.addEventListener("beforeunload", function (e) {
queueEvent({type:checkpointET});
queueEvent({type:unloadET});
}, false);
WinJS.Namespace.defineWithParent(WinJS, "Application", {
stop: function() {
/// <summary locid="3">
/// Stop application event processing and reset the WinJS.Application
/// to its initial state
/// </summary>
listeners = new ListenerType();
running = false;
sawActivated = false;
sawLoaded = false;
queuedReady = false;
copyAndClearQueue();
},
addEventListener: function (eventType, listener, capture) {
/// <summary locid="4">
/// Adds an event listener to the control.
/// </summary>
/// <param name="eventType" locid="5">
/// The type (name) of the event.
/// </param>
/// <param name="listener" locid="6">
/// The listener to invoke when the event gets raised.
/// </param>
/// <param name="capture" locid="7">
/// Specifies whether or not to initiate capture.
/// </param>
listeners.addEventListener(eventType, listener, capture);
},
removeEventListener: function (eventType, listener, capture) {
/// <summary locid="8">
/// Removes an event listener from the control.
/// </summary>
/// <param name="eventType" locid="5">
/// The type (name) of the event.
/// </param>
/// <param name="listener" locid="9">
/// The listener to remove from the invoke list.
/// </param>
/// <param name="capture" locid="7">
/// Specifies whether or not to initiate capture.
/// </param>
listeners.removeEventListener(eventType, listener, capture);
},
checkpoint: function() {
/// <summary locid="10">
/// Queue a checkpoint event
/// </summary>
queueEvent({type:checkpointET});
},
start: function () {
/// <summary locid="11">
/// Start processing items in the WinJS.Application event queue
/// </summary>
var queue = copyAndClearQueue();
running = true;
drainQueue(queue);
},
queueEvent : queueEvent
});
Object.defineProperties(WinJS.Application, WinJS.Utilities.createEventProperties(checkpointET, unloadET, mainwindowactivatedET, activatedET, loadedET, readyET));
})(this, WinJS);
(function (WinJS, undefined) {
var navigatedEventName = "navigated";
var navigatingEventName = "navigating";
var beforenavigateEventName = "beforenavigate";
var ListenerType = WinJS.Class.mix(WinJS.Class.define(null), WinJS.Utilities.eventMixin);
var listeners = new ListenerType();
var history = {
backStack: [],
current: {location:"", initialPlaceholder: true},
forwardStack: []
};
var raiseBeforeNavigate = function (proposed) {
return WinJS.Promise.as().
then(function () {
var promise = WinJS.Promise.as();
var defaultPrevented = listeners.dispatchEvent(beforenavigateEventName, {
setPromise: function(p) { promise = p; },
location: proposed.location,
state: proposed.state
});
return promise.then(function beforeNavComplete() {
return defaultPrevented;
});
});
};
var raiseNavigating = function (delta) {
return WinJS.Promise.as().
then(function () {
var promise = WinJS.Promise.as();
listeners.dispatchEvent(navigatingEventName, {
setPromise: function(p) { promise = p; },
location: history.current.location,
state: history.current.state,
delta: delta
});
return promise;
});
};
var raiseNavigated = function(value, err) {
var promise = WinJS.Promise.as();
var detail = {
value: value,
location: history.current.location,
state: history.current.state,
setPromise: function(p) { promise = p; }
};
if (!value && err) {
detail.error = err;
}
listeners.dispatchEvent(navigatedEventName, detail);
return promise;
};
var go = function (distance, fromStack, toStack, delta) {
distance = Math.min(distance, fromStack.length);
if (distance > 0) {
return raiseBeforeNavigate(fromStack[fromStack.length-distance]).
then(function goBeforeCompleted(cancel) {
if (!cancel) {
toStack.push(history.current);
while (distance-1 != 0) {
distance--;
toStack.push(fromStack.pop());
}
history.current = fromStack.pop();
return raiseNavigating(delta).then(
raiseNavigated,
function (err) {
raiseNavigated(undefined, err || true);
throw err;
}).then(function() { return true; });
}
else {
return false;
}
});
}
return WinJS.Promise.wrap(false);
}
WinJS.Namespace.defineWithParent(WinJS, "Navigation", {
/// <field name="state" type="Boolean" locid="12">
/// True if we can navigate forwards
/// </field>
canGoForward: {
get: function () {
return history.forwardStack.length > 0;
}
},
/// <field name="state" type="Boolean" locid="13">
/// True if we can navigate backwards
/// </field>
canGoBack: {
get: function () {
return history.backStack.length > 0;
}
},
/// <field name="state" locid="14">
/// Current location
/// </field>
location: {
get: function () {
return history.current.location;
}
},
/// <field name="state" locid="15">
/// Navigation state
/// </field>
state: {
get: function () {
return history.current.state;
},
set: function (value) {
history.current.state = value;
}
},
/// <field name="history" locid="16">
/// Navigation history
/// </field>
history: {
get: function() {
return history;
},
set: function(value) {
var s = history = value;
// ensure the require fields are present
//
s.backStack = s.backStack || [];
s.forwardStack = s.forwardStack || [];
s.current = s.current || {location:"", initialPlaceholder:true};
s.current.location = s.current.location || "";
}
},
forward: function(distance) {
/// <summary locid="17">
/// Navigate forwards
/// </summary>
/// <param name="distance" type="Number" optional="true" locid="18">
/// The number of entries forward to go
/// </param>
/// <returns type="Promise" locid="19">
/// Promise which is completed with a Boolean value indicating whether or not
/// the navigation was successful
/// </returns>
distance = distance || 1;
return go(distance, history.forwardStack, history.backStack, distance);
},
back: function(distance) {
/// <summary locid="20">
/// Navigate backwards
/// </summary>
/// <param name="distance" type="Number" optional="true" locid="21">
/// The number of entries back into the history to go
/// </param>
/// <returns type="Promise" locid="19">
/// Promise which is completed with a Boolean value indicating whether or not
/// the navigation was successful
/// </returns>
distance = distance || 1;
return go(distance, history.backStack, history.forwardStack, -distance);
},
navigate: function (location, initialState) {
/// <summary locid="22">
/// Navigate to a location
/// </summary>
/// <param name="location" locid="23">
/// The location to navigate to. Generally the location is a string, but
/// it may be anything.
/// </param>
/// <param name="initialState" locid="24">
/// Navigation state which may be accessed through WinJS.Navigation.state
/// </param>
/// <returns type="Promise" locid="19">
/// Promise which is completed with a Boolean value indicating whether or not
/// the navigation was successful
/// </returns>
var proposed = { location:location, state: initialState };
return raiseBeforeNavigate(proposed).
then(function navBeforeCompleted(cancel) {
if (!cancel) {
if (!history.current.initialPlaceholder) {
history.backStack.push(history.current);
}
history.forwardStack = [];
history.current = proposed;
// error or no, we go from navigating -> navigated
// cancelation should be handled with "beforenavigate"
//
return raiseNavigating().then(
raiseNavigated,
function (err) {
raiseNavigated(undefined, err || true);
throw err;
}).then(function () { return true; });
}
else {
return false;
}
});
},
addEventListener: function (eventType, listener, capture) {
/// <summary>
/// Adds an event listener to the control.
/// </summary>
/// <param name='eventType'>
/// The type (name) of the event.
/// </param>
/// <param name='listener'>
/// The listener to invoke when the event gets raised.
/// </param>
/// <param name='capture'>
/// Specifies whether or not to initiate capture.
/// </param>
listeners.addEventListener(eventType, listener, capture);
},
removeEventListener: function (eventType, listener, capture) {
/// <summary>
/// Removes an event listener from the control.
/// </summary>
/// <param name='eventType'>
/// The type (name) of the event.
/// </param>
/// <param name='listener'>
/// The listener to remove from the invoke list.
/// </param>
/// <param name='capture'>
/// Specifies whether or not to initiate capture.
/// </param>
listeners.removeEventListener(eventType, listener, capture);
}
});
Object.defineProperties(WinJS.Navigation, WinJS.Utilities.createEventProperties(navigatedEventName, navigatingEventName, beforenavigateEventName));
})(WinJS);
(function () {
function initWithWinRT() {
var sto = Windows.Storage;
var local, temp, roaming;
var IOHelper = WinJS.Class.define(
function (folder) {
this.folder = folder;
this._path = folder.path;
}, {
exists: function (fileName) {
/// <summary locid="25">
/// Determines if the specified file exists in the container
/// </summary>
/// <param name="fileName" type="String" locid="26">
/// The file which may exist within this folder
/// </param>
/// <returns locid="27">
/// Promise with either true (file exists) or false.
/// </returns>
return this.folder.getFileAsync(fileName).
then(
function () { return true; },
function () { return false; }
);
},
remove: function (fileName) {
/// <summary locid="28">
/// Delets a file in the container
/// </summary>
/// <param name="fileName" type="String" locid="29">
/// The file to be deleted
/// </param>
/// <returns locid="30">
/// Promise which is fulfilled when the file has been deleted
/// </returns>
var that = this;
return that.folder.getFileAsync(fileName).
then(
function (fileItem) {
return fileItem.deleteAsync();
},
function() { return false; }
);
},
writeText: function (fileName, str) {
/// <summary locid="31">
/// Writes a file to the container with the specified text
/// </summary>
/// <param name="fileName" type="String" locid="32">
/// The file to write to
/// </param>
/// <param name="str" type="String" locid="33">
/// Content to be written to the file
/// </param>
/// <returns locid="34">
/// Promise with the count of characters written
/// </returns>
var that = this;
return that.folder.createFileAsync(fileName, sto.CreationCollisionOption.replaceExisting).
then(function (fileItem) {
return fileItem.openAsync(sto.FileAccessMode.readWrite);
}).then(function (randomAccessStream) {
var outputStream = randomAccessStream.getOutputStreamAt(0);
var writer = new Windows.Storage.Streams.DataWriter(outputStream);
var count = writer.writeString(str);
return writer.storeAsync().then(function() {
return outputStream.flushAsync().then(function() {
return count;
});
});
});
},
readText: function (fileName, def) {
/// <summary locid="35">
/// Reads the contents of a file from the container, if the file
/// doesn't exist, def is returned.
/// </summary>
/// <param name="fileName" type="String" locid="36">
/// The file to read from
/// </param>
/// <param name="def" type="String" locid="37">
/// Default value to be returned if the file failed to open
/// </param>
/// <returns locid="38">
/// Promise containing the contents of the file, or def.
/// </returns>
var that = this;
function onerror() { return def; }
return that.folder.getFileAsync(fileName).
then(function (fileItem) {
return fileItem.openAsync(sto.FileAccessMode.read).
then(function (randomAccessStream) {
var reader = new Windows.Storage.Streams.DataReader(randomAccessStream.getInputStreamAt(0));
var size = randomAccessStream.size;
return reader.loadAsync(size).then(function () {
var fileContents = reader.readString(size);
return (fileContents);
}, onerror);
}, onerror);
}, onerror);
}
});
WinJS.Namespace.define("WinJS.Application", {
local: { get: function() {
if (!local) {
local = new IOHelper(sto.ApplicationData.current.localFolder);
}
return local;
}},
temp: { get: function() {
if (!temp) {
temp = new IOHelper(sto.ApplicationData.current.temporaryFolder);
}
return temp;
}},
roaming: { get: function() {
if (!roaming) {
roaming = new IOHelper(sto.ApplicationData.current.roamingFolder);
}
return roaming;
}}
});
};
function initWithStub() {
var InMemoryHelper = WinJS.Class.define(
function () {
this.storage = {};
}, {
exists: function (fileName) {
/// <summary locid="25">
/// Determines if the specified file exists in the container
/// </summary>
/// <param name="fileName" type="String" locid="39">
/// The filename which may exist within this folder
/// </param>
/// <returns locid="27">
/// Promise with either true (file exists) or false.
/// </returns>
// force conversion to boolean
//
return WinJS.Promise.as(this.storage[fileName] !== undefined);
},
remove: function (fileName) {
/// <summary>
/// Delets a file in the container
/// </summary>
/// <param name='fileName' type='String'>
/// The file to be deleted
/// </param>
/// <returns>
/// Promise which is fulfilled when the file has been deleted
/// </returns>
delete this.storage[fileName];
return WinJS.Promise.as();
},
writeText: function (fileName, str) {
/// <summary locid="31">
/// Writes a file to the container with the specified text
/// </summary>
/// <param name="fileName" type="String" locid="40">
/// The filename to write to
/// </param>
/// <param name="str" type="String" locid="33">
/// Content to be written to the file
/// </param>
/// <returns locid="34">
/// Promise with the count of characters written
/// </returns>
this.storage[fileName] = str;
return WinJS.Promise.as(str.length);
},
readText: function (fileName, def) {
/// <summary locid="35">
/// Reads the contents of a file from the container, if the file
/// doesn't exist, def is returned.
/// </summary>
/// <param name="fileName" type="String" locid="41">
/// The filename to read from
/// </param>
/// <param name="def" type="String" locid="37">
/// Default value to be returned if the file failed to open
/// </param>
/// <returns locid="38">
/// Promise containing the contents of the file, or def.
/// </returns>
return WinJS.Promise.as(this.storage[fileName] || def);
}
}
);
WinJS.Namespace.define("WinJS.Application", {
local: new InMemoryHelper(),
temp: new InMemoryHelper(),
roaming: new InMemoryHelper()
});
}
if (window.Windows && Windows.Storage && Windows.Storage.ApplicationData) {
initWithWinRT();
}
else {
initWithStub();
}
WinJS.Namespace.define("WinJS.Application", {
sessionState: { value: {}, writable: true, enumerable: true },
_loadState: function (e) {
var app = WinJS.Application;
// we don't restore the state if we are already running, or if we are
// booting for the first time
//
if (e.previousExecutionState !== 0 /* ApplicationExecutionState.NotRunning */ && e.previousExecutionState !== 1 /* ApplicationExecutionState.CurrentlyRunning */) {
return app.local.readText("_sessionState.json", "{}").
then(function (str) {
app.sessionState = JSON.parse(str);
});
}
else {
return WinJS.Promise.as();
}
},
_oncheckpoint: function (e) {
var app = WinJS.Application;
e.setPromise(app.local.writeText("_sessionState.json", JSON.stringify(app.sessionState)));
}
});
})();

Some files were not shown because too many files have changed in this diff Show more