first
2
AppxBlockMap.xml
Normal file
26
AppxManifest.xml
Normal 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
5
CSS/Main.css
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.main-content
|
||||||
|
{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
18
CSS/PaintView.css
Normal 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;
|
||||||
|
}
|
||||||
17
Controls/Canvas/Canvas.css
Normal 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;
|
||||||
|
}
|
||||||
33
Controls/Canvas/Canvas.html
Normal 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
|
|
@ -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);
|
||||||
107
Controls/Canvas/ToolCards.js
Normal 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);
|
||||||
28
Controls/ColorPicker/ColorPicker.css
Normal 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;
|
||||||
|
}
|
||||||
349
Controls/ColorPicker/ColorPicker.js
Normal 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);
|
||||||
104
Controls/Paint/Graphics/Canvas.js
Normal 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);
|
||||||
146
Controls/Paint/Graphics/Color.js
Normal 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);
|
||||||
294
Controls/Paint/Graphics/Path.js
Normal 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);
|
||||||
87
Controls/Paint/Graphics/Texture.js
Normal 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);
|
||||||
77
Controls/Paint/Math/Point.js
Normal 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);
|
||||||
143
Controls/Paint/Math/Vector.js
Normal 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
|
|
@ -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);
|
||||||
BIN
Controls/Paint/Res/crayon_texture.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
25
Controls/Paint/Tools/Bristle.js
Normal 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);
|
||||||
176
Controls/Paint/Tools/Brush.js
Normal 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);
|
||||||
146
Controls/Paint/Tools/Crayon.js
Normal 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);
|
||||||
101
Controls/Paint/Tools/Eraser.js
Normal 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);
|
||||||
108
Controls/Paint/Tools/Marker.js
Normal 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);
|
||||||
105
Controls/Paint/Tools/Neon.js
Normal 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);
|
||||||
221
Controls/Paint/Tools/Pipe.js
Normal 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);
|
||||||
133
Controls/Toolbar/Toolbar.css
Normal 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;
|
||||||
|
}
|
||||||
42
Controls/Toolbar/Toolbar.html
Normal 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
42
Controls/Toolbar/ToolbarColors.js
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
||||||
173
JS/CommandBar/CommandBar.css
Normal 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
26
JS/CommandBar/Flyout.css
Normal 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
|
|
@ -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
|
|
@ -0,0 +1,9 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//// © Microsoft. All rights reserved. ////
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
// Define app namespace
|
||||||
|
WinJS.Namespace.define("Microsoft.Paint", {
|
||||||
|
});
|
||||||
|
})();
|
||||||
29
JS/KeyManager.js
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/brushIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/brushIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/densityOptionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
Res/densityOptionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/densityOptionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
Res/fadeOptionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/fadeOptionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/fadeOptionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/glowOptionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Res/glowOptionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Res/glowOptionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Res/heightOptionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Res/heightOptionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/heightOptionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Res/logo.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
Res/moreIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/moreIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Res/moreIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/newIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 769 B |
BIN
Res/newIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 769 B |
BIN
Res/newIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 769 B |
BIN
Res/opacityOptionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/opacityOptionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Res/opacityOptionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/optionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/optionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Res/optionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/panmodeOptionIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
Res/panmodeOptionIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/panmodeOptionIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
Res/sizeIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/sizeIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Res/sizeIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/smallLogo.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Res/splashScreen.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Res/storeLogo.png
Normal file
|
After Width: | Height: | Size: 238 B |
BIN
Res/undoIcon40px.hover.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/undoIcon40px.press.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Res/undoIcon40px.rest.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Res/wideLogo.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
2093
WinJS/Css/ui-dark.css
Normal file
2102
WinJS/Css/ui-light.css
Normal file
1296
WinJS/js/animations.js
Normal file
1482
WinJS/js/base.js
Normal file
1347
WinJS/js/binding.js
Normal file
5621
WinJS/js/controls.js
vendored
Normal file
228
WinJS/js/res.js
Normal 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
17673
WinJS/js/uicollections.js
Normal file
716
WinJS/js/wwaapp.js
Normal 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)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||