Fix(boards): 修复所有板卡在使用函数块进行复制时一定概率出现块渲染异常

This commit is contained in:
王立帮
2025-02-25 12:04:24 +08:00
parent 08a2e18af9
commit 0033cff33a
42 changed files with 480 additions and 215 deletions

View File

@@ -9,7 +9,7 @@
* @author fraser@google.com (Neil Fraser)
*/
import * as Blockly from 'blockly/core';
import Procedures from '../others/procedures';
import { Variables, Procedures } from 'blockly/core';
export const procedures_defnoreturn = {
/**
@@ -66,7 +66,6 @@ export const procedures_defnoreturn = {
* @this {Blockly.Block}
*/
updateParams_: function () {
// Merge the arguments into a human-readable list.
var paramString = '';
if (this.arguments_.length) {
@@ -139,6 +138,58 @@ export const procedures_defnoreturn = {
// Show or hide the statement input.
this.setStatements_(xmlElement.getAttribute('statements') !== 'false');
},
/**
* Returns the state of this block as a JSON serializable object.
*
* @returns The state of this block, eg the parameters and statements.
*/
saveExtraState: function () {
if (!this.argumentVarModels_.length && this.hasStatements_) {
return null;
}
const state = Object.create(null);
if (this.argumentVarModels_.length) {
state['params'] = [];
for (let i = 0; i < this.argumentVarModels_.length; i++) {
state['params'].push({
// We don't need to serialize the name, but just in case we decide
// to separate params from variables.
'name': this.argumentVarModels_[i].name,
'id': this.argumentVarModels_[i].getId(),
});
}
}
if (!this.hasStatements_) {
state['hasStatements'] = false;
}
return state;
},
/**
* Applies the given state to this block.
*
* @param state The state to apply to this block, eg the parameters
* and statements.
*/
loadExtraState: function (state) {
this.arguments_ = [];
this.argumentVarModels_ = [];
if (state['params']) {
for (let i = 0; i < state['params'].length; i++) {
const param = state['params'][i];
const variable = Variables.getOrCreateVariablePackage(
this.workspace,
param['id'],
param['name'],
'',
);
this.arguments_.push(variable.name);
this.argumentVarModels_.push(variable);
}
}
this.updateParams_();
Procedures.mutateCallers(this);
this.setStatements_(state['hasStatements'] !== false);
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.
@@ -596,7 +647,6 @@ export const procedures_callnoreturn = {
this.quarkIds_ = null;
this.previousEnabledState_ = true;
},
/**
* Returns the name of the procedure this block calls.
* @return {string} Procedure name.
@@ -635,52 +685,52 @@ export const procedures_callnoreturn = {
// Data structures:
// this.arguments = ['x', 'y']
// Existing param names.
// this.quarkConnections_ {piua: null, f8b_: Blockly.Connection}
// this.quarkConnections_ {piua: null, f8b_: Connection}
// Look-up of paramIds to connections plugged into the call block.
// this.quarkIds_ = ['piua', 'f8b_']
// Existing param IDs.
// Note that quarkConnections_ may include IDs that no longer exist, but
// which might reappear if a param is reattached in the mutator.
var defBlock = Procedures.getDefinition(this.getProcedureCall(),
this.workspace);
const defBlock = Procedures.getDefinition(
this.getProcedureCall(),
this.workspace,
);
const mutatorIcon = defBlock && defBlock.getIcon(Blockly.icons.MutatorIcon.TYPE);
const mutatorOpen =
mutatorIcon && mutatorIcon.bubbleIsVisible();
const mutatorOpen = mutatorIcon && mutatorIcon.bubbleIsVisible();
if (!mutatorOpen) {
this.quarkConnections_ = {};
this.quarkIds_ = null;
}
if (!paramIds) {
// Reset the quarks (a mutator is about to open).
return;
} else {
// fix #6091 - this call could cause an error when outside if-else
// expanding block while mutating prevents another error (ancient fix)
this.setCollapsed(false);
}
// Test arguments (arrays of strings) for changes. '\n' is not a valid
// argument name character, so it is a valid delimiter here.
if (paramNames.join('\n') == this.arguments_.join('\n')) {
if (paramNames.join('\n') === this.arguments_.join('\n')) {
// No change.
this.quarkIds_ = paramIds;
return;
}
if (paramIds.length != paramNames.length) {
if (paramIds.length !== paramNames.length) {
throw Error('paramNames and paramIds must be the same length.');
}
this.setCollapsed(false);
if (!this.quarkIds_) {
// Initialize tracking for this block.
this.quarkConnections_ = {};
this.quarkIds_ = [];
}
// Switch off rendering while the block is rebuilt.
var savedRendered = this.rendered;
this.rendered = false;
// Update the quarkConnections_ with existing connections.
for (var i = 0; i < this.arguments_.length; i++) {
var input = this.getInput('ARG' + i);
for (let i = 0; i < this.arguments_.length; i++) {
const input = this.getInput('ARG' + i);
if (input) {
var connection = input.connection.targetConnection;
const connection = input?.connection?.targetConnection;
this.quarkConnections_[this.quarkIds_[i]] = connection;
if (mutatorOpen && connection &&
paramIds.indexOf(this.quarkIds_[i]) == -1) {
if (
mutatorOpen &&
connection &&
!paramIds.includes(this.quarkIds_[i])
) {
// This connection should no longer be attached to this block.
connection.disconnect();
connection.getSourceBlock().bumpNeighbours();
@@ -701,22 +751,18 @@ export const procedures_callnoreturn = {
this.quarkIds_ = paramIds;
// Reconnect any child blocks.
if (this.quarkIds_) {
for (var i = 0; i < this.arguments_.length; i++) {
var quarkId = this.quarkIds_[i];
for (let i = 0; i < this.arguments_.length; i++) {
const quarkId = this.quarkIds_[i]; // TODO(#6920)
if (quarkId in this.quarkConnections_) {
var connection = this.quarkConnections_[quarkId];
if (connection && !connection.reconnect(this, 'ARG' + i)) {
// TODO(#6920): investigate claimed circular initialisers.
const connection = this.quarkConnections_[quarkId];
if (!connection?.reconnect(this, 'ARG' + i)) {
// Block no longer exists or has been attached elsewhere.
delete this.quarkConnections_[quarkId];
}
}
}
}
// Restore rendering and show the changes.
this.rendered = savedRendered;
if (this.rendered) {
this.render();
}
},
/**
* Modify this block to have the correct number of arguments.
@@ -798,6 +844,35 @@ export const procedures_callnoreturn = {
}
this.setProcedureParameters_(args, paramIds);
},
/**
* Returns the state of this block as a JSON serializable object.
*
* @returns The state of this block, ie the params and procedure name.
*/
saveExtraState: function () {
const state = Object.create(null);
state['name'] = this.getProcedureCall();
if (this.arguments_.length) {
state['params'] = this.arguments_;
}
return state;
},
/**
* Applies the given state to this block.
*
* @param state The state to apply to this block, ie the params and
* procedure name.
*/
loadExtraState: function (state) {
this.renameProcedure(this.getProcedureCall(), state['name']);
const params = state['params'];
if (params) {
const ids = [];
ids.length = params.length;
ids.fill(null); // TODO(#6920)
this.setProcedureParameters_(params, ids);
}
},
/**
* Return all variables referenced by this block.
* @return {!Array<string>} List of variable names.