Skip to content

Commit 7f65890

Browse files
authored
Merge pull request #180 from scratchcpp/top_level_reporter_blocks
Add API for top level reporter blocks
2 parents b0ee231 + 20d5c55 commit 7f65890

File tree

7 files changed

+120
-2
lines changed

7 files changed

+120
-2
lines changed

include/scratchcpp/block.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class IEngine;
1212
class Target;
1313
class Input;
1414
class Field;
15+
class InputValue;
1516
class BlockPrivate;
1617

1718
/*! \brief The Block class represents a Scratch block. */
@@ -68,6 +69,11 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity
6869

6970
BlockPrototype *mutationPrototype();
7071

72+
bool isTopLevelReporter() const;
73+
void setIsTopLevelReporter(bool isTopLevelReporter);
74+
75+
InputValue *topLevelReporterInfo();
76+
7177
private:
7278
spimpl::unique_impl_ptr<BlockPrivate> impl;
7379
};

src/internal/scratch3reader.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,22 @@ bool Scratch3Reader::load()
7979
auto blocks = jsonTarget["blocks"];
8080
for (json::iterator it = blocks.begin(); it != blocks.end(); ++it) {
8181
auto blockInfo = it.value();
82+
8283
if (blockInfo.is_array()) {
83-
// TODO: Find out what these "array" blocks that look like input values are for
84-
// Let's ignore them for now...
84+
// This is a top level reporter block for a variable/list
85+
READER_STEP(step, "target -> block -> top level reporter info");
86+
auto block = std::make_shared<Block>(it.key(), "");
87+
block->setIsTopLevelReporter(true);
88+
InputValue *reporterInfo = block->topLevelReporterInfo();
89+
90+
reporterInfo->setValue(jsonToValue(blockInfo[1]));
91+
reporterInfo->setValueId(jsonToValue(blockInfo[2]).toString());
92+
reporterInfo->setType(static_cast<InputValue::Type>(blockInfo[0]));
93+
94+
target->addBlock(block);
8595
continue;
8696
}
97+
8798
READER_STEP(step, "target -> block -> opcode");
8899
auto block = std::make_shared<Block>(it.key(), blockInfo["opcode"]);
89100
std::string nextId;

src/scratch/block.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,41 @@ BlockPrototype *Block::mutationPrototype()
5858
return &impl->mutationPrototype;
5959
}
6060

61+
/*! Returns true if this is a top level reporter block for a variable or a list. */
62+
bool Block::isTopLevelReporter() const
63+
{
64+
return impl->isTopLevelReporter;
65+
}
66+
67+
/*!
68+
* Sets whether this block is a top level reporter block for a variable or a list.
69+
* \note Setting this to true will allow the use topLevelReporterInfo().
70+
*/
71+
void Block::setIsTopLevelReporter(bool isTopLevelReporter)
72+
{
73+
impl->isTopLevelReporter = isTopLevelReporter;
74+
75+
if (isTopLevelReporter && !impl->topLevelReporterInfo)
76+
impl->topLevelReporterInfo = std::make_unique<InputValue>(InputValue::Type::Variable);
77+
else if (impl->topLevelReporterInfo) {
78+
impl->topLevelReporterInfo.reset();
79+
impl->topLevelReporterInfo = nullptr;
80+
}
81+
}
82+
83+
/*!
84+
* Returns the information about this top level reporter block (if this is a top level reporter block).
85+
* \note This function will return nullptr if this isn't a top level reporter block. Use setIsTopLevelReporter(true)
86+
* before using this function.
87+
*/
88+
InputValue *Block::topLevelReporterInfo()
89+
{
90+
if (impl->topLevelReporterInfo)
91+
return impl->topLevelReporterInfo.get();
92+
else
93+
return nullptr;
94+
}
95+
6196
/*! Returns the next block. */
6297
std::shared_ptr<Block> Block::next() const
6398
{

src/scratch/block_p.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#pragma once
44

55
#include <scratchcpp/blockprototype.h>
6+
#include <scratchcpp/inputvalue.h>
67

78
namespace libscratchcpp
89
{
@@ -33,6 +34,8 @@ struct BlockPrivate
3334
Target *target = nullptr;
3435
BlockPrototype mutationPrototype;
3536
bool mutationHasNext = true;
37+
bool isTopLevelReporter = false;
38+
std::unique_ptr<InputValue> topLevelReporterInfo = nullptr;
3639
};
3740

3841
} // namespace libscratchcpp

test/load_project/load_project_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <scratchcpp/costume.h>
1111
#include <scratchcpp/sound.h>
1212
#include <scratchcpp/sprite.h>
13+
#include <scratchcpp/inputvalue.h>
1314

1415
#include "../common.h"
1516

@@ -124,17 +125,20 @@ TEST(LoadProjectTest, LoadTestProject)
124125
// Sprite1: blocks
125126
ASSERT_EQ(sprite1->greenFlagBlocks().size(), 1);
126127
ASSERT_TRUE(sprite1->greenFlagBlocks()[0]);
128+
ASSERT_FALSE(sprite1->greenFlagBlocks()[0]->isTopLevelReporter());
127129
ASSERT_EQ(sprite1->greenFlagBlocks()[0]->opcode(), "event_whenflagclicked");
128130
auto block = sprite1->greenFlagBlocks()[0]->next();
129131
ASSERT_TRUE(block);
130132
ASSERT_EQ(block->parent(), sprite1->greenFlagBlocks()[0]);
131133
ASSERT_EQ(block->opcode(), "control_forever");
134+
ASSERT_FALSE(block->isTopLevelReporter());
132135
ASSERT_INPUT(block, "SUBSTACK");
133136
block = GET_INPUT(block, "SUBSTACK")->valueBlock();
134137
ASSERT_TRUE(block);
135138

136139
ASSERT_EQ(block->opcode(), "motion_goto");
137140
ASSERT_INPUT(block, "TO");
141+
ASSERT_FALSE(block->isTopLevelReporter());
138142
auto inputBlock = GET_INPUT(block, "TO")->valueBlock();
139143
ASSERT_TRUE(inputBlock);
140144
ASSERT_EQ(inputBlock->opcode(), "motion_goto_menu");
@@ -155,6 +159,7 @@ TEST(LoadProjectTest, LoadTestProject)
155159
inputBlock = GET_INPUT(block, "VALUE")->valueBlock();
156160
ASSERT_TRUE(inputBlock);
157161
ASSERT_EQ(inputBlock->opcode(), "operator_random");
162+
ASSERT_FALSE(inputBlock->isTopLevelReporter());
158163
ASSERT_INPUT(inputBlock, "FROM");
159164
ASSERT_EQ(GET_INPUT(inputBlock, "FROM")->primaryValue()->value().toInt(), 1);
160165
ASSERT_INPUT(inputBlock, "TO");
@@ -250,6 +255,47 @@ TEST(LoadProjectTest, LoadTestProject)
250255
}
251256
}
252257

258+
TEST(LoadProjectTest, LoadTopLevelReporterProject)
259+
{
260+
int i = 0;
261+
for (auto version : scratchVersions) {
262+
Project p("top_level_reporter" + fileExtensions[i], version);
263+
264+
ASSERT_TRUE(p.load());
265+
266+
auto engine = p.engine();
267+
ASSERT_EQ(engine->targets().size(), 2);
268+
269+
// Sprite1
270+
ASSERT_NE(engine->findTarget("Sprite1"), -1);
271+
Sprite *sprite1 = dynamic_cast<Sprite *>(engine->targetAt(engine->findTarget("Sprite1")));
272+
ASSERT_EQ(sprite1->blocks().size(), 2);
273+
274+
// Sprite1: blocks
275+
auto block1 = sprite1->blockAt(0);
276+
ASSERT_TRUE(block1);
277+
ASSERT_TRUE(block1->isTopLevelReporter());
278+
InputValue *reporterInfo = block1->topLevelReporterInfo();
279+
ASSERT_TRUE(reporterInfo);
280+
ASSERT_EQ(reporterInfo->type(), InputValue::Type::Variable);
281+
ASSERT_EQ(reporterInfo->value(), "var");
282+
ASSERT_EQ(reporterInfo->valueId(), "b[Pq/qD6PJ+hpWtz;X`G");
283+
ASSERT_EQ(reporterInfo->valuePtr(), sprite1->variableAt(0));
284+
285+
auto block2 = sprite1->blockAt(1);
286+
ASSERT_TRUE(block2);
287+
ASSERT_TRUE(block2->isTopLevelReporter());
288+
reporterInfo = block2->topLevelReporterInfo();
289+
ASSERT_TRUE(reporterInfo);
290+
ASSERT_EQ(reporterInfo->type(), InputValue::Type::List);
291+
ASSERT_EQ(reporterInfo->value(), "list");
292+
ASSERT_EQ(reporterInfo->valueId(), "*BW*~d~DgcZee0q=v*T2");
293+
ASSERT_EQ(reporterInfo->valuePtr(), sprite1->listAt(0));
294+
295+
i++;
296+
}
297+
}
298+
253299
TEST(LoadProjectTest, ProjectTest)
254300
{
255301
int i = 0;

test/scratch_classes/block_test.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,20 @@ TEST_F(BlockTest, MutationPrototype)
241241
Block block("", "");
242242
ASSERT_TRUE(block.mutationPrototype());
243243
}
244+
245+
TEST_F(BlockTest, TopLevelReporter)
246+
{
247+
Block block("", "");
248+
ASSERT_FALSE(block.isTopLevelReporter());
249+
ASSERT_EQ(block.topLevelReporterInfo(), nullptr);
250+
251+
for (int i = 0; i < 2; i++) {
252+
block.setIsTopLevelReporter(true);
253+
ASSERT_TRUE(block.isTopLevelReporter());
254+
ASSERT_TRUE(block.topLevelReporterInfo());
255+
256+
block.setIsTopLevelReporter(false);
257+
ASSERT_FALSE(block.isTopLevelReporter());
258+
ASSERT_EQ(block.topLevelReporterInfo(), nullptr);
259+
}
260+
}

test/top_level_reporter.sb3

2.01 KB
Binary file not shown.

0 commit comments

Comments
 (0)