diff --git a/README.md b/README.md index 481e2f6..da33080 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,7 @@ fonteditor 在线ttf字体编辑器 5. 2014-11-10 ttf编辑器增加智能吸附,增加编辑器设置. +6. 2014-12-7 ttf编辑器增加百度编辑器样式. + +7. 2014-12-13 ttf编辑器增加列表和查看器命令栏. + diff --git a/css/common/bootstrap.less b/css/common/bootstrap.less index 1a2980c..c253a3e 100644 --- a/css/common/bootstrap.less +++ b/css/common/bootstrap.less @@ -133,6 +133,11 @@ hr { background: #28B4A0; } +.btn-confirm { + color: #FFF; + background: #4A90E2; +} + .btn-ico { padding: 5px 10px; font-size: 12px; @@ -148,12 +153,14 @@ hr { // 命令组 .command-groups { height: 40px; - line-height: 40px; padding-left: 8px; + overflow: hidden; background: rgba(112, 119, 128, 0.8); >li { + float: left; + line-height: 40px; padding: 0 8px; color: #FFF; cursor: pointer; @@ -166,11 +173,20 @@ hr { text-decoration: underline; } + >.ico { + font-size: 20px; + text-decoration: none; + } + &:hover { background: lighten(#707781, 10%); } } + >li[data-theme="ico"] { + padding: 0 12px; + } + >li[data-disabled] { color: #B9BDC1; } @@ -178,4 +194,12 @@ hr { >li[data-on] { background: darken(#707781, 10%); } + + >[data-split] { + padding: 0; + width: 1px; + height: 40px; + background: lighten(#707781, 15%); + pointer-events: none; + } } \ No newline at end of file diff --git a/css/common/common.less b/css/common/common.less index 829ed4b..ab3ac51 100644 --- a/css/common/common.less +++ b/css/common/common.less @@ -127,11 +127,38 @@ body, html { position: fixed; width: 70%; top: @top-height; + padding-top: @command-groups-height; bottom: 0; z-index: 1; background: #FEFEFE; border-right: 1px solid #DDD; display: none; + + .command-groups { + background: rgba(112, 119, 128, 1); + margin-top: -40px; + } + + .close-editor { + position: absolute; + right: 0; + top: 0; + padding-right: 5px; + z-index: 100; + font-size: 20px; + line-height: 38px; + color: #FFF; + display: none; + &:hover { + cursor: pointer + } + } + + &:hover { + .close-editor { + display: block; + } + } } .editor.editing { diff --git a/css/common/editor.less b/css/common/editor.less index 1aa1b82..e86d3a2 100644 --- a/css/common/editor.less +++ b/css/common/editor.less @@ -92,9 +92,3 @@ } } -.editor:hover { - .close-editor { - display: block; - } -} - diff --git a/css/common/ico.less b/css/common/ico.less index a74175f..8deb738 100644 --- a/css/common/ico.less +++ b/css/common/ico.less @@ -33,8 +33,13 @@ .icon(); } +.i-leave { + .i-ico('\e00c'); +} + .i-edit, -.i-del { +.i-del, +.i-leave { font-size: 12px; &:hover { cursor: pointer; @@ -99,18 +104,62 @@ .i-ico('\e022'); } -.close-editor { - position: absolute; - right: 0; - top: 0; - z-index: 100; - padding: 0 3px; - z-index: 100; - font-size: 14px; - background: #FFF; - border-left: 1px solid #000; - display: none; - &:hover { - cursor: pointer - } + + +// glyf编辑器 + +.i-upshape { + .i-ico('\e014'); } + +.i-downshape { + .i-ico('\e00b'); +} + +.i-reversepoints { + .i-ico('\e00d'); +} + +.i-alignleft { + .i-ico('\e006'); +} + +.i-aligncenter { + .i-ico('\e004'); +} + +.i-alignright { + .i-ico('\e007'); +} + +.i-aligntop { + .i-ico('\e008'); +} + +.i-alignmiddle { + .i-ico('\e005'); +} + +.i-aligndescent { + .i-ico('\e009'); +} + +.i-alignbaseline { + .i-ico('\e009'); +} + +.i-rotateleft { + .i-ico('\e01c'); +} + +.i-rotateright { + .i-ico('\e01d'); +} + +.i-flip { + .i-ico('\e013'); +} + +.i-mirror { + .i-ico('\e012'); +} \ No newline at end of file diff --git a/demo/css/editor.css b/demo/css/editor.css index 72b60ad..c7df596 100644 --- a/demo/css/editor.css +++ b/demo/css/editor.css @@ -29,12 +29,17 @@ a:hover { -webkit-font-smoothing: antialiased; -webkit-text-stroke-width: 0.1px; } +.i-leave:before { + content: '\e00c'; +} .i-edit, -.i-del { +.i-del, +.i-leave { font-size: 12px; } .i-edit:hover, -.i-del:hover { +.i-del:hover, +.i-leave:hover { cursor: pointer; color: #4A90E2; } @@ -80,19 +85,47 @@ a:hover { .i-save:before { content: '\e022'; } -.close-editor { - position: absolute; - right: 0; - top: 0; - padding: 0 3px; - z-index: 100; - font-size: 14px; - background: #FFF; - border-left: 1px solid #000; - display: none; +.i-upshape:before { + content: '\e014'; } -.close-editor:hover { - cursor: pointer; +.i-downshape:before { + content: '\e00b'; +} +.i-reversepoints:before { + content: '\e00d'; +} +.i-alignleft:before { + content: '\e006'; +} +.i-aligncenter:before { + content: '\e004'; +} +.i-alignright:before { + content: '\e007'; +} +.i-aligntop:before { + content: '\e008'; +} +.i-alignmiddle:before { + content: '\e005'; +} +.i-aligndescent:before { + content: '\e009'; +} +.i-alignbaseline:before { + content: '\e009'; +} +.i-rotateleft:before { + content: '\e01c'; +} +.i-rotateright:before { + content: '\e01d'; +} +.i-flip:before { + content: '\e013'; +} +.i-mirror:before { + content: '\e012'; } .glyf-editor { width: 100%; @@ -182,9 +215,6 @@ a:hover { .editor-contextmenu li:last-child { border-bottom: none; } -.editor:hover .close-editor { - display: block; -} body, html { height: 100%; diff --git a/index.html b/index.html index d862e9c..7a029b0 100644 --- a/index.html +++ b/index.html @@ -94,9 +94,10 @@
-
- -
+
+ + +
@@ -112,8 +113,8 @@ diff --git a/src/editor/Editor.js b/src/editor/Editor.js index 7d9bf0c..9c51bde 100644 --- a/src/editor/Editor.js +++ b/src/editor/Editor.js @@ -95,6 +95,39 @@ define( return this; }; + /** + * 设置选中的shapes + * @param {Array} shapes 选中的shapes + */ + Editor.prototype.setSelected = function(shapes) { + this.setMode('shapes', shapes); + }; + + /** + * 刷新选中的shapes + * @param {Array} shapes 选中的shapes + */ + Editor.prototype.refreshSelected = function(shapes) { + if (this.currentGroup) { + var lastShapes = this.currentGroup.shapes; + this.currentGroup.setShapes(shapes); + this.currentGroup.refresh(); + + if (shapes !== lastShapes) { + this.fire('selection:change', { + shapes: shapes + }); + } + } + }; + + /** + * 获取选中的shapes + * @return {Array} 选中的shapes + */ + Editor.prototype.getSelected = function() { + return this.currentGroup ? this.currentGroup.shapes : null; + }; /** * 执行指定命令 @@ -109,15 +142,17 @@ define( command: command, args: args }; - this.fire('command', event); + this.fire('beforecommand', event); if(event.returnValue === false) { return false; } if (commandSupport[command]) { - commandSupport[command].apply(this, args); - return true; + var ret = commandSupport[command].apply(this, args); + event.result = ret; + this.fire('command', event); + return ret; } return false; @@ -148,17 +183,6 @@ define( return true; }; - /** - * 添加到剪切板 - * - * @param {Array} 形状集合 - * @return {this} - */ - Editor.prototype.setClipBoard = function(shapes) { - clipboard.set(shapes, 'editor-shape'); - return this; - }; - /** * 是否改变过 * @@ -184,6 +208,17 @@ define( } }; + /** + * 添加到剪切板 + * + * @param {Array} 形状集合 + * @return {this} + */ + Editor.prototype.setClipBoard = function(shapes) { + clipboard.set(shapes, 'editor-shape'); + return this; + }; + /** * 从剪切板中获取 * diff --git a/src/editor/command/align.js b/src/editor/command/align.js index 85a8c6a..5b84010 100644 --- a/src/editor/command/align.js +++ b/src/editor/command/align.js @@ -21,10 +21,10 @@ define( * @param {Array} shapes 形状集合 * @param {string} align 对齐方式 */ - align: function(shapes, align) { + alignshapes: function(shapes, align) { - if (!shapes.length) { - return; + if (!shapes || !shapes.length) { + return false; } var contours = shapes.map(function(shape) { @@ -67,6 +67,7 @@ define( }); this.fontLayer.refresh(); + this.refreshSelected(shapes); }, /** @@ -75,10 +76,10 @@ define( * @param {Array} shapes 形状集合 * @param {string} align 对齐方式 */ - verticalalign: function(shapes, align) { + verticalalignshapes: function(shapes, align) { - if (!shapes.length) { - return; + if (!shapes || !shapes.length) { + return false; } var contours = shapes.map(function(shape) { @@ -113,7 +114,50 @@ define( }); this.fontLayer.refresh(); + this.refreshSelected(shapes); + }, + + /** + * 字体水平对齐 + * + * @param {Array} shapes 形状集合 + * @param {string} align 对齐方式 + */ + horizontalalignshapes: function(shapes, align) { + + if (!shapes || !shapes.length) { + return false; + } + + var contours = shapes.map(function(shape) { + return shape.points; + }); + + var xbaseline = this.axis.x; // 基线 + var rightSideBearing = this.rightSideBearing.p0.x; + + // 求边界线 + var bound = computeBoundingBox.computePath.apply(null, contours); + var xOffset = 0; + + if ('left' === align) { + xOffset = xbaseline - bound.x; + } + else if ('center' === align) { + xOffset = (xbaseline + rightSideBearing) / 2 - bound.x - bound.width / 2; + } + else if ('right' === align) { + xOffset = rightSideBearing - bound.x - bound.width; + } + + contours.forEach(function(contour) { + pathAdjust(contour, 1, 1, xOffset, 0); + }); + + this.fontLayer.refresh(); + this.refreshSelected(shapes); } + }; return support; diff --git a/src/editor/command/commandSupport.js b/src/editor/command/commandSupport.js new file mode 100644 index 0000000..d5947a7 --- /dev/null +++ b/src/editor/command/commandSupport.js @@ -0,0 +1,42 @@ +/** + * @file supportHistory.js + * @author mengke01 + * @date + * @description + * 命令相关配置 + */ + + +define( + function(require) { + + // 支持历史记录的命令列表 + var supportHistory = { + alignshapes: true, + verticalalignshapes: true, + horizontalalignshapes: true, + joinshapes: true, + intersectshapes: true, + tangencyshapes: true, + splitshapes: true, + removeshapes: true, + reversepoints: true, + topshape: true, + bottomshape: true, + upshape: true, + downshape: true, + cutshapes: true, + pasteshapes: true, + addshapes: true, + rotateleft: true, + rotateright: true, + flipshapes: true, + mirrorshapes: true + }; + + + return { + history: supportHistory + }; + } +); diff --git a/src/editor/command/editor.js b/src/editor/command/editor.js new file mode 100644 index 0000000..708ce74 --- /dev/null +++ b/src/editor/command/editor.js @@ -0,0 +1,135 @@ +/** + * @file editor.js + * @author mengke01 + * @date + * @description + * 编辑器相关命令 + */ + + +define( + function(require) { + var lang = require('common/lang'); + var computeBoundingBox = require('graphics/computeBoundingBox'); + var commandList = require('../menu/commandList'); + var shapesSupport = require('../shapes/support'); + var menuUtil = require('../menu/util'); + + return { + + /** + * 重置缩放 + */ + rescale: function() { + this.coverLayer.clearShapes(); + var size = this.render.getSize(); + var scale = 512 / this.options.unitsPerEm; + this.render.scaleTo(scale, { + x: size.width / 2, + y: size.height / 2 + }); + this.setMode(); + }, + + + /** + * 撤销 + */ + undo: function() { + var shapes = this.history.back(); + this.fontLayer.shapes.length = 0; + this.setShapes(shapes); + this.setMode(); + }, + + /** + * 恢复 + */ + redo: function() { + var shapes = this.history.forward(); + this.fontLayer.shapes.length = 0; + this.setShapes(shapes); + this.setMode(); + }, + + /** + * 是否打开网格吸附 + */ + gridsorption: function(enabled) { + menuUtil.setSelected(commandList.editor, 'setting.gridsorption', !!enabled); + this.options.sorption.enableGrid = this.sorption.enableGrid = !!enabled; + }, + + /** + * 是否打开轮廓吸附 + */ + shapesorption: function(enabled) { + menuUtil.setSelected(commandList.editor, 'setting.shapesorption', !!enabled); + this.options.sorption.enableShape = this.sorption.enableShape = !!enabled; + }, + + /** + * 是否打开轮廓吸附 + */ + showgrid: function(enabled) { + menuUtil.setSelected(commandList.editor, 'setting.showgrid', !!enabled); + this.options.axis.showGrid = this.axis.showGrid = !!enabled; + this.axisLayer.refresh(); + }, + + /** + * 更多设置 + */ + moresetting: function(enabled) { + this.fire('setting:editor', { + setting: this.options + }); + }, + + /** + * 添加path + */ + addpath: function() { + this.setMode('addpath'); + }, + + /** + * 添加自选图形 + */ + addsupportshapes: function(type) { + if (shapesSupport[type]) { + this.setMode('addshapes', lang.clone(shapesSupport[type])); + } + }, + + /** + * 设置字体信息 + */ + fontsetting: function() { + + // 计算边界 + var box = computeBoundingBox.computePathBox.apply(null, this.fontLayer.shapes.map(function(shape) { + return shape.points; + })); + + var leftSideBearing = 0; + var rightSideBearing = 0; + + if (box) { + var scale = this.render.camera.scale; + var leftSideBearing = (box.x - this.axis.x) / scale; + var rightSideBearing = (this.rightSideBearing.p0.x - box.x - box.width) / scale; + } + + this.fire('setting:font', { + setting: { + leftSideBearing: Math.round(leftSideBearing), + rightSideBearing: Math.round(rightSideBearing || 0), + unicode: this.font.unicode, + name: this.font.name + } + }); + } + }; + } +); diff --git a/src/editor/command/shapes.js b/src/editor/command/join.js similarity index 91% rename from src/editor/command/shapes.js rename to src/editor/command/join.js index 8ced399..e8c0763 100644 --- a/src/editor/command/shapes.js +++ b/src/editor/command/join.js @@ -1,5 +1,5 @@ /** - * @file shapes.js + * @file join.js * @author mengke01 * @date * @description @@ -74,7 +74,6 @@ define( return shapes; } - var support = { /** @@ -82,6 +81,7 @@ define( */ joinshapes: function(shapes) { combineShape.call(this, shapes, pathJoin.Relation.join); + this.refreshSelected(shapes); }, /** @@ -89,6 +89,7 @@ define( */ intersectshapes: function(shapes) { combineShape.call(this, shapes, pathJoin.Relation.intersect); + this.refreshSelected(shapes); }, /** @@ -96,13 +97,15 @@ define( */ tangencyshapes: function(shapes) { combineShape.call(this, shapes, pathJoin.Relation.tangency); + this.refreshSelected(shapes); }, /** * 切割路径 */ - splitshapes: function(p0, p1, outShapes) { + splitshapes: function(p0, p1) { var shapes = this.fontLayer.shapes; + var outShapes = []; for(var i = shapes.length - 1; i >=0; i--) { var result = pathSplitBySegment(shapes[i].points, p0, p1); if (result) { @@ -122,6 +125,10 @@ define( if (outShapes.length) { this.fontLayer.refresh(); + this.setMode('shapes', outShapes); + } + else { + return false; } } }; diff --git a/src/editor/command/referenceline.js b/src/editor/command/referenceline.js new file mode 100644 index 0000000..a2cd0d0 --- /dev/null +++ b/src/editor/command/referenceline.js @@ -0,0 +1,86 @@ +/** + * @file referenceline.js + * @author mengke01 + * @date + * @description + * 参考线相关命令 + */ + + +define( + function(require) { + + + return { + /** + * 添加参考线 + */ + addreferenceline: function(x, y) { + if(x > 20) { + this.axisLayer.addShape('line', { + p0: { + x: x + }, + style: this.options.referenceline.style + }); + } + + if(y > 20) { + this.axisLayer.addShape('line', { + p0: { + y: y + }, + style: this.options.referenceline.style + }); + } + this.axisLayer.refresh(); + }, + + /** + * 移除参考线 + */ + removereferenceline: function(x, y) { + var lines = []; + // 如果传入的是shape对象 + if(typeof(x) === 'object') { + lines.push(x); + } + + var axisLayer = this.axisLayer; + var rightSideBearing = this.rightSideBearing; + + // 获取选中的参考线 + if(x > 20 || y > 20) { + var result = this.axisLayer.getShapeIn(x, y); + lines = lines.concat(result); + } + + // rightside bearing 线不可移除 + lines = lines.filter(function(line) { + return line !== rightSideBearing; + }); + + lines.forEach(function(l) { + axisLayer.removeShape(l); + }); + axisLayer.refresh(); + }, + + /** + * 清除参考线 + */ + clearreferenceline: function() { + var axisLayer = this.axisLayer; + var rightSideBearing = this.rightSideBearing; + var lines = axisLayer.shapes.filter(function(line) { + return line.type === 'line' && line !== rightSideBearing; + }); + + lines.forEach(function(l) { + axisLayer.removeShape(l); + }); + axisLayer.refresh(); + } + }; + } +); diff --git a/src/editor/command/shape.js b/src/editor/command/shape.js new file mode 100644 index 0000000..f703891 --- /dev/null +++ b/src/editor/command/shape.js @@ -0,0 +1,151 @@ +/** + * @file shape.js + * @author mengke01 + * @date + * @description + * 形状相关命令 + */ + + +define( + function(require) { + + var computeBoundingBox = require('graphics/computeBoundingBox'); + var pathAdjust = require('graphics/pathAdjust'); + + + + return { + + /** + * 移除shape + */ + removeshapes: function(shapes) { + + var fontLayer = this.fontLayer; + shapes.forEach(function(shape) { + fontLayer.removeShape(shape); + }); + fontLayer.refresh(); + this.refreshSelected([]); + this.setMode(); + }, + + /** + * 反转shape + */ + reversepoints: function(shapes) { + shapes.forEach(function(shape) { + shape.points = shape.points.reverse(); + }); + + this.fontLayer.refresh(); + }, + + /** + * 设置shape到顶层 + */ + topshape: function(shape) { + var index = this.fontLayer.shapes.indexOf(shape); + this.fontLayer.shapes.splice(index, 1); + this.fontLayer.shapes.push(shape); + }, + + /** + * 设置shape到底层 + */ + bottomshape: function(shape) { + var index = this.fontLayer.shapes.indexOf(shape); + this.fontLayer.shapes.splice(index, 1); + this.fontLayer.shapes.unshift(shape); + }, + + /** + * 提升shape层级 + */ + upshape: function(shape) { + var index = this.fontLayer.shapes.indexOf(shape); + this.fontLayer.shapes.splice(index, 1); + this.fontLayer.shapes.splice(index + 1, 0, shape); + }, + + /** + * 降低shape层级 + */ + downshape: function(shape) { + var index = this.fontLayer.shapes.indexOf(shape); + this.fontLayer.shapes.splice(index, 1); + this.fontLayer.shapes.splice(index - 1, 0, shape); + }, + + /** + * 剪切shapes + * + * @param {Array} shapes 形状集合 + */ + cutshapes: function(shapes) { + var cutedShapes = this.getShapes(shapes); + this.setClipBoard(cutedShapes); + var fontLayer = this.fontLayer; + shapes.forEach(function(shape) { + fontLayer.removeShape(shape); + }); + fontLayer.refresh(); + this.refreshSelected([]); + }, + + /** + * 复制shapes + * + * @param {Array} shapes 形状集合 + */ + copyshapes: function(shapes) { + shapes = this.getShapes(shapes); + this.setClipBoard(shapes); + }, + + /** + * 粘贴shapes + * + * @param {Array} shapes 形状集合 + */ + pasteshapes: function(shapes, pos) { + + if (!shapes || !shapes.length) { + return false; + } + + if (pos) { + var bound = computeBoundingBox.computePath.apply(null, + shapes.map(function(shape){ + return shape.points; + }) + ); + // 需要根据坐标原点以及缩放换算成鼠标位置移动 + var origin = this.axis; + var scale = this.render.camera.scale; + var x = (pos.x - origin.x) / scale; + var y = (origin.y - pos.y) / scale; + + shapes.forEach(function(shape) { + pathAdjust(shape.points, 1, 1, x - bound.x, y - bound.y - bound.height); + }); + } + + + this.setShapes(shapes); + this.setMode('shapes', shapes); + }, + + /** + * 增加shapes + * + * @param {Array} shapes 形状集合 + */ + addshapes: function(shapes) { + this.setShapes(shapes); + this.fontLayer.refresh(); + } + }; + } +); diff --git a/src/editor/command/support.js b/src/editor/command/support.js index f3145ae..487e814 100644 --- a/src/editor/command/support.js +++ b/src/editor/command/support.js @@ -9,296 +9,14 @@ define( function(require) { - var lang = require('common/lang'); - var computeBoundingBox = require('graphics/computeBoundingBox'); - var shapesSupport = require('../shapes/support'); - var menuUtil = require('../menu/util'); - var commandList = require('../menu/commandList'); - - var support = { - - /** - * 重置缩放 - */ - rescale: function() { - this.coverLayer.clearShapes(); - var size = this.render.getSize(); - var scale = 512 / this.options.unitsPerEm; - this.render.scaleTo(scale, { - x: size.width / 2, - y: size.height / 2 - }); - this.setMode(); - }, - - - /** - * 添加path - */ - addpath: function() { - this.setMode('addpath'); - }, - - /** - * 添加自选图形 - */ - addsupportshapes: function(type) { - if (shapesSupport[type]) { - this.setMode('addshapes', lang.clone(shapesSupport[type])); - } - }, - - /** - * 移除shape - */ - removeshapes: function(shapes) { - var fontLayer = this.fontLayer; - shapes.forEach(function(shape) { - fontLayer.removeShape(shape); - }); - fontLayer.refresh(); - }, - - /** - * 反转shape - */ - reversepoint: function(shapes) { - shapes.forEach(function(shape) { - shape.points = shape.points.reverse(); - }); - - this.fontLayer.refresh(); - }, - - /** - * 设置shape到顶层 - */ - topshape: function(shape) { - var index = this.fontLayer.shapes.indexOf(shape); - this.fontLayer.shapes.splice(index, 1); - this.fontLayer.shapes.push(shape); - }, - - /** - * 设置shape到底层 - */ - bottomshape: function(shape) { - var index = this.fontLayer.shapes.indexOf(shape); - this.fontLayer.shapes.splice(index, 1); - this.fontLayer.shapes.unshift(shape); - }, - - /** - * 提升shape层级 - */ - upshape: function(shape) { - var index = this.fontLayer.shapes.indexOf(shape); - this.fontLayer.shapes.splice(index, 1); - this.fontLayer.shapes.splice(index + 1, 0, shape); - }, - - /** - * 降低shape层级 - */ - downshape: function(shape) { - var index = this.fontLayer.shapes.indexOf(shape); - this.fontLayer.shapes.splice(index, 1); - this.fontLayer.shapes.splice(index - 1, 0, shape); - }, - - /** - * 撤销 - */ - undo: function() { - var shapes = this.history.back(); - this.fontLayer.shapes.length = 0; - this.setShapes(shapes); - this.setMode(); - }, - - /** - * 恢复 - */ - redo: function() { - var shapes = this.history.forward(); - this.fontLayer.shapes.length = 0; - this.setShapes(shapes); - this.setMode(); - }, - - /** - * 添加参考线 - */ - addreferenceline: function(x, y) { - if(x > 20) { - this.axisLayer.addShape('line', { - p0: { - x: x - }, - style: this.options.referenceline.style - }); - } - - if(y > 20) { - this.axisLayer.addShape('line', { - p0: { - y: y - }, - style: this.options.referenceline.style - }); - } - this.axisLayer.refresh(); - }, - - /** - * 移除参考线 - */ - removereferenceline: function(x, y) { - var lines = []; - // 如果传入的是shape对象 - if(typeof(x) === 'object') { - lines.push(x); - } - - var axisLayer = this.axisLayer; - var rightSideBearing = this.rightSideBearing; - - // 获取选中的参考线 - if(x > 20 || y > 20) { - var result = this.axisLayer.getShapeIn(x, y); - lines = lines.concat(result); - } - - // rightside bearing 线不可移除 - lines = lines.filter(function(line) { - return line !== rightSideBearing; - }); - - lines.forEach(function(l) { - axisLayer.removeShape(l); - }); - axisLayer.refresh(); - }, - - /** - * 清除参考线 - */ - clearreferenceline: function() { - var axisLayer = this.axisLayer; - var rightSideBearing = this.rightSideBearing; - var lines = axisLayer.shapes.filter(function(line) { - return line.type === 'line' && line !== rightSideBearing; - }); - - lines.forEach(function(l) { - axisLayer.removeShape(l); - }); - axisLayer.refresh(); - }, - - /** - * 剪切shapes - * - * @param {Array} shapes 形状集合 - */ - cutshapes: function(shapes) { - var cutedShapes = this.getShapes(shapes); - this.setClipBoard(cutedShapes); - var fontLayer = this.fontLayer; - shapes.forEach(function(shape) { - fontLayer.removeShape(shape); - }); - fontLayer.refresh(); - }, - - /** - * 复制shapes - * - * @param {Array} shapes 形状集合 - */ - copyshapes: function(shapes) { - shapes = this.getShapes(shapes); - this.setClipBoard(shapes); - }, - - /** - * 增加shapes - * - * @param {Array} shapes 形状集合 - */ - addshapes: function(shapes) { - this.setShapes(shapes); - }, - - /** - * 是否打开网格吸附 - */ - gridsorption: function(enabled) { - menuUtil.setSelected(commandList.editor, 'setting.gridsorption', !!enabled); - this.options.sorption.enableGrid = this.sorption.enableGrid = !!enabled; - }, - - /** - * 是否打开轮廓吸附 - */ - shapesorption: function(enabled) { - menuUtil.setSelected(commandList.editor, 'setting.shapesorption', !!enabled); - this.options.sorption.enableShape = this.sorption.enableShape = !!enabled; - }, - - /** - * 是否打开轮廓吸附 - */ - showgrid: function(enabled) { - menuUtil.setSelected(commandList.editor, 'setting.showgrid', !!enabled); - this.options.axis.showGrid = this.axis.showGrid = !!enabled; - this.axisLayer.refresh(); - }, - - /** - * 设置字体信息 - */ - setfont: function() { - - // 计算边界 - var box = computeBoundingBox.computePathBox.apply(null, this.fontLayer.shapes.map(function(shape) { - return shape.points; - })); - - var leftSideBearing = 0; - var rightSideBearing = 0; - - if (box) { - var scale = this.render.camera.scale; - var leftSideBearing = (box.x - this.axis.x) / scale; - var rightSideBearing = (this.rightSideBearing.p0.x - box.x - box.width) / scale; - } - - this.fire('setting:font', { - setting: { - leftSideBearing: Math.round(leftSideBearing), - rightSideBearing: Math.round(rightSideBearing || 0), - unicode: this.font.unicode, - name: this.font.name - } - }); - }, - - /** - * 更多设置 - */ - moresetting: function(enabled) { - this.fire('setting:editor', { - setting: this.options - }); - } - }; - + var support = {}; + lang.extend(support, require('./shape')); lang.extend(support, require('./transform')); - lang.extend(support, require('./shapes')); lang.extend(support, require('./align')); - + lang.extend(support, require('./join')); + lang.extend(support, require('./referenceline')); + lang.extend(support, require('./editor')); return support; } ); diff --git a/src/editor/command/transform.js b/src/editor/command/transform.js index 797d11d..3448b00 100644 --- a/src/editor/command/transform.js +++ b/src/editor/command/transform.js @@ -18,9 +18,12 @@ define( * 旋转图形 * * @param {Array} shapes 图形集合 - * @param {number} angle 角度 + * @param {number} angle 弧度 */ function rotate(shapes, angle) { + if (!angle) { + return false; + } var points = shapes.map(function(shape) {return shape.points;}); var bound = computeBoundingBox.computePath.apply(null, points); @@ -68,36 +71,69 @@ define( var support = { + /** + * 旋转指定角度 + * @param {Array} shapes 图形集合 + * @param {number} angle 弧度 + */ + rotate: function(shapes, angle) { + + if (!shapes || !shapes.length) { + return false; + } + + var ret = rotate(shapes, angle); + if (false !== ret) { + this.fontLayer.refresh(); + this.refreshSelected(shapes); + } + return ret; + }, + /** * 向左旋转 + * @param {Array} shapes 图形集合 */ rotateleft: function(shapes) { - rotate(shapes, - Math.PI / 2); - this.fontLayer.refresh(); + return support.rotate.call(this, shapes, - Math.PI / 2); }, /** * 向右旋转 + * @param {Array} shapes 图形集合 */ rotateright: function(shapes) { - rotate(shapes, Math.PI / 2); - this.fontLayer.refresh(); + return support.rotate.call(this, shapes, Math.PI / 2); }, /** * 翻转 + * @param {Array} shapes 图形集合 */ - reverseshapes: function(shapes) { + flipshapes: function(shapes) { + + if (!shapes || !shapes.length) { + return false; + } + mirror(shapes, 1, -1); this.fontLayer.refresh(); + this.refreshSelected(shapes); }, /** * 镜像 + * @param {Array} shapes 图形集合 */ mirrorshapes: function(shapes) { + + if (!shapes || !shapes.length) { + return false; + } + mirror(shapes, -1, 1); this.fontLayer.refresh(); + this.refreshSelected(shapes); } }; diff --git a/src/editor/controller/initBinder.js b/src/editor/controller/initBinder.js index 4dedaef..0bf3c2a 100644 --- a/src/editor/controller/initBinder.js +++ b/src/editor/controller/initBinder.js @@ -9,16 +9,29 @@ define( function(require) { - + + var commandSupport = require('../command/commandSupport'); + /** * 初始化绑定器 */ function initBinder() { var me = this; + // 保存历史记录 - this.on('change', function(e) { + me.on('change', function(e) { me.history.add(me.getShapes()); }); + + // me.on('beforecommand', function(e) { + // console.log(e.command); + // }); + + me.on('command', function(e) { + if (false !== e.result && commandSupport.history[e.command]) { + me.fire('change'); + } + }); } return initBinder; diff --git a/src/editor/controller/initRender.js b/src/editor/controller/initRender.js index 1fc62d9..afe3e88 100644 --- a/src/editor/controller/initRender.js +++ b/src/editor/controller/initRender.js @@ -13,8 +13,6 @@ define( var commandList = require('../menu/commandList'); var lang = require('common/lang'); var modeSupport = require('../mode/support'); - var pathAdjust = require('graphics/pathAdjust'); - var computeBoundingBox = require('graphics/computeBoundingBox'); var selectShape = require('render/util/selectShape'); /** @@ -22,9 +20,9 @@ define( */ function onContextMenu(e) { this.contextMenu.hide(); - if (e.command == 'add_referenceline') { - var pos = e.pos; - this.execCommand('addreferenceline', pos.x, pos.y); + + if (e.command == 'addreferenceline') { + this.execCommand('addreferenceline', e.pos.x, e.pos.y); } else if (e.command == 'split') { this.setMode('split'); @@ -32,27 +30,10 @@ define( else if (e.command == 'paste') { var shapes = this.getClipBoard(); if(shapes) { - var bound = computeBoundingBox.computePath.apply(null, - shapes.map(function(shape){ - return shape.points; - }) - ); - // 需要根据坐标原点以及缩放换算成鼠标位置移动 - var origin = this.axis; - var pos = e.pos; - var scale = this.render.camera.scale; - var x = (pos.x - origin.x) / scale; - var y = (origin.y - pos.y) / scale; - - shapes.forEach(function(shape) { - pathAdjust(shape.points, 1, 1, x - bound.x, y - bound.y - bound.height); - }); - this.setShapes(shapes); - this.setMode('shapes', shapes); - this.fire('change'); + this.execCommand('pasteshapes', shapes, e.pos); } } - else if (e.command == 'add_supportshapes') { + else if (e.command == 'addsupportshapes') { var type = e.args.type; this.execCommand('addsupportshapes', type); } @@ -214,9 +195,7 @@ define( else if (e.keyCode == 86 && e.ctrlKey) { var shapes = me.getClipBoard(); if(shapes) { - me.setShapes(shapes); - me.setMode('shapes', shapes); - me.fire('change'); + me.execCommand('pasteshapes', shapes); } } // 放大 diff --git a/src/editor/menu/editor.js b/src/editor/menu/editor.js index e6a6a8c..84f4180 100644 --- a/src/editor/menu/editor.js +++ b/src/editor/menu/editor.js @@ -19,27 +19,27 @@ define( title: '添加形状', items: [ { - name: 'add_supportshapes', + name: 'addsupportshapes', type: 'circle', title: '添加圆' }, { - name: 'add_supportshapes', + name: 'addsupportshapes', type: 'rect', title: '添加矩形' }, { - name: 'add_supportshapes', + name: 'addsupportshapes', type: 'roundrect', title: '添加圆角矩形' }, { - name: 'add_supportshapes', + name: 'addsupportshapes', type: 'star', title: '添加五角星' }, { - name: 'add_supportshapes', + name: 'addsupportshapes', type: 'arrow', title: '添加箭头' } @@ -84,7 +84,7 @@ define( ] }, { - name: 'add_referenceline', + name: 'addreferenceline', title: '添加参考线' }, { @@ -96,7 +96,7 @@ define( title: '重置缩放' }, { - name: 'setfont', + name: 'fontsetting', title: '字形信息' } ]; diff --git a/src/editor/menu/shape.js b/src/editor/menu/shape.js index d9c82423..ae17bea 100644 --- a/src/editor/menu/shape.js +++ b/src/editor/menu/shape.js @@ -11,19 +11,19 @@ define( function(require) { return [ { - name: 'remove', + name: 'removeshapes', title: '删除轮廓' }, { - name: 'reverse_point', + name: 'reversepoints', title: '改变方向' }, { - name: 'cut', + name: 'cutshapes', title: '剪切' }, { - name: 'copy', + name: 'copyshapes', title: '复制' }, { @@ -31,19 +31,19 @@ define( title: '顺序', items: [ { - name: 'top', + name: 'topshape', title: '置前' }, { - name: 'bottom', + name: 'bottomshape', title: '置后' }, { - name: 'up', + name: 'upshape', title: '上移一层' }, { - name: 'down', + name: 'downshape', title: '下移一层' } ] @@ -53,51 +53,72 @@ define( title: '变换', items: [ { - name: 'rotate_left', + name: 'rotateleft', title: '向左旋转' }, { - name: 'rotate_right', + name: 'rotateright', title: '向右旋转' }, { - name: 'reverse_shapes', + name: 'flipshapes', title: '翻转' }, { - name: 'mirror_shapes', + name: 'mirrorshapes', title: '镜像' } ] }, { - name: 'shapes_verticalalign', - title: '垂直方向', + name: 'horizontalalignshapes_', + title: '水平方向', items: [ { - name: 'shapes_verticalalign', - type: 'ascent', - title: '顶端对齐' + name: 'horizontalalignshapes', + align: 'left', + title: '左对齐' }, { - name: 'shapes_verticalalign', - type: 'middle', + name: 'horizontalalignshapes', + align: 'center', title: '居中对齐' }, { - name: 'shapes_verticalalign', - type: 'descent', + name: 'horizontalalignshapes', + align: 'right', + title: '右对齐' + } + ] + }, + { + name: 'verticalalignshapes_', + title: '垂直方向', + items: [ + { + name: 'verticalalignshapes', + align: 'ascent', + title: '顶端对齐' + }, + { + name: 'verticalalignshapes', + align: 'middle', + title: '居中对齐' + }, + { + name: 'verticalalignshapes', + align: 'descent', title: '底端对齐' }, { - name: 'shapes_verticalalign', - type: 'baseline', + name: 'verticalalignshapes', + align: 'baseline', title: '基线对齐' } ] }, { - name: 'add_referenceline', + name: 'addreferenceline', title: '添加边界参考线' } ]; diff --git a/src/editor/menu/shapes.js b/src/editor/menu/shapes.js index cc9abd6..69efa88 100644 --- a/src/editor/menu/shapes.js +++ b/src/editor/menu/shapes.js @@ -11,19 +11,19 @@ define( function(require) { return [ { - name: 'reverse_point', + name: 'reversepoints', title: '改变方向' }, { - name: 'remove', + name: 'removeshapes', title: '删除轮廓' }, { - name: 'cut', + name: 'cutshapes', title: '剪切' }, { - name: 'copy', + name: 'copyshapes', title: '复制' }, { @@ -31,15 +31,15 @@ define( title: '连接轮廓', items: [ { - name: 'join_shapes', + name: 'joinshapes', title: '结合' }, { - name: 'intersect_shapes', + name: 'intersectshapes', title: '相交' }, { - name: 'tangency_shapes', + name: 'tangencyshapes', title: '相切' } ] @@ -49,88 +49,109 @@ define( title: '变换', items: [ { - name: 'rotate_left', + name: 'rotateleft', title: '向左旋转' }, { - name: 'rotate_right', + name: 'rotateright', title: '向右旋转' }, { - name: 'reverse_shapes', + name: 'flipshapes', title: '翻转' }, { - name: 'mirror_shapes', + name: 'mirrorshapes', title: '镜像' } ] }, { - name: 'shapes_align', + name: 'alignshapes_', title: '对齐形状', items: [ { - name: 'shapes_align', - type: 'left', + name: 'alignshapes', + align: 'left', title: '左对齐' }, { - name: 'shapes_align', - type: 'center', + name: 'alignshapes', + align: 'center', title: '居中对齐' }, { - name: 'shapes_align', - type: 'right', + name: 'alignshapes', + align: 'right', title: '右对齐' }, { - name: 'shapes_align', - type: 'top', + name: 'alignshapes', + align: 'top', title: '顶部对齐' }, { - name: 'shapes_align', - type: 'middle', + name: 'alignshapes', + align: 'middle', title: '中间对齐' }, { - name: 'shapes_align', - type: 'bottom', + name: 'alignshapes', + align: 'bottom', title: '底部对齐' } ] }, { - name: 'shapes_verticalalign', - title: '垂直方向', + name: 'horizontalalignshapes_', + title: '水平方向', items: [ { - name: 'shapes_verticalalign', - type: 'ascent', - title: '顶端对齐' + name: 'horizontalalignshapes', + align: 'left', + title: '左对齐' }, { - name: 'shapes_verticalalign', - type: 'middle', + name: 'horizontalalignshapes', + align: 'center', title: '居中对齐' }, { - name: 'shapes_verticalalign', - type: 'descent', + name: 'horizontalalignshapes', + align: 'right', + title: '右对齐' + } + ] + }, + { + name: 'verticalalignshapes_', + title: '垂直方向', + items: [ + { + name: 'verticalalignshapes', + align: 'ascent', + title: '顶端对齐' + }, + { + name: 'verticalalignshapes', + align: 'middle', + title: '居中对齐' + }, + { + name: 'verticalalignshapes', + align: 'descent', title: '底端对齐' }, { - name: 'shapes_verticalalign', - type: 'baseline', + name: 'verticalalignshapes', + align: 'baseline', title: '基线对齐' } ] }, { - name: 'add_referenceline', + name: 'addreferenceline', title: '添加边界参考线' } ]; diff --git a/src/editor/mode/shapes.js b/src/editor/mode/shapes.js index 73c01f3..23a8dbf 100644 --- a/src/editor/mode/shapes.js +++ b/src/editor/mode/shapes.js @@ -31,114 +31,55 @@ define( * @param {string} command 命令 */ function onContextMenu(e) { - if(this.currentGroup.shapes.length === 0) { - return; - } - this.fire('command', e); - if(e.returnValue === false) { + if(!this.currentGroup.shapes.length) { return; } this.contextMenu.hide(); var command = e.command; - - // 是否编辑器支持 - if(this.supportCommand(command)) { - this.execCommand(command, e); - return; - } - + var args = e.args; var shapes = this.currentGroup.shapes; - var shape = shapes[0]; - if (command == 'remove') { - this.execCommand('removeshapes', shapes); - this.setMode(); + switch (command) { + case 'topshape': + case 'bottomshape': + case 'upshape': + case 'downshape': + this.execCommand(command, shapes[0]); + break; + case 'joinshapes': + case 'intersectshapes': + case 'tangencyshapes': + case 'rotateleft': + case 'rotateright': + case 'flipshapes': + case 'mirrorshapes': + case 'cutshapes': + case 'copyshapes': + case 'removeshapes': + case 'reversepoints': + this.execCommand(command, shapes); + break; + case 'alignshapes': + case 'verticalalignshapes': + case 'horizontalalignshapes': + this.execCommand(command, shapes, args.align); + break; + case 'addreferenceline': + var bound = this.currentGroup.getBound(); + if(bound) { + this.execCommand(command, bound.x, bound.y); + this.execCommand(command, bound.x + bound.width, bound.y + bound.height); + } + break; + default: + // 是否编辑器支持 + if(this.supportCommand(command)) { + this.execCommand(command, e); + } } - else if (command == 'reverse_point') { - this.execCommand('reversepoint', shapes); - } - else if (command == 'top') { - this.execCommand('topshape', shape); - } - else if (command == 'bottom') { - this.execCommand('bottomshape', shape); - } - else if (command == 'up') { - this.execCommand('upshape', shape); - } - else if (command == 'down') { - this.execCommand('downshape', shape); - } - - // 相交,结合和相切 - else if (command == 'join_shapes') { - this.execCommand('joinshapes', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'intersect_shapes') { - this.execCommand('intersectshapes', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'tangency_shapes') { - this.execCommand('tangencyshapes', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - - else if (command == 'rotate_left') { - this.execCommand('rotateleft', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'rotate_right') { - this.execCommand('rotateright', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'reverse_shapes') { - this.execCommand('reverseshapes', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'mirror_shapes') { - this.execCommand('mirrorshapes', shapes); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'add_referenceline') { - var bound = this.currentGroup.getBound(); - if(bound) { - this.execCommand('addreferenceline', bound.x, bound.y); - this.execCommand( - 'addreferenceline', - bound.x + bound.width, bound.y + bound.height - ); - } - } - else if (command == 'cut') { - this.execCommand('cutshapes', shapes); - this.setMode(); - this.fire('change'); - } - else if (command == 'copy') { - this.execCommand('copyshapes', shapes); - } - else if (command == 'shapes_align') { - this.execCommand('align', shapes, e.args.type); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - else if (command == 'shapes_verticalalign') { - this.execCommand('verticalalign', shapes, e.args.type); - this.currentGroup.setShapes(shapes); - this.currentGroup.refresh(); - } - this.fire('change'); } @@ -169,23 +110,25 @@ define( var shapeIndex = this.currentGroup.shapes.indexOf(shape); if(shapeIndex >= 0) { + // ctl多选,点选2次, !altKey 防止复制冲突 if (e.ctrlKey && !e.altKey) { this.currentGroup.shapes.splice(shapeIndex, 1); - this.currentGroup.setShapes(this.currentGroup.shapes); - this.currentGroup.refresh(); + this.refreshSelected(this.currentGroup.shapes.slice(0)); this.clicked = false; } return; } else { + var shapes = [shape]; + // 多选 if (e.ctrlKey) { shapes = shapes.concat(this.currentGroup.shapes);; } - this.currentGroup.setShapes(shapes); + this.currentGroup.setMode('scale'); - this.currentGroup.refresh(); + this.refreshSelected(shapes); this.clicked = false; return; } @@ -298,7 +241,6 @@ define( if (e.key == 'delete') { this.execCommand('removeshapes', this.currentGroup.shapes); this.setMode(); - this.fire('change'); } // 全选 else if(e.keyCode == 65 && e.ctrlKey) { @@ -322,10 +264,6 @@ define( if (e.keyCode == 88 && e.ctrlKey) { if (this.currentGroup.shapes.length) { this.execCommand('cutshapes', this.currentGroup.shapes); - this.currentGroup.shapes.length = 0; - this.coverLayer.clearShapes(); - this.coverLayer.refresh(); - this.fire('change'); } } // 复制 @@ -344,15 +282,21 @@ define( * 开始模式 */ begin: function(shapes, prevMode) { + this.currentGroup = new ShapesGroup(shapes, this); this.currentGroup.refresh(); this.currentGroup.setMode('scale'); + if (prevMode == 'bound') { this.clicked = false; } else { this.clicked = true; } + + this.fire('selection:change', { + shapes: shapes + }); }, @@ -364,8 +308,8 @@ define( this.currentPoint = null; this.currentGroup.dispose(); this.currentGroup = null; - this.render.setCursor('default'); + this.fire('selection:change'); } }; diff --git a/src/editor/mode/split.js b/src/editor/mode/split.js index 261c74b..b5e715d 100644 --- a/src/editor/mode/split.js +++ b/src/editor/mode/split.js @@ -56,12 +56,8 @@ define( var p1 = this.splitLine.p1; // 对shape进行多选 if (Math.abs(p0.x - p1.x) >= 20 || Math.abs(p0.y - p1.y) >= 20) { - var shapes = []; - this.execCommand('splitshapes', p0, p1, shapes); - if (shapes.length) { - this.setMode('shapes', shapes); - this.fire('change'); - return; + if (false !== this.execCommand('splitshapes', p0, p1)) { + return; } } } diff --git a/src/fonteditor/main.js b/src/fonteditor/main.js index 385cc2a..581e512 100644 --- a/src/fonteditor/main.js +++ b/src/fonteditor/main.js @@ -86,6 +86,7 @@ define( init: function () { bindEvent(); + // glyf查看器命令组 program.viewerCommandMenu = new CommandMenu($('#glyf-list-commandmenu'), { commands: require('./widget/menu/viewer') }); @@ -95,8 +96,15 @@ define( commandMenu: program.viewerCommandMenu }); + // 字体查看器命令组 + program.editorCommandMenu = new CommandMenu($('#editor-commandmenu'), { + commands: require('./widget/menu/editor') + }); + // 字体查看器 - program.editor = new GLYFEditor($('#glyf-editor')); + program.editor = new GLYFEditor($('#glyf-editor'), { + commandMenu: program.editorCommandMenu + }); // 项目管理 program.project = require('./widget/project'); diff --git a/src/fonteditor/widget/actions.js b/src/fonteditor/widget/actions.js index aadd763..8aec796 100644 --- a/src/fonteditor/widget/actions.js +++ b/src/fonteditor/widget/actions.js @@ -47,11 +47,28 @@ define( var actions = { 'undo': function() { - program.ttfManager.undo(); + if (program.editor.isEditing()) { + program.editor.undo(); + setTimeout(function(){ + program.editor.focus(); + }, 20); + + } + else { + program.ttfManager.undo(); + } }, 'redo': function() { - program.ttfManager.redo(); + if (program.editor.isEditing()) { + program.editor.redo(); + setTimeout(function(){ + program.editor.focus(); + }, 20); + } + else { + program.ttfManager.redo(); + } }, // 新建 diff --git a/src/fonteditor/widget/commandmenu.js b/src/fonteditor/widget/commandmenu.js index c5657e2..7c0e1f3 100644 --- a/src/fonteditor/widget/commandmenu.js +++ b/src/fonteditor/widget/commandmenu.js @@ -41,7 +41,7 @@ define( command.on = false; me.fire('command:un', { command: name, - + args: command }); return; } @@ -86,13 +86,28 @@ define( commands = commands || this.commands; var str = ''; commands.forEach(function(item, i) { - str += '
  • ' - + item.title - + (item.quickKey ? '('+ item.quickKey +')' : '') - +'
  • '; + + if (item.type === 'split') { + str += '
  • '; + } + else { + + str += '
  • '; + + if (item.ico) { + str += ''; + } + else { + str += item.title + + (item.quickKey ? '('+ item.quickKey +')' : ''); + } + + str +='
  • '; + } }); this.main.html(str); this.commands = commands; diff --git a/src/fonteditor/widget/glyfeditor.js b/src/fonteditor/widget/glyfeditor.js index f1cefea..5fb8ab8 100644 --- a/src/fonteditor/widget/glyfeditor.js +++ b/src/fonteditor/widget/glyfeditor.js @@ -14,6 +14,21 @@ define( var editorOptions = require('editor/options'); var setting = require('./setting'); var program = require('./program'); + var lang = require('common/lang'); + + + // 支持的命令列表 + var COMMAND_SUPPORT = { + // 形状组 + shapes: [ + 'copyshapes', 'removeshapes', + 'horizontalalignshapes', 'verticalalignshapes', + 'rotateleft', 'rotateright', 'flipshapes', 'mirrorshapes' + ], + // 单个形状 + shape: ['upshape', 'downshape', 'reversepoints'] + }; + /** * 绑定editor编辑器 @@ -49,6 +64,87 @@ define( editor: e.setting }); }); + + var commandMenu = this.options.commandMenu; + if (commandMenu) { + + editor.on('selection:change', lang.debounce(function(e) { + var length = e.shapes ? e.shapes.length : 0; + if (!length) { + commandMenu.disableCommands(COMMAND_SUPPORT.shapes); + commandMenu.disableCommands(COMMAND_SUPPORT.shape); + } + else { + commandMenu.enableCommands(COMMAND_SUPPORT.shapes); + commandMenu[length === 1 ? 'enableCommands' : 'disableCommands'](COMMAND_SUPPORT.shape); + } + }), 100); + + commandMenu.on('command', function(e) { + + var command = e.command; + var args = e.args; + var shapes; + + if (command === 'pasteshapes') { + shapes = editor.getClipBoard(); + } + else { + shapes = editor.getSelected(); + } + + if (shapes && shapes.length) { + switch (command) { + case 'topshape': + case 'bottomshape': + case 'upshape': + case 'downshape': + editor.execCommand(command, shapes[0]); + break; + + case 'copyshapes': + case 'pasteshapes': + case 'removeshapes': + case 'joinshapes': + case 'intersectshapes': + case 'tangencyshapes': + case 'rotateleft': + case 'rotateright': + case 'flipshapes': + case 'mirrorshapes': + case 'cutshapes': + case 'copyshapes': + case 'removeshapes': + case 'reversepoints': + editor.execCommand(command, shapes); + break; + + case 'alignshapes': + case 'verticalalignshapes': + case 'horizontalalignshapes': + editor.execCommand(command, shapes, args.align); + break; + } + } + + // 这里延时进行focus + setTimeout(function() { + me.focus(); + }, 20); + }); + } + + } + + /** + * 执行指定命令 + * + * @param {string} command 命令名 + */ + function execCommand(command) { + if (this.editor) { + this.editor.execCommand.apply(this.editor, arguments); + } } /** @@ -122,6 +218,20 @@ define( this.editor && this.editor.blur(); }; + /** + * 撤销 + */ + GLYFEditor.prototype.undo = function() { + execCommand.call(this, 'undo'); + }; + + /** + * 重做 + */ + GLYFEditor.prototype.redo = function() { + execCommand.call(this, 'redo'); + }; + /** * 设置项目 * @param {Object} options 参数集合 diff --git a/src/fonteditor/widget/glyfviewer.js b/src/fonteditor/widget/glyfviewer.js index 5dfd97d..356af2f 100644 --- a/src/fonteditor/widget/glyfviewer.js +++ b/src/fonteditor/widget/glyfviewer.js @@ -293,13 +293,13 @@ define( var selected = me.getSelected(); if (selected.length) { commandMenu.enableCommands(['copy', 'cut', 'del']); - commandMenu[selected.length === 1 ? 'enableCommands' : 'disableCommands'](['info']); + commandMenu[selected.length === 1 ? 'enableCommands' : 'disableCommands'](['fontsetting']); } else { - commandMenu.disableCommands(['copy', 'cut', 'del', 'info']); + commandMenu.disableCommands(['copy', 'cut', 'del', 'fontsetting']); } - }, 20)); + }, 100)); commandMenu.on('command', function(e) { var command = e.command; diff --git a/src/fonteditor/widget/menu/editor.js b/src/fonteditor/widget/menu/editor.js new file mode 100644 index 0000000..cdc185c --- /dev/null +++ b/src/fonteditor/widget/menu/editor.js @@ -0,0 +1,132 @@ +/** + * @file viewer.js + * @author mengke01 + * @date + * @description + * glyf编辑器相关命令 + */ + + +define( + function(require) { + return [ + { + name: 'copyshapes', + title: '复制', + quickKey: 'C', + disabled: true + }, + { + name: 'pasteshapes', + title: '粘贴', + quickKey: 'V' + }, + { + name: 'removeshapes', + title: '删除', + quickKey: 'D', + disabled: true + }, + { + type: 'split' + }, + { + name: 'upshape', + title: '上移一层', + ico: 'upshape', + disabled: true + }, + { + name: 'downshape', + title: '下移一层', + ico: 'downshape', + disabled: true + }, + { + name: 'reversepoints', + title: '改变方向', + ico: 'reversepoints', + disabled: true + }, + { + type: 'split' + }, + { + name: 'horizontalalignshapes', + title: '左对齐', + ico: 'alignleft', + align: 'left', + disabled: true + }, + { + name: 'horizontalalignshapes', + title: '居中对齐', + ico: 'aligncenter', + align: 'center', + disabled: true + }, + { + name: 'horizontalalignshapes', + title: '右对齐', + ico: 'alignright', + align: 'right', + disabled: true + }, + { + name: 'verticalalignshapes', + title: '顶端对齐', + ico: 'aligntop', + align: 'ascent', + disabled: true + }, + { + name: 'verticalalignshapes', + title: '居中对齐', + ico: 'alignmiddle', + align: 'middle', + disabled: true + }, + { + name: 'verticalalignshapes', + title: '底端对齐', + ico: 'aligndescent', + align: 'descent', + disabled: true + }, + { + name: 'verticalalignshapes', + title: '基线对齐', + ico: 'alignbaseline', + align: 'baseline', + disabled: true + }, + { + type: 'split' + }, + { + name: 'rotateleft', + title: '向左旋转', + ico: 'rotateleft', + disabled: true + }, + { + name: 'rotateright', + title: '向右旋转', + ico: 'rotateright', + disabled: true + }, + { + name: 'flipshapes', + title: '翻转', + ico: 'flip', + disabled: true + }, + { + name: 'mirrorshapes', + title: '镜像', + ico: 'mirror', + disabled: true + } + ]; + } +); diff --git a/src/fonteditor/widget/menu/viewer.js b/src/fonteditor/widget/menu/viewer.js index c7d8fcd..b4628a4 100644 --- a/src/fonteditor/widget/menu/viewer.js +++ b/src/fonteditor/widget/menu/viewer.js @@ -9,40 +9,44 @@ define( function(require) { + return [ { - name: "copy", - title: "复制", + name: 'copy', + title: '复制', quickKey: 'C', disabled: true }, { - name: "cut", - title: "剪切", + name: 'cut', + title: '剪切', quickKey: 'X' }, { - name: "paste", - title: "粘贴", + name: 'paste', + title: '粘贴', quickKey: 'V' }, { - name: "del", - title: "删除", + name: 'del', + title: '删除', quickKey: 'D', disabled: true }, { - name: "adjust-pos", - title: "调整位置" + type: 'split' }, { - name: "adjust-glyf", - title: "调整字形" + name: 'adjust-pos', + title: '调整位置' }, { - name: "info", - title: "字形信息", + name: 'adjust-glyf', + title: '调整字形' + }, + { + name: 'fontsetting', + title: '字形信息', disabled: true } ];