diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 53b5a877..90fd905f 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -927,7 +927,7 @@ return code+',\n'; */; text_1_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? BGNL? Newline EvalString_Multi Newline + : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? BGNL? Newline EvalString_Multi Newline /* text_1_s @@ -935,7 +935,7 @@ tooltip : text:显示一段文字(剧情),选项较多请右键点击帮 helpUrl : /_docs/#/instruction doubleclicktext : EvalString_Multi_0 allIds : ['EvalString_1'] -default : ["小妖精","fairy","","欢迎使用事件编辑器(回车直接多行编辑)"] +default : ["小妖精","fairy","","","","","欢迎使用事件编辑器(回车直接多行编辑)"] var title=''; if (EvalString_0==''){ if (EvalString_1=='' )title=''; @@ -944,13 +944,21 @@ if (EvalString_0==''){ if (EvalString_1=='')title='\\t['+EvalString_0+']'; else title='\\t['+EvalString_0+','+EvalString_1+']'; } +var pos = ''; +if (PosString_0 || PosString_1) { + if (EvalString_2) throw new Error('对话框效果和起点像素位置只能设置一项!'); + pos = '[' + (PosString_0||0) + ',' + (PosString_1||0); + if (PosString_2) pos += ',' + PosString_2; + pos += ']'; +} if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.test(EvalString_2))) { throw new Error('对话框效果的用法请右键点击帮助'); } EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); var code = '"'+title+EvalString_2+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled()) { +if (block.isCollapsed() || !block.isEnabled() || pos) { code = '{"type": "text", "text": '+code; + if (pos) code += ', "pos": ' + pos; if (block.isCollapsed()) code += ', "_collapsed": true'; if (!block.isEnabled()) code += ', "_disabled": true'; code += '}'; @@ -959,7 +967,7 @@ return code+',\n'; */; text_2_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline + : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline /* text_2_s @@ -968,7 +976,7 @@ helpUrl : /_docs/#/instruction doubleclicktext : EvalString_Multi_0 allIds : ['EvalString_1'] menu : [['预览所有立绘','editor_blockly.previewBlock(block)']] -default : ["小妖精","fairy","","欢迎使用事件编辑器(回车直接多行编辑)",null] +default : ["小妖精","fairy","","","","","欢迎使用事件编辑器(回车直接多行编辑)",null] var title=''; if (EvalString_0==''){ if (EvalString_1=='' )title=''; @@ -977,13 +985,21 @@ if (EvalString_0==''){ if (EvalString_1=='')title='\\t['+EvalString_0+']'; else title='\\t['+EvalString_0+','+EvalString_1+']'; } +var pos = ''; +if (PosString_0 || PosString_1) { + if (EvalString_2) throw new Error('对话框效果和起点像素位置只能设置一项!'); + pos = '[' + (PosString_0||0) + ',' + (PosString_1||0); + if (PosString_2) pos += ',' + PosString_2; + pos += ']'; +} if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.test(EvalString_2))) { throw new Error('对话框效果的用法请右键点击帮助'); } EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); var code = '"'+title+EvalString_2+textDrawingList_0.replace(/\s/g, '')+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled()) { +if (block.isCollapsed() || !block.isEnabled() || pos) { code = '{"type": "text", "text": '+code; + if (pos) code += ', "pos": ' + pos; if (block.isCollapsed()) code += ', "_collapsed": true'; if (!block.isEnabled()) code += ', "_disabled": true'; code += '}'; diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js index da3869e1..4ce7e408 100644 --- a/_server/MotaActionParser.js +++ b/_server/MotaActionParser.js @@ -281,12 +281,14 @@ ActionParser.prototype.parseAction = function() { } return text_choices; } + data.pos = data.pos || []; this.next = MotaActionFunctions.xmlText('text_2_s', [ - info[0], info[1], info[2], info[3], buildTextDrawing(textDrawing), this.next + info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], info[3], buildTextDrawing(textDrawing), this.next ], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); - } else if (info[0] || info[1] || info[2]) { + } else if (info[0] || info[1] || info[2] || data.pos) { + data.pos = data.pos || []; this.next = MotaActionFunctions.xmlText('text_1_s',[ - info[0], info[1], info[2], info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); + info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); } else { this.next = MotaActionFunctions.xmlText('text_0_s', [info[3],this.next], diff --git a/libs/events.js b/libs/events.js index 0557c8a9..f25b4c25 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1354,7 +1354,7 @@ events.prototype.__action_doAsyncFunc = function (isAsync, func) { events.prototype._action_text = function (data, x, y, prefix) { if (this.__action_checkReplaying()) return; data.text = core.replaceText(data.text, prefix); - core.ui.drawTextBox(data.text, data.showAll); + core.ui.drawTextBox(data.text, data); if (!data.showAll) core.ui._animateUI('show'); } diff --git a/libs/ui.js b/libs/ui.js index 1b9f3187..18e88fb5 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -743,10 +743,8 @@ ui.prototype.drawText = function (contents, callback) { } var data=core.status.event.data.list.shift(); - if (typeof data == 'string') - core.ui.drawTextBox(data); - else - core.ui.drawTextBox(data.content, data.id); + if (typeof data == 'string') data = { "text": data }; + core.ui.drawTextBox(data.text, data); } ui.prototype._drawText_setContent = function (contents, callback) { @@ -1407,7 +1405,8 @@ ui.prototype._animateUI = function (type, callback) { } ////// 绘制一个对话框 ////// -ui.prototype.drawTextBox = function(content, showAll) { +ui.prototype.drawTextBox = function(content, config) { + config = config || {}; if (core.status.event && core.status.event.id == 'action') core.status.event.ui = content; @@ -1422,6 +1421,11 @@ ui.prototype.drawTextBox = function(content, showAll) { if (posInfo.position != 'up' && posInfo.position != 'down') posInfo.px = posInfo.py = null; if (!posInfo.position) posInfo.position = textAttribute.position; content = this._drawTextBox_drawImages(posInfo.content); + if (config.pos) { + delete posInfo.px; + delete posInfo.py; + posInfo.pos = config.pos; + } // Step 2: 计算对话框的矩形位置 var hPos = this._drawTextBox_getHorizontalPosition(content, titleInfo, posInfo); @@ -1439,7 +1443,7 @@ ui.prototype.drawTextBox = function(content, showAll) { // Step 5: 绘制正文 var config = this.drawTextContent('ui', content, { left: hPos.content_left, top: content_top, maxWidth: hPos.validWidth, - lineHeight: vPos.lineHeight, time: (showAll || textAttribute.time<=0 || core.status.event.id!='action')?0:textAttribute.time + lineHeight: vPos.lineHeight, time: (config.showAll || textAttribute.time<=0 || core.status.event.id!='action')?0:textAttribute.time }); // Step 6: 绘制光标 @@ -1475,22 +1479,32 @@ ui.prototype._drawTextBox_drawImages = function (content) { ui.prototype._drawTextBox_getHorizontalPosition = function (content, titleInfo, posInfo) { var realContent = this._getRealContent(content); var paddingLeft = 25, paddingRight = 12; - if (posInfo.px != null && posInfo.py != null) paddingLeft = 20; + if ((posInfo.px != null && posInfo.py != null) || posInfo.pos) paddingLeft = 20; if (titleInfo.icon != null) paddingLeft = 62; // 15 + 32 + 15 else if (titleInfo.image) paddingLeft = 90; // 10 + 70 + 10 var left = 7 + 3 * (this.HSIZE - 6), right = this.PIXEL - left, width = right - left, validWidth = width - paddingLeft - paddingRight; // 对话框效果:改为动态计算 - if (posInfo.px != null && posInfo.py != null) { + if ((posInfo.px != null && posInfo.py != null) || posInfo.pos) { var min_width = 220 - paddingLeft, max_width = validWidth; // 无行走图或头像,则可以适当缩小min_width if (titleInfo.image == null) min_width = 160; if (titleInfo.title) { min_width = core.clamp(core.calWidth('ui', titleInfo.title, this._buildFont(core.status.textAttribute.titlefont, true)), min_width, max_width); } - validWidth = this._calTextBoxWidth('ui', realContent, min_width, max_width, this._buildFont()); - width = validWidth + paddingLeft + paddingRight; - left = core.clamp(32 * posInfo.px + 16 - width / 2 - core.bigmap.offsetX, left, right - width); + if (posInfo.pos) { + left = core.calValue(posInfo.pos[0]) || 0; + max_width = Math.max(min_width, right - left - paddingLeft - paddingRight); + } else left = null; + if (posInfo.pos && posInfo.pos[2] != null) { + width = core.calValue(posInfo.pos[2]) || 0; + validWidth = width - paddingLeft - paddingRight; + } else validWidth = 0; + if (validWidth < min_width) { + validWidth = this._calTextBoxWidth('ui', realContent, min_width, max_width, this._buildFont()); + width = validWidth + paddingLeft + paddingRight; + } + if (left == null) left = core.clamp(32 * posInfo.px + 16 - width / 2 - core.bigmap.offsetX, left, right - width); right = left + width; } return { left: left, right: right, width: width, validWidth: validWidth, xoffset: 11, content_left: left + paddingLeft }; @@ -1527,6 +1541,9 @@ ui.prototype._drawTextBox_getVerticalPosition = function (content, titleInfo, po top = 32 * posInfo.py + 32 + yoffset - core.bigmap.offsetY; } } + if (posInfo.pos) { + top = core.calValue(posInfo.pos[1]) || 0; + } return { top: top, height: height, bottom: top + height, yoffset: yoffset, lineHeight: lineHeight }; } diff --git a/runtime.d.ts b/runtime.d.ts index 3a7fd6ee..1aa0bfcc 100644 --- a/runtime.d.ts +++ b/runtime.d.ts @@ -2247,7 +2247,7 @@ declare class ui { getTextContentHeight(content: string, config?: any): void /** 绘制一个对话框 */ - drawTextBox(content: string, showAll?: boolean): void + drawTextBox(content: string, config?: any): void /** 绘制滚动字幕 */ drawScrollText(content: string, time: number, lineHeight?: number, callback?: () => any): void