(function ($) { // setup menu $.fn.wPaint.menus.main = { img: 'plugins/main/img/icons-menu-main.png', items: { undo: { icon: 'generic', title: 'Undo', index: 0, callback: function () { this.undo(); } }, redo: { icon: 'generic', title: 'Redo', index: 1, callback: function () { this.redo(); } }, clear: { icon: 'generic', title: 'Clear', index: 2, callback: function () { this.clear(); } }, rectangle: { icon: 'activate', title: 'Rectangle', index: 3, callback: function () { this.setMode('rectangle'); } }, ellipse: { icon: 'activate', title: 'Ellipse', index: 4, callback: function () { this.setMode('ellipse'); } }, line: { icon: 'activate', title: 'Line', index: 5, callback: function () { this.setMode('line'); } }, pencil: { icon: 'activate', title: 'Pencil', index: 6, callback: function () { this.setMode('pencil'); } }, eraser: { icon: 'activate', title: 'Eraser', index: 8, callback: function () { this.setMode('eraser'); } }, bucket: { icon: 'activate', title: 'Bucket', index: 9, callback: function () { this.setMode('bucket'); } }, fillStyle: { title: 'Fill Color', icon: 'colorPicker', callback: function (color) { this.setFillStyle(color); } }, lineWidth: { icon: 'select', title: 'Stroke Width', range: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], value: 2, callback: function (width) { this.setLineWidth(width); } }, strokeStyle: { icon: 'colorPicker', title: 'Stroke Color', callback: function (color) { this.setStrokeStyle(color); } } } }; // extend cursors $.extend($.fn.wPaint.cursors, { 'default': {path: 'plugins/main/img/cursor-crosshair.png', left: 7, top: 7}, dropper: {path: 'plugins/main/img/cursor-dropper.png', left: 0, top: 12}, pencil: {path: 'plugins/main/img/cursor-pencil.png', left: 0, top: 11.99}, bucket: {path: 'plugins/main/img/cursor-bucket.png', left: 0, top: 10}, eraser1: {path: 'plugins/main/img/cursor-eraser1.png', left: 1, top: 1}, eraser2: {path: 'plugins/main/img/cursor-eraser2.png', left: 2, top: 2}, eraser3: {path: 'plugins/main/img/cursor-eraser3.png', left: 2, top: 2}, eraser4: {path: 'plugins/main/img/cursor-eraser4.png', left: 3, top: 3}, eraser5: {path: 'plugins/main/img/cursor-eraser5.png', left: 3, top: 3}, eraser6: {path: 'plugins/main/img/cursor-eraser6.png', left: 4, top: 4}, eraser7: {path: 'plugins/main/img/cursor-eraser7.png', left: 4, top: 4}, eraser8: {path: 'plugins/main/img/cursor-eraser8.png', left: 5, top: 5 }, eraser9: {path: 'plugins/main/img/cursor-eraser9.png', left: 5, top: 5}, eraser10: {path: 'plugins/main/img/cursor-eraser10.png', left: 6, top: 6} }); // extend defaults $.extend($.fn.wPaint.defaults, { mode: 'pencil', // set mode lineWidth: '3', // starting line width fillStyle: '#FFFFFF', // starting fill style strokeStyle: '#FFFF00' // start stroke style }); // extend functions $.fn.wPaint.extend({ undoCurrent: -1, undoArray: [], setUndoFlag: true, generate: function () { this.menus.all.main = this._createMenu('main', { offsetLeft: this.options.menuOffsetLeft, offsetTop: this.options.menuOffsetTop }); }, _init: function () { // must add undo on init to set the first undo as the initial drawing (bg or blank) this._addUndo(); this.menus.all.main._setIconDisabled('clear', true); }, setStrokeStyle: function (color) { this.options.strokeStyle = color; this.menus.all.main._setColorPickerValue('strokeStyle', color); }, setLineWidth: function (width) { this.options.lineWidth = width; this.menus.all.main._setSelectValue('lineWidth', width); // reset cursor here based on mode in case we need to update cursor (for instance when changing cursor for eraser sizes) this.setCursor(this.options.mode); }, setFillStyle: function (color) { this.options.fillStyle = color; this.menus.all.main._setColorPickerValue('fillStyle', color); }, setCursor: function (cursor) { if (cursor === 'eraser') { this.setCursor('eraser' + this.options.lineWidth); } }, /**************************************** * undo / redo ****************************************/ undo: function () { if (this.undoArray[this.undoCurrent - 1]) { this._setUndo(--this.undoCurrent); } this._undoToggleIcons(); }, redo: function () { if (this.undoArray[this.undoCurrent + 1]) { this._setUndo(++this.undoCurrent); } this._undoToggleIcons(); }, _addUndo: function () { //if it's not at the end of the array we need to repalce the current array position if (this.undoCurrent < this.undoArray.length - 1) { this.undoArray[++this.undoCurrent] = this.getImage(false); } else { // owtherwise we push normally here this.undoArray.push(this.getImage(false)); //if we're at the end of the array we need to slice off the front - in increment required if (this.undoArray.length > this.undoMax) { this.undoArray = this.undoArray.slice(1, this.undoArray.length); } //if we're NOT at the end of the array, we just increment else { this.undoCurrent++; } } //for undo's then a new draw we want to remove everything afterwards - in most cases nothing will happen here while (this.undoCurrent !== this.undoArray.length - 1) { this.undoArray.pop(); } this._undoToggleIcons(); this.menus.all.main._setIconDisabled('clear', false); }, _undoToggleIcons: function () { var undoIndex = (this.undoCurrent > 0 && this.undoArray.length > 1) ? 0 : 1, redoIndex = (this.undoCurrent < this.undoArray.length - 1) ? 2 : 3; this.menus.all.main._setIconDisabled('undo', undoIndex === 1 ? true : false); this.menus.all.main._setIconDisabled('redo', redoIndex === 3 ? true : false); }, _setUndo: function (undoCurrent) { this.setImage(this.undoArray[undoCurrent], null, null, true); }, /**************************************** * clear ****************************************/ clear: function () { // only run if not disabled (make sure we only run one clear at a time) if (!this.menus.all.main._isIconDisabled('clear')) { this.ctx.clearRect(0, 0, this.width, this.height); this._addUndo(); this.menus.all.main._setIconDisabled('clear', true); } }, /**************************************** * rectangle ****************************************/ _drawRectangleDown: function (e) { this._drawShapeDown(e); }, _drawRectangleMove: function (e) { this._drawShapeMove(e); this.ctxTemp.rect(e.x, e.y, e.w, e.h); this.ctxTemp.stroke(); this.ctxTemp.fill(); }, _drawRectangleUp: function (e) { this._drawShapeUp(e); this._addUndo(); }, /**************************************** * ellipse ****************************************/ _drawEllipseDown: function (e) { this._drawShapeDown(e); }, _drawEllipseMove: function (e) { this._drawShapeMove(e); this.ctxTemp.ellipse(e.x, e.y, e.w, e.h); this.ctxTemp.stroke(); this.ctxTemp.fill(); }, _drawEllipseUp: function (e) { this._drawShapeUp(e); this._addUndo(); }, /**************************************** * line ****************************************/ _drawLineDown: function (e) { this._drawShapeDown(e); }, _drawLineMove: function (e) { this._drawShapeMove(e, 1); var xo = this.canvasTempLeftOriginal; var yo = this.canvasTempTopOriginal; if (e.pageX < xo) { e.x = e.x + e.w; e.w = e.w * - 1; } if (e.pageY < yo) { e.y = e.y + e.h; e.h = e.h * - 1; } this.ctxTemp.lineJoin = 'round'; this.ctxTemp.beginPath(); this.ctxTemp.moveTo(e.x, e.y); this.ctxTemp.lineTo(e.x + e.w, e.y + e.h); this.ctxTemp.closePath(); this.ctxTemp.stroke(); }, _drawLineUp: function (e) { this._drawShapeUp(e); this._addUndo(); }, /**************************************** * pencil ****************************************/ _drawPencilDown: function (e) { this.ctx.lineJoin = 'round'; this.ctx.lineCap = 'round'; this.ctx.strokeStyle = this.options.strokeStyle; this.ctx.fillStyle = this.options.strokeStyle; this.ctx.lineWidth = this.options.lineWidth; //draw single dot in case of a click without a move this.ctx.beginPath(); this.ctx.arc(e.pageX, e.pageY, this.options.lineWidth / 2, 0, Math.PI * 2, true); this.ctx.closePath(); this.ctx.fill(); //start the path for a drag this.ctx.beginPath(); this.ctx.moveTo(e.pageX, e.pageY); }, _drawPencilMove: function (e) { this.ctx.lineTo(e.pageX, e.pageY); this.ctx.stroke(); }, _drawPencilUp: function () { this.ctx.closePath(); this._addUndo(); }, /**************************************** * eraser ****************************************/ _drawEraserDown: function (e) { this.ctx.save(); this.ctx.globalCompositeOperation = 'destination-out'; this._drawPencilDown(e); }, _drawEraserMove: function (e) { this._drawPencilMove(e); }, _drawEraserUp: function (e) { this._drawPencilUp(e); this.ctx.restore(); }, /**************************************** * bucket ****************************************/ _drawBucketDown: function (e) { this.ctx.fillArea(e.pageX, e.pageY, this.options.fillStyle); this._addUndo(); } }); })(jQuery);