diff --git a/css/style.css b/css/style.css
index cee6f6ab..4e4984b5 100644
--- a/css/style.css
+++ b/css/style.css
@@ -16,9 +16,9 @@ body {
text-align: center;
font-size: 0;
position: absolute;
- left: 104px;
+ left: 100px; /* Reserve room for tools on the left edge of the screen. */
top: 10px;
- right: 0;
+ right: 50px; /* Reserve room for actions on the right edge of the screen. */
bottom: 10px;
}
@@ -51,15 +51,120 @@ body {
position: fixed;
top: 0;
bottom: 0;
- left: 0;
- width: 140px;
+ z-index: 1000;
}
-.sticky-section .wrap {
+.sticky-section .wrap,
+.sticky-section .drawer {
display: table-cell;
vertical-align: middle;
}
+.left-sticky-section.sticky-section {
+ left: 0;
+ max-width: 100px;
+}
+
+.left-sticky-section .tool-icon {
+ float: left;
+}
+
+.right-sticky-section.sticky-section {
+ right: 0;
+ width: 50px;
+
+ -webkit-transition: all 200ms ease-out;
+ -moz-transition: all 200ms ease-out;
+ -ms-transition: all 200ms ease-out;
+ transition: all 200ms ease-out;
+}
+
+.right-sticky-section .tool-icon {
+ float: right;
+ margin-right: 0;
+}
+
+.drawer {
+
+}
+
+.drawer-content {
+ overflow: hidden;
+ background-color: #444;
+ height: 550px;
+ max-height: 100%;
+ width: 280px;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+
+/** Righty sticky drawer expanded state. */
+
+.right-sticky-section.expanded {
+ right: 280px;
+}
+
+.right-sticky-section.expanded .tool-icon {
+ margin-right: 1px;
+}
+
+.right-sticky-section .tool-icon.has-expanded-drawer {
+ position: relative;
+ background-color: #444;
+ margin-right: 0;
+ padding-right: 1px;
+}
+
+.settings-section {
+ margin: 10px 20px;
+ font-size: 12px;
+ font-weight: bold;
+ color: #ccc;
+ text-shadow: 1px 1px #000;
+}
+
+.settings-title {
+ margin-top: 20px;
+ margin-bottom: 10px;
+ text-transform: uppercase;
+ border-bottom: 1px #aaa solid;
+ padding-bottom: 5px;
+}
+
+.settings-item {}
+
+.background-picker-wrapper {
+ overflow: hidden;
+ padding: 10px 5px 20px 5px;
+}
+
+.background-picker {
+ cursor: pointer;
+ float: left;
+ height: 35px;
+ width: 35px;
+ background-color: transparent;
+ margin-right: 15px;
+ padding: 1px;
+ position: relative;
+}
+
+.background-picker:after {
+ content: " ";
+ position: absolute;
+ top: -2px;
+ right: -2px;
+ bottom: -2px;
+ left: -2px;
+}
+
+.background-picker:hover:after {
+ border: #eee 1px solid;
+}
+
+.background-picker.selected:after {
+ border: gold 1px solid;
+}
/**
* Canvases layout
@@ -76,7 +181,6 @@ body {
}
.canvas-container .canvas-background {
- background: url(../img/canvas_background/medium_canvas_background.png) repeat;
position: absolute;
top: 0;
right: 0;
@@ -84,18 +188,22 @@ body {
left: 0;
}
+.light-picker-background,
.light-canvas-background .canvas-background {
background: url(../img/canvas_background/light_canvas_background.png) repeat;
}
+.medium-picker-background,
.medium-canvas-background .canvas-background {
background: url(../img/canvas_background/medium_canvas_background.png) repeat;
}
+.lowcont-medium-picker-background,
.lowcont-medium-canvas-background .canvas-background {
background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat;
}
+.lowcont-dark-picker-background,
.lowcont-dark-canvas-background .canvas-background {
background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat;
}
@@ -137,10 +245,6 @@ body {
overflow: hidden;
}
-.application-actions {
- margin-top: 35px;
-}
-
/**
* User messages
*/
diff --git a/css/tools.css b/css/tools.css
index 69db6316..76165c7b 100644
--- a/css/tools.css
+++ b/css/tools.css
@@ -6,12 +6,11 @@
}
.tool-icon {
- float: left;
cursor : pointer;
width: 46px;
height: 46px;
margin: 1px;
- background-color: rgba(200,200,200, .1);
+ background-color: #3a3a3a;
background-repeat: no-repeat;
background-position: 12px 12px;
background-size: 24px 24px;
@@ -198,6 +197,12 @@
background-size: 36px 36px;
}
+.tool-icon.gear-icon {
+ background-image: url(../img/gear.png);
+ background-position: 6px 7px;
+ background-size: 32px 32px;
+}
+
.tool-icon.upload-cloud-icon {
background-image: url(../img/cloud_export.png);
background-position: 4px 0px;
@@ -213,5 +218,6 @@
font-size: 11px;
text-transform: uppercase;
color: #fff;
+ text-align: center;
}
diff --git a/img/gear.png b/img/gear.png
new file mode 100644
index 00000000..c09e06fa
Binary files /dev/null and b/img/gear.png differ
diff --git a/index.html b/index.html
index 18aa0140..77de32b0 100644
--- a/index.html
+++ b/index.html
@@ -16,8 +16,7 @@
-
-
+
+
+
+
+
+
+
+ GIF
-
- Canvas background:
-
+
+ PNG
+
+
+
+
+
+
+ Canvas settings:
+
+
+
+
+
+
@@ -81,16 +107,6 @@
-
-
-
-
- GIF
-
-
- PNG
-
-
@@ -114,6 +130,7 @@
+
@@ -136,6 +153,7 @@
+
diff --git a/js/Constants.js b/js/Constants.js
index 231dfb5b..c7abf94a 100644
--- a/js/Constants.js
+++ b/js/Constants.js
@@ -1,3 +1,4 @@
+// TODO(grosbouddha): put under pskl namespace.
var Constants = {
DEFAULT_SIZE : {
height : 32,
diff --git a/js/Events.js b/js/Events.js
index ab065356..34283d0d 100644
--- a/js/Events.js
+++ b/js/Events.js
@@ -1,3 +1,4 @@
+// TODO(grosbouddha): put under pskl namespace.
Events = {
TOOL_SELECTED : "TOOL_SELECTED",
@@ -30,7 +31,13 @@ Events = {
*/
REDRAW_PREVIEWFILM: "REDRAW_PREVIEWFILM",
- GRID_DISPLAY_STATE_CHANGED: "GRID_DISPLAY_STATE_CHANGED",
+ /**
+ * Fired each time a user setting change.
+ * The payload will be:
+ * 1st argument: Name of the settings
+ * 2nd argument: New value
+ */
+ USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED",
/**
* The framesheet was reseted and is now probably drastically different.
diff --git a/js/controller/DrawingController.js b/js/controller/DrawingController.js
index c1284ff1..c6ee9844 100644
--- a/js/controller/DrawingController.js
+++ b/js/controller/DrawingController.js
@@ -19,7 +19,7 @@
// TODO(vincz): Store user prefs in a localstorage string ?
var renderingOptions = {
"dpi": this.calculateDPI_(),
- "hasGrid" : true
+ "supportGridRendering" : true
};
this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, "drawing-canvas");
@@ -61,7 +61,7 @@
$(window).resize($.proxy(this.startDPIUpdateTimer_, this));
$.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.updateDPI_, this));
- $.subscribe(Events.GRID_DISPLAY_STATE_CHANGED, $.proxy(this.forceRendering_, this));
+ $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
};
ns.DrawingController.prototype.initMouseBehavior = function() {
@@ -83,6 +83,15 @@
this.dpiUpdateTimer = window.setTimeout($.proxy(this.updateDPI_, this), 200);
},
+ /**
+ * @private
+ */
+ ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) {
+ if(settingsName == pskl.UserSettings.SHOW_GRID) {
+ this.forceRendering_();
+ }
+ },
+
/**
* @private
*/
diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js
index 3f5a0ec3..a80f3db9 100644
--- a/js/controller/PreviewFilmController.js
+++ b/js/controller/PreviewFilmController.js
@@ -56,10 +56,10 @@
if (scrollBottom > treshold) {
overflowBottom = true;
}
- var wrapper = $('#preview-list-wrapper');
- wrapper.toggleClass('top-overflow-visible', overflowTop);
- wrapper.toggleClass('bottom-overflow-visible', overflowBottom);
}
+ var wrapper = $('#preview-list-wrapper');
+ wrapper.toggleClass('top-overflow-visible', overflowTop);
+ wrapper.toggleClass('bottom-overflow-visible', overflowBottom);
};
ns.PreviewFilmController.prototype.createPreviews_ = function () {
diff --git a/js/controller/SettingsController.js b/js/controller/SettingsController.js
new file mode 100644
index 00000000..7c54903d
--- /dev/null
+++ b/js/controller/SettingsController.js
@@ -0,0 +1,45 @@
+(function () {
+ var ns = $.namespace("pskl.controller");
+
+ ns.SettingsController = function () {};
+
+ /**
+ * @public
+ */
+ ns.SettingsController.prototype.init = function() {
+
+ // Highlight selected background picker:
+ var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND);
+ $('#background-picker-wrapper')
+ .find('.background-picker[data-background-class=' + backgroundClass + ']')
+ .addClass('selected');
+
+ // Initial state for grid display:
+ var show_grid = pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID);
+ $('#show-grid').prop('checked', show_grid);
+
+ // Expand drawer when clicking 'Settings' tab.
+ $('#settings').click(function(evt) {
+ $('.right-sticky-section').toggleClass('expanded');
+ $('#settings').toggleClass('has-expanded-drawer');
+ });
+
+ // Handle grid display changes:
+ $('#show-grid').change($.proxy(function(evt) {
+ var checked = $('#show-grid').prop('checked');
+ pskl.UserSettings.set(pskl.UserSettings.SHOW_GRID, checked);
+ }, this));
+
+ // Handle canvas background changes:
+ $('#background-picker-wrapper').click(function(evt) {
+ var target = $(evt.target).closest('.background-picker');
+ if (target.length) {
+ var backgroundClass = target.data('background-class');
+ pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass);
+
+ $('.background-picker').removeClass('selected');
+ target.addClass('selected');
+ }
+ });
+ };
+})();
\ No newline at end of file
diff --git a/js/controller/ToolController.js b/js/controller/ToolController.js
index 26b008c6..aa48685e 100644
--- a/js/controller/ToolController.js
+++ b/js/controller/ToolController.js
@@ -58,7 +58,7 @@
this.selectTool_(this.toolInstances[tool]);
// Show tool as selected:
- $('#menubar .tool-icon.selected').removeClass('selected');
+ $('#tool-section .tool-icon.selected').removeClass('selected');
clickedTool.addClass('selected');
}
}
@@ -83,17 +83,6 @@
$('#tools-container').html(toolMarkup);
};
- /**
- * Get state for the checkbox that control the display of the grid
- * on the drawing canvas.
- * @private
- */
- ns.ToolController.prototype.isShowGridChecked_ = function() {
- var showGridCheckbox = $('#show-grid');
- var isChecked = showGridCheckbox.is(':checked');
- return isChecked;
- };
-
/**
* @public
*/
@@ -105,13 +94,6 @@
// Set SimplePen as default selected tool:
this.selectTool_(this.toolInstances.simplePen);
// Activate listener on tool panel:
- $("#menubar").click($.proxy(this.onToolIconClicked_, this));
-
- // Show/hide the grid on drawing canvas:
- $.publish(Events.GRID_DISPLAY_STATE_CHANGED, [this.isShowGridChecked_()]);
- $('#show-grid').change($.proxy(function(evt) {
- var checked = this.isShowGridChecked_();
- $.publish(Events.GRID_DISPLAY_STATE_CHANGED, [checked]);
- }, this));
+ $("#tool-section").click($.proxy(this.onToolIconClicked_, this));
};
})();
\ No newline at end of file
diff --git a/js/piskel.js b/js/piskel.js
index 04830f4f..725d15c9 100644
--- a/js/piskel.js
+++ b/js/piskel.js
@@ -24,6 +24,7 @@ $.namespace("pskl");
this.drawingController = new pskl.controller.DrawingController(frameSheet, $('#drawing-canvas-container'));
this.animationController = new pskl.controller.AnimatedPreviewController(frameSheet, $('#preview-canvas-container'));
this.previewsController = new pskl.controller.PreviewFilmController(frameSheet, $('#preview-list'));
+ this.settingsController = new pskl.controller.SettingsController();
// To catch the current active frame, the selection manager have to be initialized before
// the 'frameSheet.setCurrentFrameIndex(0);' line below.
@@ -39,6 +40,7 @@ $.namespace("pskl");
this.animationController.init();
this.previewsController.init();
+ this.settingsController.init();
this.historyService = new pskl.service.HistoryService(frameSheet);
this.historyService.init();
@@ -70,13 +72,6 @@ $.namespace("pskl");
$('body').tooltip({
selector: '[rel=tooltip]'
});
-
- $('#canvas-picker').change(function(evt) {
- $('#canvas-picker option:selected').each(function() {
- console.log($(this).val());
- $('html')[0].className = $(this).val();
- });
- });
},
render : function (delta) {
@@ -130,7 +125,6 @@ $.namespace("pskl");
loadFramesheetFromService : function (frameId) {
var xhr = new XMLHttpRequest();
- // TODO: Change frameId to framesheetId on the backend
xhr.open('GET', Constants.PISKEL_SERVICE_URL + '/get?l=' + frameId, true);
xhr.responseType = 'text';
@@ -152,7 +146,6 @@ $.namespace("pskl");
// TODO(julz): Create package ?
storeSheet : function (event) {
- // TODO Refactor using jquery ?
var xhr = new XMLHttpRequest();
var formData = new FormData();
formData.append('framesheet_content', frameSheet.serialize());
@@ -213,6 +206,7 @@ $.namespace("pskl");
}
};
+ // TODO(grosbouddha): Remove this window.piskel global (eventually pskl.piskel or pskl.app instead)
window.piskel = piskel;
piskel.init();
diff --git a/js/rendering/FrameRenderer.js b/js/rendering/FrameRenderer.js
index e4fec384..99d30131 100644
--- a/js/rendering/FrameRenderer.js
+++ b/js/rendering/FrameRenderer.js
@@ -1,143 +1,165 @@
(function () {
- var ns = $.namespace("pskl.rendering");
+ var ns = $.namespace("pskl.rendering");
- ns.FrameRenderer = function (container, renderingOptions, className) {
-
- this.defaultRenderingOptions = {
- "hasGrid" : false
- };
- renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions);
+ ns.FrameRenderer = function (container, renderingOptions, className) {
+ this.defaultRenderingOptions = {
+ 'supportGridRendering' : false
+ };
+ renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions);
- if(container === undefined) {
- throw "Bad FrameRenderer initialization. undefined.";
- }
-
- if(isNaN(renderingOptions.dpi)) {
- throw "Bad FrameRenderer initialization. not well defined.";
- }
+ if(container === undefined) {
+ throw 'Bad FrameRenderer initialization. undefined.';
+ }
+
+ if(isNaN(renderingOptions.dpi)) {
+ throw 'Bad FrameRenderer initialization. not well defined.';
+ }
- this.container = container;
- this.dpi = renderingOptions.dpi;
- this.className = className;
- this.canvas = null;
- this.hasGrid = renderingOptions.hasGrid;
- this.gridStrokeWidth = 0;
+ this.container = container;
+ this.dpi = renderingOptions.dpi;
+ this.className = className;
+ this.canvas = null;
+ this.supportGridRendering = renderingOptions.supportGridRendering;
- // Flag to know if the config was altered
- this.canvasConfigDirty = true;
+ this.enableGrid(pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID));
- if(this.hasGrid) {
- $.subscribe(Events.GRID_DISPLAY_STATE_CHANGED, $.proxy(this.showGrid, this));
- }
- };
+ // Flag to know if the config was altered
+ this.canvasConfigDirty = true;
+ this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND));
+ $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
+ };
- ns.FrameRenderer.prototype.init = function (frame) {
- this.render(frame);
- this.lastRenderedFrame = frame;
- };
+ ns.FrameRenderer.prototype.init = function (frame) {
+ this.render(frame);
+ this.lastRenderedFrame = frame;
+ };
- ns.FrameRenderer.prototype.updateDPI = function (newDPI) {
- this.dpi = newDPI;
- this.canvasConfigDirty = true;
- };
+ ns.FrameRenderer.prototype.updateDPI = function (newDPI) {
+ this.dpi = newDPI;
+ this.canvasConfigDirty = true;
+ };
- ns.FrameRenderer.prototype.showGrid = function (evt, show) {
-
- this.gridStrokeWidth = 0;
- if(show) {
- this.gridStrokeWidth = Constants.GRID_STROKE_WIDTH;
- }
-
- this.canvasConfigDirty = true;
- };
+ /**
+ * @private
+ */
+ ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) {
+
+ if(settingName == pskl.UserSettings.SHOW_GRID) {
+ this.enableGrid(settingValue);
+ }
+ else if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) {
+ this.updateBackgroundClass_(settingValue);
+ }
+ };
- ns.FrameRenderer.prototype.render = function (frame) {
- this.clear(frame);
- var context = this.getCanvas_(frame).getContext('2d');
- for(var col = 0, width = frame.getWidth(); col < width; col++) {
- for(var row = 0, height = frame.getHeight(); row < height; row++) {
- var color = frame.getPixel(col, row);
- this.renderPixel_(color, col, row, context);
- }
- }
- this.lastRenderedFrame = frame;
- };
+ /**
+ * @private
+ */
+ ns.FrameRenderer.prototype.updateBackgroundClass_ = function (newClass) {
+ var currentClass = this.container.data('current-background-class');
+ if (currentClass) {
+ this.container.removeClass(currentClass);
+ }
+ this.container.addClass(newClass);
+ this.container.data('current-background-class', newClass);
+ };
- ns.FrameRenderer.prototype.renderPixel_ = function (color, col, row, context) {
- if(color != Constants.TRANSPARENT_COLOR) {
- context.fillStyle = color;
- context.fillRect(this.getFramePos_(col), this.getFramePos_(row), this.dpi, this.dpi);
- }
- };
+ ns.FrameRenderer.prototype.enableGrid = function (flag) {
+ this.gridStrokeWidth = (flag && this.supportGridRendering) ? Constants.GRID_STROKE_WIDTH : 0;
+ this.canvasConfigDirty = true;
+ };
- ns.FrameRenderer.prototype.clear = function (frame) {
- var canvas = this.getCanvas_(frame);
- canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
- };
+ ns.FrameRenderer.prototype.render = function (frame) {
+ this.clear(frame);
+ var context = this.getCanvas_(frame).getContext('2d');
+ for(var col = 0, width = frame.getWidth(); col < width; col++) {
+ for(var row = 0, height = frame.getHeight(); row < height; row++) {
+ var color = frame.getPixel(col, row);
+ this.renderPixel_(color, col, row, context);
+ }
+ }
+ this.lastRenderedFrame = frame;
+ };
- /**
- * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered
- * frame) into a sprite coordinate in column and row.
- * @public
- */
- ns.FrameRenderer.prototype.convertPixelCoordinatesIntoSpriteCoordinate = function(coords) {
- var cellSize = this.dpi + this.gridStrokeWidth;
- return {
- "col" : (coords.x - coords.x % cellSize) / cellSize,
- "row" : (coords.y - coords.y % cellSize) / cellSize
- };
- };
+ ns.FrameRenderer.prototype.renderPixel_ = function (color, col, row, context) {
+ if(color != Constants.TRANSPARENT_COLOR) {
+ context.fillStyle = color;
+ context.fillRect(this.getFramePos_(col), this.getFramePos_(row), this.dpi, this.dpi);
+ }
+ };
- /**
- * @private
- */
- ns.FrameRenderer.prototype.getFramePos_ = function(index) {
- return index * this.dpi + ((index - 1) * this.gridStrokeWidth);
- };
+ ns.FrameRenderer.prototype.clear = function (frame) {
+ var canvas = this.getCanvas_(frame);
+ canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
+ };
- /**
- * @private
- */
- ns.FrameRenderer.prototype.drawGrid_ = function(canvas, width, height, col, row) {
- var ctx = canvas.getContext("2d");
- ctx.lineWidth = Constants.GRID_STROKE_WIDTH;
- ctx.strokeStyle = Constants.GRID_STROKE_COLOR;
- for(var c=1; c < col; c++) {
- ctx.moveTo(this.getFramePos_(c), 0);
- ctx.lineTo(this.getFramePos_(c), height);
- ctx.stroke();
- }
-
- for(var r=1; r < row; r++) {
- ctx.moveTo(0, this.getFramePos_(r));
- ctx.lineTo(width, this.getFramePos_(r));
- ctx.stroke();
- }
- };
+ /**
+ * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered
+ * frame) into a sprite coordinate in column and row.
+ * @public
+ */
+ ns.FrameRenderer.prototype.convertPixelCoordinatesIntoSpriteCoordinate = function(coords) {
+ var cellSize = this.dpi + this.gridStrokeWidth;
+ return {
+ "col" : (coords.x - coords.x % cellSize) / cellSize,
+ "row" : (coords.y - coords.y % cellSize) / cellSize
+ };
+ };
- /**
- * @private
- */
- ns.FrameRenderer.prototype.getCanvas_ = function (frame) {
- if(this.canvasConfigDirty) {
- $(this.canvas).remove();
-
- var col = frame.getWidth(),
- row = frame.getHeight();
-
- var pixelWidth = col * this.dpi + this.gridStrokeWidth * (col - 1);
- var pixelHeight = row * this.dpi + this.gridStrokeWidth * (row - 1);
- var canvas = pskl.CanvasUtils.createCanvas(pixelWidth, pixelHeight, ["canvas", this.className]);
+ /**
+ * @private
+ */
+ ns.FrameRenderer.prototype.getFramePos_ = function(index) {
+ return index * this.dpi + ((index - 1) * this.gridStrokeWidth);
+ };
- this.container.append(canvas);
+ /**
+ * @private
+ */
+ ns.FrameRenderer.prototype.drawGrid_ = function(canvas, width, height, col, row) {
+ var ctx = canvas.getContext("2d");
+ ctx.lineWidth = Constants.GRID_STROKE_WIDTH;
+ ctx.strokeStyle = Constants.GRID_STROKE_COLOR;
+ for(var c=1; c < col; c++) {
+ ctx.moveTo(this.getFramePos_(c), 0);
+ ctx.lineTo(this.getFramePos_(c), height);
+ ctx.stroke();
+ }
+
+ for(var r=1; r < row; r++) {
+ ctx.moveTo(0, this.getFramePos_(r));
+ ctx.lineTo(width, this.getFramePos_(r));
+ ctx.stroke();
+ }
+ };
- if(this.gridStrokeWidth > 0) {
- this.drawGrid_(canvas, pixelWidth, pixelHeight, col, row);
- }
-
- this.canvas = canvas;
- this.canvasConfigDirty = false;
- }
- return this.canvas;
- };
+ /**
+ * @private
+ */
+ ns.FrameRenderer.prototype.getCanvas_ = function (frame) {
+ if(this.canvasConfigDirty) {
+ $(this.canvas).remove();
+
+ var col = frame.getWidth(),
+ row = frame.getHeight();
+
+ var pixelWidth = col * this.dpi + this.gridStrokeWidth * (col - 1);
+ var pixelHeight = row * this.dpi + this.gridStrokeWidth * (row - 1);
+ var classes = ['canvas'];
+ if (this.className) {
+ classes.push(this.className);
+ }
+ var canvas = pskl.CanvasUtils.createCanvas(pixelWidth, pixelHeight, classes);
+
+ this.container.append(canvas);
+
+ if(this.gridStrokeWidth > 0) {
+ this.drawGrid_(canvas, pixelWidth, pixelHeight, col, row);
+ }
+
+ this.canvas = canvas;
+ this.canvasConfigDirty = false;
+ }
+ return this.canvas;
+ };
})();
\ No newline at end of file
diff --git a/js/utils/UserSettings.js b/js/utils/UserSettings.js
new file mode 100644
index 00000000..89359bee
--- /dev/null
+++ b/js/utils/UserSettings.js
@@ -0,0 +1,76 @@
+(function () {
+ var ns = $.namespace("pskl");
+
+ ns.UserSettings = {
+
+ SHOW_GRID : 'SHOW_GRID',
+ CANVAS_BACKGROUND : 'CANVAS_BACKGROUND',
+
+ KEY_TO_DEFAULT_VALUE_MAP_ : {
+ 'SHOW_GRID' : false,
+ 'CANVAS_BACKGROUND' : 'medium-canvas-background'
+ },
+
+ /**
+ * @private
+ */
+ cache_ : {},
+
+ /**
+ * Static method to access a user defined settings value ot its default
+ * value if not defined yet.
+ */
+ get : function (key) {
+ this.checkKeyValidity_(key);
+ if (!(key in this.cache_)) {
+ this.cache_[key] =
+ this.readFromLocalStorage_(key) || this.readFromDefaults_(key);
+ }
+ return this.cache_[key];
+ },
+
+ set : function (key, value) {
+ this.checkKeyValidity_(key);
+ this.cache_[key] = value;
+ this.writeToLocalStorage_(key, value);
+
+ $.publish(Events.USER_SETTINGS_CHANGED, [key, value]);
+ },
+
+ /**
+ * @private
+ */
+ readFromLocalStorage_ : function(key) {
+ var value = window.localStorage[key];
+ if (typeof value != "undefined") {
+ value = JSON.parse(value);
+ }
+ return value;
+ },
+
+ /**
+ * @private
+ */
+ writeToLocalStorage_ : function(key, value) {
+ // TODO(grosbouddha): Catch storage exception here.
+ window.localStorage[key] = JSON.stringify(value);
+ },
+
+ /**
+ * @private
+ */
+ readFromDefaults_ : function (key) {
+ return this.KEY_TO_DEFAULT_VALUE_MAP_[key];
+ },
+
+ /**
+ * @private
+ */
+ checkKeyValidity_ : function(key) {
+ if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) {
+ // TODO(grosbouddha): Define error catching strategy and throw exception from here.
+ console.log("UserSettings key <"+ key +"> not find in supported keys.");
+ }
+ }
+ };
+})();
\ No newline at end of file
diff --git a/resources/icons.png b/resources/icons.png
new file mode 100644
index 00000000..cbeb10d7
Binary files /dev/null and b/resources/icons.png differ