viewport = $viewport; } public function getViewport(): Viewport { return $this->viewport; } public function getContentViewport(): Viewport { return $this->contentViewport; } public function setContentViewport(Viewport $viewport): void { $this->contentViewport = $viewport; } /** * Apply offset to viewport and all child viewports recursively */ public function applyScrollOffset(int $offsetX, int $offsetY): void { // Offset this component's viewports $this->viewport->x = (int) ($this->viewport->x - $offsetX); $this->viewport->y = (int) ($this->viewport->y - $offsetY); $this->contentViewport->x = (int) ($this->contentViewport->x - $offsetX); $this->contentViewport->y = (int) ($this->contentViewport->y - $offsetY); // Recursively apply to all children foreach ($this->children as $child) { $child->applyScrollOffset($offsetX, $offsetY); } } public function setWindow($window): void { $this->window = $window; } public function setPixelRatio($pixelRatio): void { $this->pixelRatio = $pixelRatio; } public function update(): void { foreach ($this->children as $child) { $child->update(); } } public function layout(null|TextRenderer $textRenderer = null): void { $this->computedStyles = StyleParser::parse($this->style)->getValidStyles( MediaQueryEnum::normal, StateEnum::normal, ); if (isset($this->computedStyles[Margin::class]) && ($m = $this->computedStyles[Margin::class])) { $this->viewport->x = (int) ($this->viewport->x + $m->left); $this->viewport->width = max(0, ($this->viewport->width - $m->right) - $m->left); $this->viewport->y = (int) ($this->viewport->y + $m->top); $this->viewport->height = max(0, ($this->viewport->height - $m->bottom) - $m->top); } $this->contentViewport = clone $this->viewport; if (isset($this->computedStyles[Padding::class]) && ($p = $this->computedStyles[Padding::class])) { $this->contentViewport->x = (int) ($this->contentViewport->x + $p->left); $this->contentViewport->width = max(0, ($this->contentViewport->width - $p->right) - $p->left); $this->contentViewport->y = (int) ($this->contentViewport->y + $p->top); $this->contentViewport->height = max(0, ($this->contentViewport->height - $p->bottom) - $p->top); } } public function render(null|TextRenderer $textRenderer = null): void { if (!$this->visible) { return; } if ( isset($this->computedStyles[\PHPNative\Tailwind\Style\Background::class]) && ($bg = $this->computedStyles[\PHPNative\Tailwind\Style\Background::class]) ) { rsgl_setColor($this->window, $bg->color->red, $bg->color->green, $bg->color->blue, $bg->color->alpha); if ( isset($this->computedStyles[\PHPNative\Tailwind\Style\Border::class]) && ($border = $this->computedStyles[\PHPNative\Tailwind\Style\Border::class]) ) { rsgl_drawRoundRectExF( $this->window, $this->viewport->x, $this->viewport->y, $this->viewport->width, $this->viewport->height, $border->roundTopLeft ?? 0, $border->roundTopLeft ?? 0, $border->roundTopRight ?? 0, $border->roundTopRight ?? 0, $border->roundBottomLeft ?? 0, $border->roundBottomLeft ?? 0, $border->roundBottomRight ?? 0, $border->roundBottomRight ?? 0, ); } else { rsgl_drawRectF( $this->window, $this->viewport->x, $this->viewport->y, $this->viewport->width, $this->viewport->height, ); } } } public function renderContent(null|TextRenderer $textRenderer = null): void { if (!$this->visible) { return; } // Render children foreach ($this->children as $child) { $child->setWindow($this->window); $child->render($textRenderer); $child->renderContent($textRenderer); } } public function addComponent(Component $component): void { $this->children[] = $component; } /** * Handle mouse click event * @return bool True if event was handled */ public function handleMouseClick(float $mouseX, float $mouseY, int $button): bool { // Default implementation: propagate to children foreach ($this->children as $child) { if ($child->handleMouseClick($mouseX, $mouseY, $button)) { return true; } } return false; } /** * Handle mouse move event */ public function handleMouseMove(float $mouseX, float $mouseY): void { // Default implementation: propagate to children foreach ($this->children as $child) { $child->handleMouseMove($mouseX, $mouseY); } } /** * Handle mouse button release event */ public function handleMouseRelease(float $mouseX, float $mouseY, int $button): void { // Default implementation: propagate to children foreach ($this->children as $child) { $child->handleMouseRelease($mouseX, $mouseY, $button); } } /** * Handle mouse wheel event * @return bool True if event was handled */ public function handleMouseWheel(float $mouseX, float $mouseY, float $deltaY): bool { // Default implementation: propagate to children foreach ($this->children as $child) { if ($child->handleMouseWheel($mouseX, $mouseY, $deltaY)) { return true; } } return false; } }