Closed ksraj123 closed 3 years ago
Looks good. Try to list the variables that the model and view classes need to maintain, methods in each to communicate certain things with the other, and methods the block component as a whole needs in order to communicate (bidirectionally) with the monitor.
You can follow the component pattern for handling syntax as in the engine. Basically, you'd have one component that deals with one individual block of any of the available block types supported (syntaxElement
in engine, Block
in MB v3), another component that deals with the arrangement of several blocks (AST
in engine, Blocks
in MB v3), and some helper components like syntaxElementFactory
in engine which deals with instantiating new individual blocks, and syntaxHandler
in engine which deals with supervising and bookkeeping. The monitor only talks to the supervisor component, the rest are private to the component as a whole and are handled internally.
All these together will comprise the Block Framework. The engine isn't concerned with how the blocks look or where they are positioned but handles intricate challenges regarding the attachment-detachment of blocks. The prior are your client-side framework objectives, the latter are engine-side framework objectives.
A few things:
In the block Backend Model, we will want to have default values for the block and default arguments for any block arguments. We also want to store the generic labels for the block, which would be translated and rendered in the Viewer. The Client Model will hold the current value of a block; how that is rendered is still up to the Viewer.
In MB 3, the value stored in a block is also used to reconstruct the overall MB environment when a project is loaded, e.g., the position, heading, pen attributes, etc. of a turtle are saved in the corresponding Start block. Image and Sample blocks can end up with very unwieldy payloads.
We may want to revisit this in terms of how we save/restore state (but we will want some level of backward compatibility).
The position of the block would be in the Viewer.
I am on the fence regarding the block connections: in MB 3, the connections are in the individual blocks; Not sure that makes sense. That could all live in the Blocks Model.
Value blocks connect as arguments to other blocks, no block connects to top or bottom of value blocks.
category: // One of Value, Flow, Clamp etc
type: // unique for every block type, ex - heading, number, rightpos, width, text, solfege etc
title: // a title to be displayed in the block body
helpString:
tooltip: // displayed when hovered over the blocks
color: // color of the block
output: // present only for Value and Left Blocks which connect as arguments to other blocks,
// denotes what kind of value they return number, solfege, string, boolean etc.
defaultValue:
click: // menu | input | null - what happens on clicking on the value block, clicking on solfege block makes a menu appear, clicking on text or number box lets us type the input
menuOptions: // if this key is present and not null then clicking on the block makes a menu appear options for which are specified here, view handles exactly what kind of menu to show
Examples -
category: "value",
type: "solfege",
title: null,
helpString: "Pitch can be specified in terms of do re mi fa sol la ti.",
tooltip: "Solfege",
colour: "#7cd622",
output: "solfege",
defaultValue: "sol",
click: "menu",
menuOptions: [
["do", "re", "mi", "fa", "sol", "la", "ti"],
[
{tooltip: "double sharp", label: DOUBLESHARP},
{tooltip: "sharp", label: SHARP},
{tooltip: "natural", label: NATURAL},
{tooltip: "flat", label: FLAT},
{tooltip: "double flat", label: DOUBLEFLAT}
],
["8", "7", "6", "5", "4", "3", "2", "1"]
]
category: "value",
type: "heading",
title: "heading",
helpString: "The Heading block returns the orientation of the mouse.",
tooltip: "Heading",
colour: "#92a9ff",
output: "number",
defaultValue: null,
click: null
category: "value",
type: "number",
title: null,
helpString: "The Number block holds a number.",
tooltip: "Number",
colour: "#fe6ea1",
output: "number",
defaultValue: 0,
click: "input"
Left block take value blocks or other left blocks as arguments and give an output to the block they are connected to. No other blocks could be attached to top and bottom of left blocks.
category:
type:
title:
helpString:
tooltip:
color:
output:
args: [ // an aray of arguments, one element for every argument exepected
{
types: // an array containing types of value blocks that can be attached or any
input: // type of input expected? number, solfege, any
name: // name using which this argument would be reffered to
title: // title for the arg to be displayed in block's body
constraints: // additioanl constratins like minValue, maxValue or one of could be applied on arg depending upon the situation
}
]
Examples -
Any block that returns a number could be connected to the random block.
category: "left",
type: "random",
title: "random",
helpString: "The Random block returns a random number.",
tooltip: "Random",
color: "#fe6ea1",
output: "number",
args: [
{
types: "any",
input: "number",
"name": "min",
title: "min",
constraints: null
},
{
types: "any",
input: "number",
"name": "max",
title: "max",
constraints: null
}
]
category: "left",
type: "division",
title: "/",
helpString: "The Divide block is used to divide.",
tooltip: "Division",
color: "#fe6ea1",
output: "number",
args: [
{
types: "any",
input: "number",
"name": "dividend",
title: null,
constraints: null
},
{
types: "any",
input: "number",
"name": "divisor",
title: null,
constraints: {
exclude: 0
}
}
]
Other Blocks could be connected to top and bottom of flow blocks, flow block may or may not take arguments.
category:
type:
title:
helpString:
tooltip:
color:
args:
previousTypes: // an array containing types of block that could connect to top or any
nextTypes: // an array containing types of block tthat could connect to bottom or any
category: "flow",
type: "pitch",
title: "pitch",
helpString: "The Divide block is used to divide.",
tooltip: "Pitch",
color: "#7cd622",
args: [
{
types: ["solfege"],
input: "solfege",
"name": "name",
title: "name",
constraints: {
oneOf: ["do", "re", "mi", "fa", "sol", "la", "ti"]
}
},
{
types: "any",
input: "number",
"name": "octave",
title: "octave",
constraints: {
minValue: 1,
minValue: 8
}
}
]
previousTypes: "any",
nextTypes: "any"
Clamp blocks are blocks within which other blocks can be nested. Clamp Blocks may or may not take in arguments. We have two types of Clamp blocks in music block -
previousTypes
and nextTypes
as null.In the current version of music block, any Flow or FlowClamp block could be nested inside a Clamp Block. Below is an example of such absurd situation, inside a note block there should be one or more pitch blocks
Ideally there should be a way to prevent this from happening or at least warn the user about syntax issues.
category:
type:
title:
helpString:
tooltip:
color:
args:
previousTypes:
nextTypes:
nestedTypes: // an array containing all the top level block types that could be nested inside the clamp block or any, if a block of any other type is nested then we will get a syntax warning
Example -
category: "clamp",
type: "note",
title: "Note",
helpString: "The Note block is a container for one or more Pitch blocks. The Note block specifies the duration (note value) of its contents",
tooltip: "Note",
color: "#fe994f",
args: [
{
types: "any",
input: "number",
name: "value",
title: "value",
constraints: {
minValue: 0 // duration of note can't be negative
}
]
previousTypes: "any",
nextTypes: "any",
nestedTypes: ["pitch", "note"]
This is a great start. A few more ideas re constraints:
We can support defaultValues, defaultTypes (e.g., int vs. float), defaultMin, defaulltMax
We may want to define type convertors too: shuld we try to convert ASCII 1 into int 1? Prob. yes for some blocks and no for others. It gets messy for the various representations of pitch.
Boxes are also problematic, but I think we decided to have different types of boxes for different types of content: shoe boxes, hat boxes, etc.
Where it gets a bit tricky is when we overload operators, such as using the plus block for arithmetic sums and string concatenation. We discussed using seperate blocks for that.
We'll ptob. break some backward vcompatibility with some of these decisions. C'est la vie.
This gets into graphics territory a bit, but I think it would be nice if arguments/children of a block could go inside their parent instead of attaching on the right like a node (where appropriate). This can make code more readable: for example, the division block would read [[1]/[4]], on one line. Plus, two-arg-in--one-arg-out left-blocks can cause segments of code to overlap if you don't use grey filler blocks.
I suppose the reason that this could affect how blocks are represented internally is the in-between labels. The arguments would still be functionally represented the same way, but there would need to be block labels that go between arguments. This representation of arguments would probably be best fit for simple operations like boolean logic, arithmetic, and concatenation. Using this style for other blocks like notes would sacrifice their argument labels.
Sure, making blocks utilise the horizontal screen space in a more meaningful manner is on the list, perhaps we could have an entry on the backend model which signifies if a block takes in its arguments horizontally or vertically but this would mostly be handled by the view. Not sure if we should represent the filler blocks in our block stacks model as they are not a part of the execution, maybe the view would add them automatically if required. Thanks
Btw, did you think of some generalised jargon for 'flow', 'clamp', 'turtle', etc.
prototype built at sugarlabs/musicblocks-v4-builder-framework.
Architecture
Models for Blocks
Model for one block
Backend Models - Specifies the features of a block type like the type of the block, how many arguments does the block take, what other blocks can a block connect to, help string for a block etc, this analogous the json file used in blockly to specify block features. Contents of this model do not change ordinarily during execution.
Client Side Model - Specifies the current state of a single instance of a block type, contains information specific to a single block instance which could change frequently like the current position of a block, block collapsed or expanded, block clamp hight, any warnings associated with the current block configuration etc, changes in this Model would cause the block to re-render.
Model for Stacks of Blocks
An array of isolated block stack entities such as top level blocks like start, action, define temperament, widget blocks etc or just random group of blocks.