diff --git a/include/scratchcpp/block.h b/include/scratchcpp/block.h index 02b7ddeb..fe6cf382 100644 --- a/include/scratchcpp/block.h +++ b/include/scratchcpp/block.h @@ -56,6 +56,12 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity bool topLevel() const; + int x() const; + void setX(int x); + + int y() const; + void setY(int y); + std::shared_ptr comment() const; const std::string &commentId() const; void setComment(std::shared_ptr comment); diff --git a/src/internal/scratch3reader.cpp b/src/internal/scratch3reader.cpp index 14f6065b..8f2ec4c0 100644 --- a/src/internal/scratch3reader.cpp +++ b/src/internal/scratch3reader.cpp @@ -92,6 +92,9 @@ bool Scratch3Reader::load() reporterInfo->setValueId(jsonToValue(blockInfo[2]).toString()); reporterInfo->setType(static_cast(blockInfo[0])); + block->setX(blockInfo[3]); + block->setY(blockInfo[4]); + target->addBlock(block); continue; } @@ -108,6 +111,17 @@ bool Scratch3Reader::load() if (!blockInfo["parent"].is_null()) parentId = blockInfo["parent"]; block->setParentId(parentId); + READER_STEP(step, "target -> block -> parent"); + if (!blockInfo["parent"].is_null()) + parentId = blockInfo["parent"]; + block->setParentId(parentId); + + if (block->topLevel()) { + READER_STEP(step, "target -> block -> x"); + block->setX(blockInfo["x"]); + READER_STEP(step, "target -> block -> y"); + block->setY(blockInfo["y"]); + } // inputs READER_STEP(step, "target -> block -> inputs"); diff --git a/src/scratch/block.cpp b/src/scratch/block.cpp index 6ce51593..0350ccd4 100644 --- a/src/scratch/block.cpp +++ b/src/scratch/block.cpp @@ -313,6 +313,36 @@ bool Block::topLevel() const return (impl->parentId == "" && !impl->parent); } +/*! Returns the X-coordinate of the block in the code area (only for top level blocks). */ +int Block::x() const +{ + return impl->x; +} + +/*! Sets the X-coordinate of the block in the code area (only for top level blocks). */ +void Block::setX(int x) +{ + if (!topLevel()) + std::cout << "warning: setting X-coordinate of a block which is not a top level block" << std::endl; + + impl->x = x; +} + +/*! Returns the Y-coordinate of the block in the code area (only for top level blocks). */ +int Block::y() const +{ + return impl->y; +} + +/*! Sets the Y-coordinate of the block in the code area (only for top level blocks). */ +void Block::setY(int y) +{ + if (!topLevel()) + std::cout << "warning: setting Y-coordinate of a block which is not a top level block" << std::endl; + + impl->y = y; +} + /*! Returns the comment which is attached to this block. */ std::shared_ptr Block::comment() const { diff --git a/src/scratch/block_p.h b/src/scratch/block_p.h index 215d3bbd..a1aecb7b 100644 --- a/src/scratch/block_p.h +++ b/src/scratch/block_p.h @@ -33,6 +33,8 @@ struct BlockPrivate std::vector> fields; std::unordered_map fieldMap; bool shadow = false; + int x = 0; + int y = 0; std::string commentId; std::shared_ptr comment = nullptr; IEngine *engine = nullptr; diff --git a/test/load_project/load_project_test.cpp b/test/load_project/load_project_test.cpp index c7a505ff..1830b446 100644 --- a/test/load_project/load_project_test.cpp +++ b/test/load_project/load_project_test.cpp @@ -228,7 +228,7 @@ TEST(LoadProjectTest, LoadTestProject) ASSERT_EQ(sprite1->name(), "Sprite1"); ASSERT_EQ(sprite1->variables().size(), 1); ASSERT_EQ(sprite1->lists().size(), 1); - ASSERT_EQ(sprite1->blocks().size(), 18); + ASSERT_EQ(sprite1->blocks().size(), 19); ASSERT_EQ(sprite1->costumes().size(), 2); ASSERT_EQ(sprite1->comments().size(), 1); ASSERT_EQ(sprite1->costumeIndex(), 1); @@ -278,6 +278,8 @@ TEST(LoadProjectTest, LoadTestProject) ASSERT_TRUE(sprite1->greenFlagBlocks()[0]); ASSERT_FALSE(sprite1->greenFlagBlocks()[0]->isTopLevelReporter()); ASSERT_EQ(sprite1->greenFlagBlocks()[0]->opcode(), "event_whenflagclicked"); + ASSERT_EQ(sprite1->greenFlagBlocks()[0]->x(), 0); + ASSERT_EQ(sprite1->greenFlagBlocks()[0]->y(), 0); auto block = sprite1->greenFlagBlocks()[0]->next(); ASSERT_TRUE(block); ASSERT_EQ(block->parent(), sprite1->greenFlagBlocks()[0]); @@ -343,6 +345,8 @@ TEST(LoadProjectTest, LoadTestProject) } } ASSERT_TRUE(defineBlock); + ASSERT_EQ(defineBlock->x(), 0); + ASSERT_EQ(defineBlock->y(), 384); ASSERT_INPUT(defineBlock, "custom_block"); auto blockPrototype = GET_INPUT(defineBlock, "custom_block")->valueBlock(); ASSERT_TRUE(blockPrototype); @@ -372,6 +376,17 @@ TEST(LoadProjectTest, LoadTestProject) ASSERT_TRUE(argBlock); ASSERT_EQ(argBlock->opcode(), "argument_reporter_string_number"); + std::shared_ptr keyPressedBlock = nullptr; + for (auto b : blocks) { + if (b->opcode() == "event_whenkeypressed") { + keyPressedBlock = b; + break; + } + } + ASSERT_TRUE(keyPressedBlock); + ASSERT_EQ(keyPressedBlock->x(), 488); + ASSERT_EQ(keyPressedBlock->y(), 152); + // Balloon1 ASSERT_NE(engine->findTarget("Balloon1"), -1); Sprite *sprite2 = dynamic_cast(engine->targetAt(engine->findTarget("Balloon1"))); @@ -651,6 +666,8 @@ TEST(LoadProjectTest, LoadTopLevelReporterProject) auto block1 = sprite1->blockAt(0); ASSERT_TRUE(block1); ASSERT_TRUE(block1->isTopLevelReporter()); + ASSERT_EQ(block1->x(), 335); + ASSERT_EQ(block1->y(), 335); InputValue *reporterInfo = block1->topLevelReporterInfo(); ASSERT_TRUE(reporterInfo); ASSERT_EQ(reporterInfo->type(), InputValue::Type::Variable); @@ -661,6 +678,8 @@ TEST(LoadProjectTest, LoadTopLevelReporterProject) auto block2 = sprite1->blockAt(1); ASSERT_TRUE(block2); ASSERT_TRUE(block2->isTopLevelReporter()); + ASSERT_EQ(block2->x(), 313); + ASSERT_EQ(block2->y(), 435); reporterInfo = block2->topLevelReporterInfo(); ASSERT_TRUE(reporterInfo); ASSERT_EQ(reporterInfo->type(), InputValue::Type::List); diff --git a/test/load_test.sb3 b/test/load_test.sb3 index d1553e8e..eeaa571f 100644 Binary files a/test/load_test.sb3 and b/test/load_test.sb3 differ diff --git a/test/scratch_classes/block_test.cpp b/test/scratch_classes/block_test.cpp index 905f5c64..a0b4545c 100644 --- a/test/scratch_classes/block_test.cpp +++ b/test/scratch_classes/block_test.cpp @@ -194,6 +194,24 @@ TEST_F(BlockTest, TopLevel) ASSERT_TRUE(block.topLevel()); } +TEST_F(BlockTest, X) +{ + Block block("", ""); + ASSERT_EQ(block.x(), 0); + + block.setX(12); + ASSERT_EQ(block.x(), 12); +} + +TEST_F(BlockTest, Y) +{ + Block block("", ""); + ASSERT_EQ(block.y(), 0); + + block.setY(8); + ASSERT_EQ(block.y(), 8); +} + TEST_F(BlockTest, Comment) { Block block("", "");