feat(pro): correct translated textbox positioning

- Create buildOriginalBounds(): origin(150, 99.543) size(1620×182.946)
- Create buildTranslationBounds(): origin(150, 303.166) size(1620×113.889)
- Modify buildCue() to use different bounds for translated vs non-translated
- Modify buildSlideElement() to accept optional bounds parameter
- Add test: translated slide has correct dual bounds
- Add test: non-translated slide has single full-size bounds
- All tests pass: 14 PHPUnit, 203 Laravel tests
This commit is contained in:
Thorsten Bus 2026-03-02 21:46:37 +01:00
parent 7de43f4aec
commit 2fefe72ef6
2 changed files with 121 additions and 5 deletions

View file

@ -161,9 +161,13 @@ final class ProFileGenerator
{ {
$elements = []; $elements = [];
if (isset($slideData['text'])) { if (isset($slideData['text'])) {
$hasTranslation = isset($slideData['translation']) && $slideData['translation'] !== null;
if ($hasTranslation) {
$elements[] = self::buildSlideElement('Orginal', (string) $slideData['text'], self::buildOriginalBounds());
$elements[] = self::buildSlideElement('Deutsch', (string) $slideData['translation'], self::buildTranslationBounds());
} else {
$elements[] = self::buildSlideElement('Orginal', (string) $slideData['text']); $elements[] = self::buildSlideElement('Orginal', (string) $slideData['text']);
if (isset($slideData['translation']) && $slideData['translation'] !== null) {
$elements[] = self::buildSlideElement('Deutsch', (string) $slideData['translation']);
} }
} }
@ -263,12 +267,12 @@ final class ProFileGenerator
return $action; return $action;
} }
private static function buildSlideElement(string $name, string $text): SlideElement private static function buildSlideElement(string $name, string $text, ?Rect $bounds = null): SlideElement
{ {
$graphicsElement = new GraphicsElement(); $graphicsElement = new GraphicsElement();
$graphicsElement->setUuid(self::newUuid()); $graphicsElement->setUuid(self::newUuid());
$graphicsElement->setName($name); $graphicsElement->setName($name);
$graphicsElement->setBounds(self::buildBounds()); $graphicsElement->setBounds($bounds ?? self::buildBounds());
$graphicsElement->setOpacity(1.0); $graphicsElement->setOpacity(1.0);
$graphicsElement->setPath(self::buildPath()); $graphicsElement->setPath(self::buildPath());
$graphicsElement->setFill(self::buildFill()); $graphicsElement->setFill(self::buildFill());
@ -306,6 +310,40 @@ final class ProFileGenerator
return $rect; return $rect;
} }
private static function buildOriginalBounds(): Rect
{
$origin = new Point();
$origin->setX(150);
$origin->setY(99.543);
$size = new Size();
$size->setWidth(1620);
$size->setHeight(182.946);
$rect = new Rect();
$rect->setOrigin($origin);
$rect->setSize($size);
return $rect;
}
private static function buildTranslationBounds(): Rect
{
$origin = new Point();
$origin->setX(150);
$origin->setY(303.166);
$size = new Size();
$size->setWidth(1620);
$size->setHeight(113.889);
$rect = new Rect();
$rect->setOrigin($origin);
$rect->setSize($size);
return $rect;
}
private static function buildPath(): Path private static function buildPath(): Path
{ {
$path = new Path(); $path = new Path();

View file

@ -541,4 +541,82 @@ class ProFileGeneratorTest extends TestCase
$this->assertNotNull($selectedArrangement); $this->assertNotNull($selectedArrangement);
$this->assertSame('custom', $selectedArrangement->getName()); $this->assertSame('custom', $selectedArrangement->getName());
} }
#[Test]
public function testTranslatedSlideHasCorrectDualBounds(): void
{
$song = ProFileGenerator::generate(
'TranslateTest',
[
[
'name' => 'V1',
'color' => [0, 0, 0, 1],
'slides' => [
['text' => 'Amazing Grace', 'translation' => 'Erstaunliche Gnade'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['V1']],
],
);
$filePath = $this->tmpDir . '/translate-test.pro';
ProFileWriter::write($song, $filePath);
$readSong = ProFileReader::read($filePath);
$slides = $readSong->getSlides();
$elements = $slides[0]->getAllElements();
$this->assertCount(2, $elements);
$this->assertSame('Orginal', $elements[0]->getName());
$this->assertSame('Deutsch', $elements[1]->getName());
$bounds0 = $elements[0]->getGraphicsElement()->getBounds();
$bounds1 = $elements[1]->getGraphicsElement()->getBounds();
// Check heights differ and match expected values
$this->assertEqualsWithDelta(182.946, $bounds0->getSize()->getHeight(), 0.01);
$this->assertEqualsWithDelta(113.889, $bounds1->getSize()->getHeight(), 0.01);
// Check Y positions
$this->assertEqualsWithDelta(99.543, $bounds0->getOrigin()->getY(), 0.01);
$this->assertEqualsWithDelta(303.166, $bounds1->getOrigin()->getY(), 0.01);
}
#[Test]
public function testNonTranslatedSlideHasSingleFullBounds(): void
{
$song = ProFileGenerator::generate(
'NoTranslateTest',
[
[
'name' => 'V1',
'color' => [0, 0, 0, 1],
'slides' => [
['text' => 'Amazing Grace'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['V1']],
],
);
$filePath = $this->tmpDir . '/no-translate-test.pro';
ProFileWriter::write($song, $filePath);
$readSong = ProFileReader::read($filePath);
$slides = $readSong->getSlides();
$elements = $slides[0]->getAllElements();
$this->assertCount(1, $elements);
$this->assertSame('Orginal', $elements[0]->getName());
$bounds = $elements[0]->getGraphicsElement()->getBounds();
// Check full-size bounds
$this->assertEqualsWithDelta(880, $bounds->getSize()->getHeight(), 0.01);
$this->assertEqualsWithDelta(1620, $bounds->getSize()->getWidth(), 0.01);
$this->assertEqualsWithDelta(100, $bounds->getOrigin()->getY(), 0.01);
$this->assertEqualsWithDelta(150, $bounds->getOrigin()->getX(), 0.01);
}
} }