|
1 | 1 | \page extensions Extensions
|
2 | 2 |
|
3 |
| -An extension is a group of block sections (see [Block sections](blockSections.html)). |
| 3 | +An extension is a group of Scratch blocks, for example motion blocks. |
4 | 4 |
|
5 | 5 | ## Creating an extension
|
6 | 6 | To create a custom extension, subclass \link libscratchcpp::IExtension IExtension \endlink and override
|
7 | 7 | \link libscratchcpp::IExtension::name() name() \endlink and \link libscratchcpp::IExtension::description() description() \endlink
|
8 |
| -functions to return the name and the description of the extension. |
9 |
| - |
10 |
| -There's also an \link libscratchcpp::IExtension::includeByDefault() includeByDefault() \endlink function which returns `true` |
11 |
| -if the extension is intended to be hidden from the block palette and included in a Scratch project by default. |
12 |
| - |
13 |
| -The default implementation returns `false`. |
| 8 | +functions to return the name and the description of the extension. Then override \link libscratchcpp::IExtension::registerBlocks() registerBlocks() \endlink |
| 9 | +where you'll register the compile functions for blocks. |
14 | 10 |
|
15 | 11 | It's recommended to use the libscratchcpp namespace like this in your extension class:
|
16 | 12 | ```cpp
|
17 | 13 | using namespace libscratchcpp;
|
18 | 14 | ```
|
19 | 15 |
|
20 |
| -### Registering block sections |
21 |
| -Block sections can be registered by overriding the \link libscratchcpp::IExtension::registerSections() registerSections() \endlink function: |
| 16 | +### Adding blocks |
| 17 | +See the [Scratch Wiki](https://en.scratch-wiki.info/wiki/Scratch_File_Format#Blocks) for more information about blocks. |
| 18 | + |
| 19 | +Scratch projects are compiled by the \link libscratchcpp::Compiler Compiler \endlink class. |
| 20 | +To add a block, you have to let the compiler know how to compile it. |
| 21 | +Start by defining a **compile function**. |
| 22 | +For example, the compile function for a `hello world` block would look like this: |
| 23 | +```cpp |
| 24 | +class MyExtension : public IExtension { |
| 25 | + public: |
| 26 | + ... |
| 27 | + static void compileHelloWorld(Compiler *compiler); |
| 28 | + static unsigned int helloWorld(VirtualMachine *vm); |
| 29 | +}; |
| 30 | + |
| 31 | +void MySection::compileHelloWorld(Compiler *compiler) { |
| 32 | + compiler->addFunctionCall(&helloWorld); |
| 33 | +} |
| 34 | + |
| 35 | +unsigned int MySection::helloWorld(VirtualMachine *vm) { |
| 36 | + std::cout << "Hello, world!" << std::endl; |
| 37 | + return 0; |
| 38 | +} |
| 39 | +``` |
| 40 | +\note Make sure the functions are **static**. |
| 41 | +
|
| 42 | +Register the compile function using the \link libscratchcpp::IEngine::addCompileFunction() addCompileFunction() \endlink method in link libscratchcpp::IExtension::registerBlocks() registerBlocks() \endlink: |
| 43 | +```cpp |
| 44 | +MyExtension::registerBlocks(IEngine *engine) { |
| 45 | + engine->addCompileFunction(this, "myextension_helloworld", &MySection::compileHelloWorld); |
| 46 | +} |
| 47 | +``` |
| 48 | +Where `myextension_helloworld` is the opcode of the `hello world` block. |
| 49 | + |
| 50 | +### Adding inputs |
| 51 | +To add inputs, create an `Inputs` enumeration in your extension: |
| 52 | +```hpp |
| 53 | +class MyExtension : public IExtension { |
| 54 | + enum Inputs { |
| 55 | + TEXT |
| 56 | + }; |
| 57 | + ... |
| 58 | +}; |
| 59 | +``` |
| 60 | +Then add inputs in link libscratchcpp::IExtension::registerBlocks() registerBlocks() \endlink: |
| 61 | +```cpp |
| 62 | +MyExtension::registerBlocks(IEngine *engine) { |
| 63 | + ... |
| 64 | + engine->addInput(this, "TEXT", TEXT); |
| 65 | +} |
| 66 | +``` |
| 67 | +The compiler will assign the input name with the `TEXT` ID. In this case, the ID is 0 because it's the first member of the enumeration. |
| 68 | + |
| 69 | +To add the input to the compiled code, call the \link libscratchcpp::Compiler::addInput() addInput() \endlink function: |
| 70 | +```cpp |
| 71 | +void MyExtension::compileHelloWorld(Compiler *compiler) { |
| 72 | + compiler->addInput(TEXT); |
| 73 | + compiler->addFunctionCall(&helloWorld); |
| 74 | +} |
| 75 | +``` |
| 76 | +
|
| 77 | +The value of the input can be read during runtime using the \link libscratchcpp::VirtualMachine::getInput() getInput() \endlink function: |
| 78 | +```cpp |
| 79 | +unsigned int MyExtension::helloWorld(VirtualMachine *vm) { |
| 80 | + std::cout << "Hello, " << vm->getInput(0, 1)->toString() << "!" << std::endl; |
| 81 | + return 1; |
| 82 | +} |
| 83 | +``` |
| 84 | +\note The order of the inputs is the same as in the compile function. Do not use the `Inputs` enumeration in runtime functions. |
| 85 | + |
| 86 | +```cpp |
| 87 | +vm->getInput(0, 1) |
| 88 | +``` |
| 89 | +The first argument is the index of the input and the second argument is the amount of inputs. |
| 90 | +\note Make sure to return the amount of inputs in the `helloWorld` function. |
| 91 | +
|
| 92 | +### Adding fields |
| 93 | +**Fields** are drop-down menus into which one cannot drop a reporter. |
| 94 | +Fields have a predefined set of values. |
| 95 | +```cpp |
| 96 | +class MyExtension : public IExtension { |
| 97 | + ... |
| 98 | + enum Fields { |
| 99 | + ANIMAL |
| 100 | + }; |
| 101 | +
|
| 102 | + enum FieldValues { |
| 103 | + Cat, |
| 104 | + Dog |
| 105 | + }; |
| 106 | + ... |
| 107 | +}; |
| 108 | +
|
| 109 | +MyExtension::registerBlocks(IEngine *engine) { |
| 110 | + ... |
| 111 | + engine->addField(this, "ANIMAL", ANIMAL); |
| 112 | + engine->addFieldValue(this, "Cat", Cat); |
| 113 | + engine->addFieldValue(this, "Dog", Dog); |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +Because fields are handled at compile time, you can read them from the compile function: |
22 | 118 | ```cpp
|
23 |
| -void MyExtension::registerSections(IEngine *engine) { |
24 |
| - engine->registerSection(std::make_shared<MySection>()); |
| 119 | +void MyExtension::compileHelloWorld(Compiler *compiler) { |
| 120 | + int id = compiler->field(ANIMAL)->specialValueId(); |
| 121 | + |
| 122 | + switch(id) { |
| 123 | + case Cat: |
| 124 | + compiler->addFunctionCall(&helloCat); |
| 125 | + break; |
| 126 | + |
| 127 | + case Dog: |
| 128 | + compiler->addFunctionCall(&helloDog); |
| 129 | + break; |
| 130 | + |
| 131 | + default: |
| 132 | + break; |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +unsigned int MySection::helloCat(VirtualMachine *vm) { |
| 137 | + std::cout << "Hello, cat!" << std::endl; |
| 138 | + return 0; |
| 139 | +} |
| 140 | + |
| 141 | +unsigned int MySection::helloDog(VirtualMachine *vm) { |
| 142 | + std::cout << "Hello, dog!" << std::endl; |
| 143 | + return 0; |
25 | 144 | }
|
26 | 145 | ```
|
27 |
| -See the [Block sections](blockSections.html) page for instructions on how to create a block section. |
| 146 | +\note Don't confuse \link libscratchcpp::Field::specialValueId() specialValueId() \endlink with \link libscratchcpp::Field::valueId() valueId() \endlink |
| 147 | +because \link libscratchcpp::Field::valueId() valueId() \endlink stores the ID of the block, variable, list or broadcast selected in the dropdown list. |
| 148 | +
|
| 149 | +To get a pointer to the block, variable, list or broadcast selected in the dropdown list, use \link libscratchcpp::Field::valuePtr() valuePtr() \endlink. |
28 | 150 |
|
29 | 151 | ### Registering the extension
|
30 | 152 | Register the extension **before** loading a project, using the \link libscratchcpp::ScratchConfiguration ScratchConfiguration \endlink class:
|
|
0 commit comments