Hi @richard ! I had a question about custom blocks in extensions.
I’m working on a MathX extension, and I’d like users to be able to define reusable formulas in Blocks, something conceptually like:
define formula "square" with input x
x × x
Then later evaluate it with something like:
evaluate formula "square" with 5
I tried using callback handlers (handlerStatement, draggableParameters, etc.), but I ran into the issue that the callback only provides the evaluated value and not the expression itself, so I can’t store the formula for later evaluation.
Is there a supported way for an extension to create a block like this, or would it require custom Blockly/PXT changes? If it isn’t currently possible, is there a recommended approach for implementing something similar in a MakeCode extension?
Thanks!
Code:
// CUSTOM FUNCTIONS
type FormulaFn = (x: number) => number
let formulas: { [key: string]: FormulaFn } = {}
let currentFormula = ""
let currentInput = 0
/**
* Define a formula
*/
//% blockId=mathx_define_formula
//% block="define formula $name with input $x"
//% handlerStatement=1
//% draggableParameters="reporter"
//% group="Create"
//% subcategory="Custom Functions"
//% name.shadow="text"
//% x.defl="x"
export function defineFormula(name: string, handler: (x: number) => void): void {
currentFormula = name
// Run once so "set result" executes while defining.
handler(0)
currentFormula = ""
}
/**
* Formula input
*/
//% blockId=mathx_formula_input
//% block="input"
//% group="Create"
//% subcategory="Custom Functions"
export function input(): number {
return currentInput
}
/**
* Set formula result
*/
//% blockId=mathx_set_formula_result
//% block="set result to $value"
//% group="Create"
//% subcategory="Custom Functions"
//% value.shadow="math_number"
export function setFormulaResult(value: number): void {
if (!currentFormula)
return
formulas[currentFormula] = (x: number) => {
currentInput = x
return value
}
}
/**
* Evaluate formula
*/
//% blockId=mathx_eval_formula
//% block="evaluate formula $name with $x"
//% group="Run"
//% subcategory="Custom Functions"
//% name.shadow="text"
//% x.shadow="math_number"
export function evalFormula(name: string, x: number): number {
let fn = formulas[name]
if (!fn)
return 0
return fn(x)
}
Github: (I haven’t pushed the changes yet for it)