This commit is contained in:
Thomas Peterson 2024-09-30 08:49:14 +02:00
parent 7d4139234f
commit 401287a2a1
51 changed files with 972 additions and 127 deletions

BIN
assets/symbol.ttf Normal file

Binary file not shown.

View File

@ -11,7 +11,9 @@
"require": {
"ext-parallel": "*",
"ext-sdl": "*",
"php": "^8.3"
"php": "^8.3",
"symfony/serializer": "^7",
"zumba/json-serializer": "^3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.21",
@ -28,6 +30,7 @@
"phpnative/event": "self.version",
"phpnative/framework": "self.version",
"phpnative/renderer": "self.version",
"phpnative/storage": "self.version",
"phpnative/support": "self.version",
"phpnative/tailwind": "self.version",
"phpnative/ui": "self.version"
@ -39,6 +42,7 @@
"PHPNative\\Event\\": "src/PHPNative/Event/src",
"PHPNative\\Framework\\": "src/PHPNative/Framework/src",
"PHPNative\\Renderer\\": "src/PHPNative/Renderer/src",
"PHPNative\\Storage\\": "src/PHPNative/Storage/src",
"PHPNative\\Support\\": "src/PHPNative/Support/src",
"PHPNative\\Tailwind\\": "src/PHPNative/Tailwind/src",
"PHPNative\\UI\\": "src/PHPNative/UI/src"
@ -51,6 +55,7 @@
"PHPNative\\Event\\Tests\\": "src/PHPNative/Event/tests",
"PHPNative\\Framework\\Tests\\": "src/PHPNative/Framework/tests",
"PHPNative\\Renderer\\Tests\\": "src/PHPNative/Renderer/tests",
"PHPNative\\Storage\\Tests\\": "src/PHPNative/Storage/tests",
"PHPNative\\Support\\Tests\\": "src/PHPNative/Support/tests",
"PHPNative\\Tailwind\\Tests\\": "src/PHPNative/Tailwind/tests",
"PHPNative\\UI\\Tests\\": "src/PHPNative/UI/tests"

View File

@ -120,4 +120,9 @@ abstract class Collection implements IteratorAggregate
$this->elements = $temp->items();
}
public function clear(): void
{
$this->elements = [];
}
}

View File

@ -12,11 +12,17 @@ class Driver
public function pollEvent(): Event
{
\SDL_PollEvent($this->event);
if($this->event->type == \SDL_EVENT_KEY_UP) {
var_dump($this->event->key->key);
}
return match($this->event->type) {
\SDL_EVENT_QUIT => new \PHPNative\Event\SystemEvent(EventType::QUIT),
\SDL_EVENT_MOUSE_BUTTON_DOWN => new MouseDown(EventType::MOUSEBUTTON_DOWN, $this->event->button->x, $this->event->button->y ),
\SDL_EVENT_MOUSE_BUTTON_UP => new MouseUp(EventType::MOUSEBUTTON_UP, $this->event->button->x, $this->event->button->y ),
\SDL_EVENT_MOUSE_MOTION => new MouseMove(EventType::MOUSEMOVE, $this->event->motion->x, $this->event->motion->y ),
\SDL_EVENT_WINDOW_CLOSE_REQUESTED => new \PHPNative\Event\SystemEvent(EventType::WINDOW_CLOSE, $this->event->window->windowID),
\SDL_EVENT_KEY_UP => new \PHPNative\Event\KeyUp(EventType::KEYUP, $this->event->window->windowID, Key::tryFrom($this->event->key->key)),
\SDL_EVENT_TEXT_INPUT => new \PHPNative\Event\TextInput(EventType::TEXTINPUT, $this->event->window->windowID, mb_convert_encoding($this->event->text->text, 'ISO-8859-1', 'UTF-8')),
\SDL_EVENT_MOUSE_BUTTON_DOWN => new MouseDown(EventType::MOUSEBUTTON_DOWN, $this->event->window->windowID, $this->event->button->x, $this->event->button->y ),
\SDL_EVENT_MOUSE_BUTTON_UP => new MouseUp(EventType::MOUSEBUTTON_UP, $this->event->window->windowID, $this->event->button->x, $this->event->button->y ),
\SDL_EVENT_MOUSE_MOTION => new MouseMove(EventType::MOUSEMOVE, $this->event->window->windowID, $this->event->motion->x, $this->event->motion->y ),
default => new \PHPNative\Event\SystemEvent(EventType::NOOP)
};
}

View File

@ -6,7 +6,6 @@ enum EventType: int
{
case NOOP = 0;
case QUIT = 1;
case CLOSE_WINDOW = 2;
case WINDOW_FOCUS_LOST = 1000;
case WINDOW_FOCUS_GAINED = 1001;
case WINDOW_RESIZED = 1002;

View File

@ -0,0 +1,15 @@
<?php
namespace PHPNative\Event;
enum Key: int
{
case BACKSPACE = 8;
case SDLK_RIGHT = 1073741903;
case SDLK_LEFT = 1073741904;
case SDLK_UP = 1073741906;
case SDLK_DOWN = 1073741905;
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace PHPNative\Event;
class KeyUp implements Event
{
public function __construct(public EventType $type = EventType::MOUSEBUTTON_UP, public int $windowId = 0, public ?Key $key = null)
{
}
public function getType(): EventType
{
return $this->type;
}
}

View File

@ -5,7 +5,7 @@ namespace PHPNative\Event;
class MouseDown implements Event
{
public function __construct(public EventType $type = EventType::MOUSEBUTTON_DOWN, public int $x = 0, public int $y = 0)
public function __construct(public EventType $type = EventType::MOUSEBUTTON_DOWN, public int $windowId = 0, public int $x = 0, public int $y = 0)
{
}

View File

@ -5,7 +5,7 @@ namespace PHPNative\Event;
class MouseMove implements Event
{
public function __construct(public EventType $type = EventType::MOUSEMOVE, public int $x = 0, public int $y = 0)
public function __construct(public EventType $type = EventType::MOUSEMOVE, public int $windowId = 0, public int $x = 0, public int $y = 0)
{
}

View File

@ -5,7 +5,7 @@ namespace PHPNative\Event;
class MouseUp implements Event
{
public function __construct(public EventType $type = EventType::MOUSEBUTTON_UP, public int $x = 0, public int $y = 0)
public function __construct(public EventType $type = EventType::MOUSEBUTTON_UP, public int $windowId = 0, public int $x = 0, public int $y = 0)
{
}

View File

@ -5,7 +5,7 @@ namespace PHPNative\Event;
class SystemEvent implements Event
{
public function __construct(public EventType $type = EventType::NOOP)
public function __construct(public EventType $type = EventType::NOOP, public int $windowId = 0)
{
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace PHPNative\Event;
class TextInput implements Event
{
public function __construct(public EventType $type = EventType::TEXTINPUT, public int $windowId = 0, public string $text = "")
{
}
public function getType(): EventType
{
return $this->type;
}
}

View File

@ -5,6 +5,6 @@ namespace PHPNative\Framework\Application;
interface Application
{
public function run(string|null $start): void;
public function run(): void;
}

View File

@ -0,0 +1,7 @@
<?php
declare(strict_types=1);
namespace PHPNative\Framework\Application;
class Config
{
}

View File

@ -18,25 +18,29 @@ final readonly class Gui implements Application
}
public static function boot(
string $name = 'PHPNative',
?string $app = null,
?string $root = null,
array $discoveryLocations = [],
): self {
$container = PHPNative::boot($root);
$container = PHPNative::boot($root);
$container->register(App::class, function () use ($app, $container) {
return $container->get($app);
});
$application = $container->get(Gui::class);
return $application;
}
public function run(string|null $start): void
public function run(): void
{
try {
$application = $this->container->get(App::class);
$lifeCycle = $this->container->get(Lifecycle::class);
try {
$lifeCycle->show($this->container->get($start));
$lifeCycle->show($this->container->get($application->getStartWindow()));
$lifeCycle->run();
} catch (ArgumentCountError $e) {
var_dump($e->getMessage());

View File

@ -6,9 +6,9 @@ namespace PHPNative\Framework\Application;
use PHPNative\Container\Container;
use PHPNative\Container\GenericContainer;
use PHPNative\Framework\Discovery\DiscoveryLocationBootstrap;
use PHPNative\Framework\Discovery\LoadDiscoveryClasses;
use PHPNative\Framework\Discovery\LoadDiscoveryLocations;
use Zumba\JsonSerializer\JsonSerializer;
final class Kernel
{
@ -34,6 +34,9 @@ final class Kernel
private function registerKernel(): self
{
$this->container->singleton(self::class, $this);
$this->container->register(JsonSerializer::class, function () {
return new JsonSerializer();
});
return $this;
}

View File

@ -2,6 +2,7 @@
namespace PHPNative\Framework\Lifecycle;
use Closure;
use PHPNative\Event\Event;
use PHPNative\Framework\Application\Window;
use PHPNative\Renderer\Thread;
@ -9,7 +10,7 @@ use PHPNative\Renderer\Thread;
class Context
{
public function __construct(private Thread $thread)
public function __construct(public Thread $thread, public ?Closure $onClose = null)
{
}
@ -26,7 +27,9 @@ class Context
public function event(Event $event): void
{
$this->thread->addEvent($event);
if($event->windowId == $this->thread->windowId) {
$this->thread->addEvent($event);
}
}
public function render(float $delta): void
@ -36,7 +39,10 @@ class Context
public function unload(): void
{
//TODO: unload
if($this->onClose) {
($this->onClose)();
}
$this->thread->close();
}
}

View File

@ -12,4 +12,15 @@ class ContextCollection extends TypedCollection
{
return Context::class;
}
public function removeWindowFrom(string $windowId): void
{
$temp = $this->filter(function ($value, $key) use($windowId){
if($value->thread->windowId == $windowId) {
$value->unload();
}
return $value->thread->windowId != $windowId;
});
$this->setElements($temp->items());
}
}

View File

@ -3,6 +3,7 @@
namespace PHPNative\Framework\Lifecycle;
use PHPNative\Container\Container;
use PHPNative\Container\Singleton;
use PHPNative\Event\Event;
use PHPNative\Event\EventType;
use PHPNative\Framework\Application\Window;
@ -10,6 +11,7 @@ use PHPNative\Framework\Loop\OrderedEventLoop;
use PHPNative\Framework\Loop\WorkerInterface;
use PHPNative\Renderer\Thread;
#[Singleton]
class Lifecycle implements WorkerInterface
{
public function __construct(
@ -20,14 +22,15 @@ class Lifecycle implements WorkerInterface
$this->loop->use($this);
}
public function show(Window $window, array $arguments = []): void
public function show(Window $window, array $arguments = [], ?callable $onClose = null): void
{
$context = $this->container->get(
Context::class,
thread: $this->container->get(Thread::class)
null
);
$context->onClose = $onClose;
$context->show($window);
$this->contextCollection->add($context);
@ -45,7 +48,9 @@ class Lifecycle implements WorkerInterface
public function onRender(float $delta): void
{
$this->contextCollection->map(fn(Context $context) => $context->render($delta));
$this->contextCollection->map(
fn(Context $context) => $context->render($delta)
);
}
public function onEvent( $event): void
@ -60,6 +65,9 @@ class Lifecycle implements WorkerInterface
case EventType::WINDOW_FOCUS_LOST:
$this->loop->pause();
break;
case EventType::WINDOW_CLOSE:
$this->closeWindow($event->windowId);
break;
case EventType::WINDOW_FOCUS_GAINED:
$this->loop->resume();
break;
@ -67,6 +75,7 @@ class Lifecycle implements WorkerInterface
$this->contextCollection->map(fn(Context $context) => $context->unload());
$this->contextCollection = new ContextCollection();
$this->loop->stop();
\SDL_Quit();
break;
}
}
@ -84,4 +93,13 @@ class Lifecycle implements WorkerInterface
$this->context->resume();
}
}
private function closeWindow($windowId)
{
if($this->contextCollection->count() == 1) {
return;
}
$this->contextCollection->removeWindowFrom($windowId);
}
}

View File

@ -15,6 +15,8 @@ final class PHPNative
): Container {
$root ??= getcwd();
\SDL_Init(\SDL_INIT_VIDEO);
\SDL_TTF_Init();
// Kernel
return (new Kernel(
root: $root,

View File

@ -0,0 +1,8 @@
<?php
namespace PHPNative\Renderer\Cache;
class Image
{
}

View File

@ -13,10 +13,13 @@ use PHPNative\Tailwind\StyleParser;
class Thread
{
private ?\SDL_Window $windowId = null;
public ?\SDL_Window $windowPtr = null;
public ?int $windowId = null;
private $rendererPtr = null;
private Window $window;
private bool $shouldRenderd = true;
public Window $window;
private StackCollection $renderStack;
@ -32,28 +35,32 @@ class Thread
{
$this->window = $window;
\SDL_Init(\SDL_INIT_VIDEO);
\SDL_TTF_Init();
$this->windowId = \SDL_CreateWindow($this->window->getTitle(), 800, 600, \SDL_WINDOW_HIGH_PIXEL_DENSITY);
$this->rendererPtr = \SDL_CreateRenderer($this->windowId);
$this->windowPtr = \SDL_CreateWindow($this->window->getTitle(), 1000, 600, \SDL_WINDOW_HIGH_PIXEL_DENSITY);
$this->rendererPtr = \SDL_CreateRenderer($this->windowPtr);
$this->windowId = \SDL_GetWindowID($this->windowPtr);
}
public function close(): void
{
$this->shouldRenderd = false;
\SDL_DestroyRenderer($this->rendererPtr);
\SDL_DestroyWindow($this->windowId);
\SDL_Quit();
\SDL_DestroyWindow($this->windowPtr);
}
public function render(): void
{
if(!$this->shouldRenderd) {
return;
}
$windowWidth = 0;
$windowHeight = 0;
\SDL_GetWindowSize($this->windowId, $windowWidth, $windowHeight);
\SDL_GetWindowSize($this->windowPtr, $windowWidth, $windowHeight);
$viewPort = new Viewport(
windowId: $this->windowId,
windowPtr: $this->windowPtr,
renderPtr: $this->rendererPtr,
x:0, y: 0,
width: $windowWidth, height: $windowHeight, windowWidth: $windowWidth, windowHeight: $windowHeight,
@ -74,6 +81,7 @@ class Thread
if($item->clipAt) {
$item->renderAt->w = $item->clipAt->w;
}
\SDL_RenderTexture($this->rendererPtr, $item->texture, $item->clipAt?? null , $item->renderAt);
});

View File

@ -9,6 +9,7 @@ class Viewport
{
public function __construct(public $windowId,
public $windowPtr,
public $renderPtr,
public int $x = 0,
public int $y = 0,
@ -16,6 +17,8 @@ class Viewport
public $height = 0,
public $windowWidth = 0,
public $windowHeight = 0,
public $addX = 0,
public $addY = 0,
public MediaQueryEnum $windowMediaQuery = MediaQueryEnum::normal)
{
}

View File

@ -2,26 +2,37 @@
namespace PHPNative\Renderer\Visuals;
use PHPNative\Renderer\GFX;
use PHPNative\Renderer\Item;
use PHPNative\Renderer\Thread;
use PHPNative\Renderer\Viewport;
class Background
{
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport): void
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport, int $index = 0): void
{
if(isset($styles[\PHPNative\Tailwind\Style\Background::class]) && $bg = $styles[\PHPNative\Tailwind\Style\Background::class]) {
$texture = \SDL_CreateTexture($targetViewport->renderPtr, \SDL_PIXELFORMAT_RGBA8888, \SDL_TEXTUREACCESS_TARGET, $targetViewport->width, $targetViewport->height);
\SDL_SetRenderTarget($targetViewport->renderPtr, $texture);
\SDL_SetRenderDrawColor($targetViewport->renderPtr, 255, 255, 255, 255);
\SDL_SetRenderDrawColor($targetViewport->renderPtr, 0, 0, 0, 0);
\SDL_RenderClear($targetViewport->renderPtr);
$rect = new \SDL_FRect(0, 0, $targetViewport->width, $targetViewport->height);
\SDL_SetRenderDrawColor($targetViewport->renderPtr, $bg->color->red, $bg->color->green, $bg->color->blue, $bg->color->alpha);
\SDL_RenderFillRect($targetViewport->renderPtr, $rect);
$thread->addToRenderStack(new Item($widgetId, $texture, new \SDL_FRect($targetViewport->x, $targetViewport->y, $targetViewport->width, $targetViewport->height), 2));
if(isset($styles[\PHPNative\Tailwind\Style\Border::class]) && $border = $styles[\PHPNative\Tailwind\Style\Border::class]) {
if($border->roundTop > 0) {
GFX::roundedBoxRGBA($targetViewport->renderPtr, 0, 0,
$targetViewport->width, $targetViewport->height, $border->roundTop, $bg->color->red, $bg->color->green, $bg->color->blue, $bg->color->alpha);
}else{
GFX::boxRGBA($targetViewport->renderPtr, 0, 0,
$targetViewport->width, $targetViewport->height, $bg->color->red, $bg->color->green, $bg->color->blue, $bg->color->alpha);
}
}else{
GFX::boxRGBA($targetViewport->renderPtr, 0, 0,
$targetViewport->width, $targetViewport->height, $bg->color->red, $bg->color->green, $bg->color->blue, $bg->color->alpha);
}
$thread->addToRenderStack(new Item($widgetId, $texture, new \SDL_FRect($targetViewport->x, $targetViewport->y, $targetViewport->width, $targetViewport->height), $index));
}
}
}

View File

@ -10,7 +10,7 @@ use PHPNative\Renderer\Viewport;
class Border
{
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport): void
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport, int $index): void
{
if(isset($styles[\PHPNative\Tailwind\Style\Border::class]) && $b = $styles[\PHPNative\Tailwind\Style\Border::class]) {
$texture = \SDL_CreateTexture($targetViewport->renderPtr, \SDL_PIXELFORMAT_RGBA8888, \SDL_TEXTUREACCESS_TARGET, $targetViewport->width, $targetViewport->height);
@ -38,7 +38,7 @@ class Border
GFX::boxRGBA($targetViewport->renderPtr, $targetViewport->width - $b->right, 0,
$targetViewport->width, $targetViewport->height, $b->color->red, $b->color->green, $b->color->blue, $b->color->alpha);
}
$thread->addToRenderStack(new Item($widgetId, $texture, new \SDL_FRect($targetViewport->x, $targetViewport->y, $targetViewport->width, $targetViewport->height), 10));
$thread->addToRenderStack(new Item($widgetId, $texture, new \SDL_FRect($targetViewport->x, $targetViewport->y, $targetViewport->width, $targetViewport->height), $index));
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace PHPNative\Renderer\Visuals;
use PHPNative\Renderer\GFX;
use PHPNative\Renderer\Item;
use PHPNative\Renderer\Thread;
use PHPNative\Renderer\Viewport;
class Cursor
{
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport, int $index = 0): void
{
$texture = \SDL_CreateTexture($targetViewport->renderPtr, \SDL_PIXELFORMAT_RGBA8888, \SDL_TEXTUREACCESS_TARGET, 4, $targetViewport->height);
\SDL_SetRenderTarget($targetViewport->renderPtr, $texture);
\SDL_SetRenderDrawColor($targetViewport->renderPtr, 0, 0, 0, 255);
\SDL_RenderClear($targetViewport->renderPtr);
GFX::boxRGBA($targetViewport->renderPtr, 0, 0, 4, $targetViewport->height, 128,128,128,255);
$thread->addToRenderStack(new Item($widgetId, $texture, new \SDL_FRect($targetViewport->x, $targetViewport->y, 4, $targetViewport->height), $index));
}
}

View File

@ -7,10 +7,10 @@ use PHPNative\Renderer\Viewport;
class Visuals
{
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport): void
public static function render(string $widgetId, Thread $thread, array $styles, Viewport $targetViewport, int $index = 0): void
{
Background::render($widgetId, $thread, $styles, $targetViewport);
Border::render($widgetId, $thread, $styles, $targetViewport);
Background::render($widgetId, $thread, $styles, $targetViewport, $index);
Border::render($widgetId, $thread, $styles, $targetViewport, $index);
}
public static function changeViewport(string $widgetId, Thread $thread, array $styles, Viewport $viewport): void

View File

@ -2,29 +2,40 @@
namespace PHPNative\Renderer;
use PHPNative\UI\Widget\Icon;
use PHPNative\UI\Widget\Image;
use PHPNative\UI\Widget\TextEdit;
use PHPNative\UI\BaseView;
use PHPNative\UI\View;
use PHPNative\UI\Widget\Button;
use PHPNative\UI\Widget\Container;
use PHPNative\UI\Widget\Label;
use PHPNative\UI\Widget\Text;
class Widget
{
public static function render(Thread $thread, ViewPort $viewPort, View $view): Viewport {
public static function render(Thread $thread, ViewPort $viewPort, View $view, int $index = 1): Viewport {
if($view instanceof BaseView) {
return \PHPNative\Renderer\Widgets\BaseView::render($thread, $viewPort, $view);
return \PHPNative\Renderer\Widgets\BaseView::render($thread, $viewPort, $view, $index);
}
if($view instanceof Button) {
return \PHPNative\Renderer\Widgets\Button::render($thread, $viewPort, $view);
return \PHPNative\Renderer\Widgets\Container::render($thread, $viewPort, $view, $index);
}
if($view instanceof Label) {
return \PHPNative\Renderer\Widgets\Label::render($thread, $viewPort, $view);
if($view instanceof Text) {
return \PHPNative\Renderer\Widgets\Text::render($thread, $viewPort, $view, $index);
}
if($view instanceof TextEdit) {
return \PHPNative\Renderer\Widgets\TextEdit::render($thread, $viewPort, $view, $index);
}
if($view instanceof Container) {
return \PHPNative\Renderer\Widgets\Container::render($thread, $viewPort, $view);
return \PHPNative\Renderer\Widgets\Container::render($thread, $viewPort, $view, $index);
}
if($view instanceof Image) {
return \PHPNative\Renderer\Widgets\Image::render($thread, $viewPort, $view, $index);
}
if($view instanceof Icon) {
return \PHPNative\Renderer\Widgets\Icon::render($thread, $viewPort, $view, $index);
}
}
}

View File

@ -13,43 +13,7 @@ use PHPNative\Tailwind\Style\Padding;
use PHPNative\Tailwind\Style\StateEnum;
use PHPNative\Tailwind\StyleParser;
class BaseView
class BaseView extends Container
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\BaseView $view): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, StateEnum::normal);
if(isset($styles[Margin::class]) && $m = $styles[Margin::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height -= ($m->bottom + $m->top);
}
if(isset($styles[Background::class]) && $bg = $styles[Background::class]) {
$texture = \SDL_CreateTexture($viewport->renderPtr, \SDL_PIXELFORMAT_ARGB8888, \SDL_TEXTUREACCESS_TARGET, 200, 100);
\SDL_SetRenderTarget($viewport->renderPtr, $texture);
\SDL_SetRenderDrawColor($viewport->renderPtr, 0, 0, 0, 255);
\SDL_RenderClear($viewport->renderPtr);
$rect = new \SDL_FRect($viewport->x, $viewport->y, $viewport->width, $viewport->height);
\SDL_SetRenderDrawColor($viewport->renderPtr, $bg->color->red, $bg->color->green, $bg->color->blue, $bg->color->alpha);
\SDL_RenderFillRect($viewport->renderPtr, $rect);
$thread->addToRenderStack(new Item($view->getId(), $texture, $rect, 0));
}
if(isset($styles[Padding::class]) && $m = $styles[Padding::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height -= ($m->bottom + $m->top);
}
if($view->getViews()->count() > 0) {
Widget::render($thread, $viewport, $view->getViews()->first());
}
return $viewport;
}
}

View File

@ -8,6 +8,7 @@ use PHPNative\Renderer\Item;
use PHPNative\Renderer\Thread;
use PHPNative\Renderer\Viewport;
use PHPNative\Renderer\Widget;
use PHPNative\Tailwind\Style\AlignEnum;
use PHPNative\Tailwind\Style\Background;
use PHPNative\Tailwind\Style\Basis;
use PHPNative\Tailwind\Style\Border;
@ -23,15 +24,20 @@ use PHPNative\Tailwind\StyleParser;
class Button
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Button $view): Viewport
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Button $view, int $index = 0): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, $view->state);
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , 20);
if(isset($styles[Text::class]) && $t = $styles[Text::class]) {
$color = new \SDL_Color($t->color->red, $t->color->green, $t->color->blue, $t->color->alpha);
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , $t->size);
if($t->color->red != -1) {
$color = new \SDL_Color($t->color->red, $t->color->green, $t->color->blue, $t->color->alpha);
}else{
$color = new \SDL_Color(0, 0, 0, 255);
}
}else{
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , 16);
$color = new \SDL_Color(0, 0, 0, 255);
}
$surface = \SDL_TTF_RenderText_Blended($font, $view->label, $color);
@ -76,7 +82,7 @@ class Button
$backdropViewport->height += ($m->top + $m->bottom);
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport);
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport, $index);
if((isset($styles[Width::class]) && $m = $styles[Width::class]) || (isset($styles[Basis::class]) && $m = $styles[Basis::class])) {
@ -87,10 +93,15 @@ class Button
new \SDL_FRect(0, 0, $viewport->width, $surface->h)
));
}else {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), 3));
if(isset($styles[Text::class]) && $styles[Text::class]->align == AlignEnum::center) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + (($viewport->width - $surface->w) /2), $viewport->y, $surface->w, $surface->h), ++$index));
}elseif(isset($styles[Text::class]) && $styles[Text::class]->align == AlignEnum::right) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + ($viewport->width - $surface->w), $viewport->y, $surface->w, $surface->h), ++$index));
}else{
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
}
}else{
}

View File

@ -22,9 +22,9 @@ use PHPNative\Tailwind\StyleParser;
class Container
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Container $view): Viewport
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Container $view, int $index = 0): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, StateEnum::normal);
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, $view->state);
if(isset($styles[Margin::class]) && $m = $styles[Margin::class]) {
$viewport->x += $m->left;
@ -46,6 +46,7 @@ class Container
$flexStyles = [];
if($view->getViews() != null) {
foreach ($view->getViews() as $subView) {
$found = false;
$stylesSubView = StyleParser::parse($subView->style)->getValidStyles($viewport->windowMediaQuery, StateEnum::normal);
@ -68,13 +69,13 @@ class Container
if ($found) {
if (isset($styles[Flex::class]) && $f = $styles[Flex::class] && $styles[Flex::class]->direction == DirectionEnum::column) {
$viepo = new Viewport($viewport->windowId, $viewport->renderPtr, $viewport->x, $viewport->y, $width, $viewport->height, $viewport->windowWidth, $viewport->windowHeight, $viewport->windowMediaQuery);
$viepo = new Viewport($viewport->windowId, $viewport->windowPtr, $viewport->renderPtr, $viewport->x, $viewport->y, $width, $viewport->height, $viewport->windowWidth, $viewport->windowHeight, $viewport->windowMediaQuery);
} else {
$viepo = new Viewport($viewport->windowId, $viewport->renderPtr, $viewport->x + (count($flexStyles) === 0 ? 0 : end($flexStyles)->x+end($flexStyles)->width), $viewport->y, $width, $viewport->height, $viewport->windowWidth, $viewport->windowHeight, $viewport->windowMediaQuery);
$viepo = new Viewport($viewport->windowId, $viewport->windowPtr, $viewport->renderPtr, $viewport->x + (count($flexStyles) === 0 ? 0 : end($flexStyles)->x+end($flexStyles)->width), $viewport->y, $width, $viewport->height, $viewport->windowWidth, $viewport->windowHeight, $viewport->windowMediaQuery);
}
$flexStyles[] = $viepo;
} else {
$flexStyles[] = $viewport;
$flexStyles[] = clone $viewport;
}
}
@ -83,7 +84,7 @@ class Container
if (isset($styles[Flex::class]) && $f = $styles[Flex::class] && $styles[Flex::class]->direction == DirectionEnum::column) {
$subViewPort = array_shift($flexStyles);
$subViewPort->y = $viewport->y - $view->getMoveToY();
$vp = Widget::render($thread, $subViewPort, $subView);
$vp = Widget::render($thread, $subViewPort, $subView, $index+1);
if($vp->y < $targetViewport->y) {
$thread->clipFromStack($subView->getId(), y: $targetViewport->y-$vp->y);
}
@ -93,9 +94,19 @@ class Container
$viewport->y += $vp->height;
$viewport->height -= $vp->height;
} else {
$vp = Widget::render($thread, array_shift($flexStyles), $subView);
} elseif(isset($styles[Flex::class]) && $f = $styles[Flex::class] && $styles[Flex::class]->direction == DirectionEnum::row) {
$vp = Widget::render($thread, array_shift($flexStyles), $subView, $index+1);
$topHeight = max($topHeight, $vp->height);
} else{
$sfs = array_shift($flexStyles);
$vp = Widget::render($thread, $sfs, $subView, $index+1);
$topHeight = max($topHeight, $vp->height);
if(count($flexStyles) > 0) {
if($vp->addX > 0) {
$flexStyles[0]->x += $vp->addX;
$flexStyles[0]->width -= $vp->addX;
}
}
}
}
if (isset($styles[Flex::class]) && $f = $styles[Flex::class] && $styles[Flex::class]->direction == DirectionEnum::column) {
@ -104,16 +115,43 @@ class Container
$targetViewport->height = $topHeight;
$viewport->y += $topHeight;
$viewport->height = $topHeight;
if(isset($styles[Padding::class]) && $m = $styles[Padding::class]) {
$targetViewport->height += ($m->bottom + $m->top);
$viewport->height += ($m->bottom + $m->top);
}
if(isset($styles[Margin::class]) && $m = $styles[Margin::class]) {
$viewport->height += ($m->bottom + $m->top);
}
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $targetViewport);
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEMOVE) {
if( $targetViewport->x <= $thread->getEvent()->x &&
$thread->getEvent()->x <= $targetViewport->x + $targetViewport->width &&
$targetViewport->y <= $thread->getEvent()->y &&
$thread->getEvent()->y <= $targetViewport->y + $targetViewport->height ) {
$view->state = StateEnum::hover;
}else{
$view->state = StateEnum::normal;
}
}
if($view instanceof \PHPNative\UI\Widget\Button && $thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEBUTTON_UP) {
if( $targetViewport->x <= $thread->getEvent()->x &&
$thread->getEvent()->x <= $targetViewport->x + $targetViewport->width &&
$targetViewport->y <= $thread->getEvent()->y && $thread->getEvent()->y <=
$targetViewport->y + $targetViewport->height ) {
$view->onClick($thread->worker);
}
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $targetViewport, $index);
if (isset($styles[Overflow::class]) && $f = $styles[Overflow::class] && (
$styles[Overflow::class]->y == OverflowEnum::scroll ||
($styles[Overflow::class]->y == OverflowEnum::auto && $viewport->height < 0)
)) {
\PHPNative\Renderer\Visuals\Scrollbar::renderBackground($view->getId(), $thread, $styles, $targetViewport);
\PHPNative\Renderer\Visuals\Scrollbar::renderBackground($view->getId(), $thread, $styles, $targetViewport, $index);
if ($thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEBUTTON_DOWN) {
if ($targetViewport->x + $targetViewport->width - 10 <= $thread->getEvent()->x &&
@ -154,7 +192,7 @@ class Container
$sliderViewport->y = $targetViewport->y + (int)($view->getMoveToY()*$ratio);
$sliderViewport->height = (int)($ratio*100 * $ohP);
\PHPNative\Renderer\Visuals\Scrollbar::renderSlider($view->getId(), $thread, $styles, $sliderViewport);
\PHPNative\Renderer\Visuals\Scrollbar::renderSlider($view->getId(), $thread, $styles, $sliderViewport, $index);
}
}

View File

@ -0,0 +1,103 @@
<?php
namespace PHPNative\Renderer\Widgets;
use PHPNative\Event\EventType;
use PHPNative\Renderer\GFX;
use PHPNative\Renderer\Item;
use PHPNative\Renderer\Thread;
use PHPNative\Renderer\Viewport;
use PHPNative\Renderer\Widget;
use PHPNative\Tailwind\Style\Background;
use PHPNative\Tailwind\Style\Basis;
use PHPNative\Tailwind\Style\Border;
use PHPNative\Tailwind\Style\Margin;
use PHPNative\Tailwind\Style\MediaQueryEnum;
use PHPNative\Tailwind\Style\Padding;
use PHPNative\Tailwind\Style\StateEnum;
use PHPNative\Tailwind\Style\Text;
use PHPNative\Tailwind\Style\Unit;
use PHPNative\Tailwind\Style\Width;
use PHPNative\Tailwind\StyleParser;
class Icon
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Icon $view, int $index = 0): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, $view->state);
if(isset($styles[\PHPNative\Tailwind\Style\Text::class]) && $t = $styles[\PHPNative\Tailwind\Style\Text::class]) {
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/symbol.ttf' , $view->size);
if($t->color->red != -1) {
$color = new \SDL_Color($t->color->red, $t->color->green, $t->color->blue, $t->color->alpha);
}else{
$color = new \SDL_Color(0, 0, 0, 255);
}
}else{
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/symbol.ttf' , $view->size);
$color = new \SDL_Color(0, 0, 0, 255);
}
$surface = \SDL_TTF_RenderGlyph_Blended($font, $view->icon->value, $color);
if(!isset($styles[Basis::class]) && !isset($styles[Width::class])) {
$viewport->width = $surface->w;
}
$viewport->height = $surface->h;
if(isset($styles[Margin::class]) && $m = $styles[Margin::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height += ($m->bottom + $m->top);
}
$backdropViewport = clone $viewport;
$backdropViewport->height = $surface->h;
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEMOVE) {
if( $viewport->x <= $thread->getEvent()->x &&
$thread->getEvent()->x <= $viewport->x + $viewport->width &&
$viewport->y <= $thread->getEvent()->y &&
$thread->getEvent()->y <= $viewport->y + $viewport->height ) {
$view->state = StateEnum::hover;
}else{
$view->state = StateEnum::normal;
}
}
if(isset($styles[Padding::class]) && $m = $styles[Padding::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height += ($m->bottom + $m->top);
$backdropViewport->height += ($m->bottom + $m->top);
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport, $index);
if((isset($styles[Width::class]) && $m = $styles[Width::class]) || (isset($styles[Basis::class]) && $m = $styles[Basis::class])) {
$textureFont = \SDL_CreateTextureFromSurface($viewport->renderPtr, $surface);
if($surface->w > $viewport->width) {
$thread->addToRenderStack(new Item($textureFont,
new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), 3,
new \SDL_FRect(0, 0, $viewport->width, $surface->h)
));
}else{
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
}else{
$textureFont = \SDL_CreateTextureFromSurface($viewport->renderPtr, $surface);
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
if(!isset($styles[Basis::class]) && !isset($styles[Width::class])) {
$viewport->addX = $viewport->width;
}
return $viewport;
}
}

View File

@ -20,20 +20,17 @@ use PHPNative\Tailwind\Style\Unit;
use PHPNative\Tailwind\Style\Width;
use PHPNative\Tailwind\StyleParser;
class Label
class Image
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Label $view): Viewport
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Image $view, int $index = 0): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, $view->state);
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , 20);
if(isset($styles[Text::class]) && $t = $styles[Text::class]) {
$color = new \SDL_Color($t->color->red, $t->color->green, $t->color->blue, $t->color->alpha);
}else{
$color = new \SDL_Color(0, 0, 0, 255);
if(!file_exists($view->src)) {
return $viewport;
}
$surface = \SDL_TTF_RenderText_Blended($font, $view->label, $color);
$surface = \SDL_IMG_Load($view->src);
$viewport->height = $surface->h;
@ -66,7 +63,7 @@ class Label
$backdropViewport->height += ($m->bottom + $m->top);
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport);
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport, $index);
if((isset($styles[Width::class]) && $m = $styles[Width::class]) || (isset($styles[Basis::class]) && $m = $styles[Basis::class])) {
@ -77,10 +74,11 @@ class Label
new \SDL_FRect(0, 0, $viewport->width, $surface->h)
));
}else{
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), 3));
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
}else{
$textureFont = \SDL_CreateTextureFromSurface($viewport->renderPtr, $surface);
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
return $viewport;

View File

@ -0,0 +1,119 @@
<?php
namespace PHPNative\Renderer\Widgets;
use PHPNative\Event\EventType;
use PHPNative\Renderer\GFX;
use PHPNative\Renderer\Item;
use PHPNative\Renderer\Thread;
use PHPNative\Renderer\Viewport;
use PHPNative\Tailwind\Style\AlignEnum;
use PHPNative\Tailwind\Style\Basis;
use PHPNative\Tailwind\Style\Border;
use PHPNative\Tailwind\Style\Margin;
use PHPNative\Tailwind\Style\MediaQueryEnum;
use PHPNative\Tailwind\Style\Padding;
use PHPNative\Tailwind\Style\StateEnum;
use PHPNative\Tailwind\Style\Width;
use PHPNative\Tailwind\StyleParser;
class Text
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\Text $view, int $index = 0): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, $view->state);
if(isset($styles[\PHPNative\Tailwind\Style\Text::class]) && $t = $styles[\PHPNative\Tailwind\Style\Text::class]) {
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , $t->size);
if($t->color->red != -1) {
$color = new \SDL_Color($t->color->red, $t->color->green, $t->color->blue, $t->color->alpha);
}else{
$color = new \SDL_Color(0, 0, 0, 255);
}
}else{
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , 16);
$color = new \SDL_Color(0, 0, 0, 255);
}
$surface = \SDL_TTF_RenderText_Blended($font, $view->text, $color);
if(!isset($styles[Basis::class]) && !isset($styles[Width::class])) {
$viewport->width = $surface->w;
}
$viewport->height = $surface->h;
if(isset($styles[Margin::class]) && $m = $styles[Margin::class]) {
$viewport->x += $m->left;
if(!isset($styles[Basis::class]) && !isset($styles[Width::class])) {
$viewport->width += ($m->right + $m->left);
}else{
$viewport->width -= ($m->right + $m->left);
}
$viewport->y += $m->top;
$viewport->height += ($m->bottom + $m->top);
}
$backdropViewport = clone $viewport;
$backdropViewport->height = $surface->h;
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEMOVE) {
if( $viewport->x <= $thread->getEvent()->x &&
$thread->getEvent()->x <= $viewport->x + $viewport->width &&
$viewport->y <= $thread->getEvent()->y &&
$thread->getEvent()->y <= $viewport->y + $viewport->height ) {
$view->state = StateEnum::hover;
}else{
$view->state = StateEnum::normal;
}
}
if(isset($styles[Padding::class]) && $m = $styles[Padding::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height += ($m->bottom + $m->top);
$backdropViewport->height += ($m->top + $m->bottom);
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport, $index);
if((isset($styles[Width::class]) && $m = $styles[Width::class]) || (isset($styles[Basis::class]) && $m = $styles[Basis::class])) {
$textureFont = \SDL_CreateTextureFromSurface($viewport->renderPtr, $surface);
if($surface->w > $viewport->width) {
$thread->addToRenderStack(new Item($textureFont,
new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), 3,
new \SDL_FRect(0, 0, $viewport->width, $surface->h)
));
}else {
if(isset($styles[\PHPNative\Tailwind\Style\Text::class]) && $styles[\PHPNative\Tailwind\Style\Text::class]->align == AlignEnum::center) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + (($viewport->width - $surface->w) /2), $viewport->y, $surface->w, $surface->h), ++$index));
}elseif(isset($styles[Text::class]) && $styles[Text::class]->align == AlignEnum::right) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + ($viewport->width - $surface->w), $viewport->y, $surface->w, $surface->h), ++$index));
}else{
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
}
}else{
$textureFont = \SDL_CreateTextureFromSurface($viewport->renderPtr, $surface);
if($surface->w > $viewport->width) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont,
new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), 3,
new \SDL_FRect(0, 0, $viewport->width, $surface->h)
));
}else {
if(isset($styles[\PHPNative\Tailwind\Style\Text::class]) && $styles[\PHPNative\Tailwind\Style\Text::class]->align == AlignEnum::center) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + (($viewport->width - $surface->w) /2), $viewport->y, $surface->w, $surface->h), ++$index));
}elseif(isset($styles[Text::class]) && $styles[Text::class]->align == AlignEnum::right) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + ($viewport->width - $surface->w), $viewport->y, $surface->w, $surface->h), ++$index));
}else{
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
}
}
return $viewport;
}
}

View File

@ -0,0 +1,179 @@
<?php
namespace PHPNative\Renderer\Widgets;
use PHPNative\Event\EventType;
use PHPNative\Event\Key;
use PHPNative\Renderer\GFX;
use PHPNative\Renderer\Item;
use PHPNative\Renderer\Thread;
use PHPNative\Renderer\Viewport;
use PHPNative\Renderer\Visuals\Cursor;
use PHPNative\Renderer\Widget;
use PHPNative\Tailwind\Style\AlignEnum;
use PHPNative\Tailwind\Style\Background;
use PHPNative\Tailwind\Style\Basis;
use PHPNative\Tailwind\Style\Border;
use PHPNative\Tailwind\Style\Margin;
use PHPNative\Tailwind\Style\MediaQueryEnum;
use PHPNative\Tailwind\Style\Padding;
use PHPNative\Tailwind\Style\StateEnum;
use PHPNative\Tailwind\Style\Text;
use PHPNative\Tailwind\Style\Unit;
use PHPNative\Tailwind\Style\Width;
use PHPNative\Tailwind\StyleParser;
class TextEdit
{
public static function render(Thread $thread, Viewport $viewport, \PHPNative\UI\Widget\TextEdit $view, int $index = 0): Viewport
{
$styles = StyleParser::parse($view->style)->getValidStyles($viewport->windowMediaQuery, $view->state);
if(isset($styles[Text::class]) && $t = $styles[Text::class]) {
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , $t->size);
if($t->color->red != -1) {
$color = new \SDL_Color($t->color->red, $t->color->green, $t->color->blue, $t->color->alpha);
}else{
$color = new \SDL_Color(0, 0, 0, 255);
}
}else{
$font = \SDL_TTF_OpenFont(__DIR__ . DIRECTORY_SEPARATOR . '../../../../../assets/segoe-ui.ttf' , 16);
$color = new \SDL_Color(0, 0, 0, 255);
}
if($view->value == "" && $view->placeholder != null) {
$color = new \SDL_Color(0, 0, 0, 128);
$surface = \SDL_TTF_RenderText_Blended($font, $view->placeholder, $color);
$cursorWidth = 0;
}else{
$surface = \SDL_TTF_RenderText_Blended($font, $view->value, $color);
$surfaceCursor = \SDL_TTF_RenderText_Blended($font, mb_substr($view->value, 0, $view->textEditIndex), $color);
$cursorWidth = $surfaceCursor->w;
}
$viewport->height = $surface->h;
if(isset($styles[Margin::class]) && $m = $styles[Margin::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height += ($m->bottom + $m->top);
}
$backdropViewport = clone $viewport;
$backdropViewport->height = $surface->h;
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEMOVE) {
if( $viewport->x <= $thread->getEvent()->x &&
$thread->getEvent()->x <= $viewport->x + $viewport->width &&
$viewport->y <= $thread->getEvent()->y &&
$thread->getEvent()->y <= $viewport->y + $viewport->height ) {
if($view->state == StateEnum::focus || $view->state == StateEnum::hoverfocus) {
$view->state = StateEnum::hoverfocus;
}else{
$view->state = StateEnum::hover;
}
}else{
if($view->state == StateEnum::hoverfocus ) {
$view->state = StateEnum::focus;
}
if($view->state != StateEnum::focus ) {
$view->state = StateEnum::normal;
}
}
}
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::MOUSEBUTTON_UP) {
if( $viewport->x <= $thread->getEvent()->x &&
$thread->getEvent()->x <= $viewport->x + $viewport->width &&
$viewport->y <= $thread->getEvent()->y && $thread->getEvent()->y <=
$viewport->y + $viewport->height ) {
$view->state = StateEnum::focus;
\SDL_StartTextInput($thread->windowPtr);
}else{
\SDL_StopTextInput($thread->windowPtr);
$view->state = StateEnum::normal;
}
}
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::KEYUP && $thread->getEvent()->key == Key::BACKSPACE) {
if($view->textEditIndex > 0) {
$view->value = self::str_delete($view->value, $view->textEditIndex);
$view->textEditIndex -= 1;
}
}
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::TEXTINPUT && $view->state === StateEnum::focus) {
if($view->value != "") {
$view->value = self::str_insert($view->value, $thread->getEvent()->text, $view->textEditIndex);
}else {
$view->value = $view->value . $thread->getEvent()->text;
}
$view->textEditIndex += mb_strlen($thread->getEvent()->text);
}
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::KEYUP && $thread->getEvent()->key == Key::SDLK_LEFT) {
if($view->textEditIndex > 0) {
$view->textEditIndex -= 1;
}
}
if($thread->getEvent() && $thread->getEvent()->getType() === EventType::KEYUP && $thread->getEvent()->key == Key::SDLK_RIGHT) {
if($view->textEditIndex < mb_strlen($view->value)) {
$view->textEditIndex += 1;
}
}
if(isset($styles[Padding::class]) && $m = $styles[Padding::class]) {
$viewport->x += $m->left;
$viewport->width -= ($m->right + $m->left);
$viewport->y += $m->top;
$viewport->height += ($m->bottom + $m->top);
$backdropViewport->height += ($m->top + $m->bottom);
}
\PHPNative\Renderer\Visuals\Visuals::render($view->getId(), $thread, $styles, $backdropViewport, $index);
$currentTime = \SDL_GetTicks() / 500;
if (((int)$currentTime & 1) && ($view->state == StateEnum::focus || $view->state == StateEnum::hoverfocus)) {
$viewportCorsor = clone $viewport;
$viewportCorsor->height = $surface->h;
$viewportCorsor->x += $cursorWidth;
Cursor::render($view->getId(), $thread, $styles, $viewportCorsor, $index);
}
if((isset($styles[Width::class]) && $m = $styles[Width::class]) || (isset($styles[Basis::class]) && $m = $styles[Basis::class])) {
$textureFont = \SDL_CreateTextureFromSurface($viewport->renderPtr, $surface);
if($surface->w > $viewport->width) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont,
new \SDL_FRect($viewport->x, $viewport->y, $viewport->width, $surface->h), 3,
new \SDL_FRect($surface->w - $viewport->width, 0, $viewport->width, $surface->h)
));
}else {
if(isset($styles[Text::class]) && $styles[Text::class]->align == AlignEnum::center) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + (($viewport->width - $surface->w) /2), $viewport->y, $surface->w, $surface->h), ++$index));
}elseif(isset($styles[Text::class]) && $styles[Text::class]->align == AlignEnum::right) {
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x + ($viewport->width - $surface->w), $viewport->y, $surface->w, $surface->h), ++$index));
}else{
$thread->addToRenderStack(new Item($view->getId(), $textureFont, new \SDL_FRect($viewport->x, $viewport->y, $surface->w, $surface->h), ++$index));
}
}
}else{
}
return $viewport;
}
private static function str_delete(string $str, int $pos = 0) {
return mb_substr($str, 0, $pos-1) . mb_substr($str, $pos);
}
private static function str_insert(string $oldString, string $newString, int $pos = 0) {
return mb_substr($oldString, 0, $pos) . $newString . mb_substr($oldString, $pos);
}
}

View File

@ -0,0 +1,18 @@
{
"name": "phpnative/storage",
"license": "MIT",
"require": {
"php": "^8.3",
"zumba/json-serializer": "^3"
},
"autoload": {
"psr-4": {
"PHPNative\\Storage\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"PHPNative\\Storage\\Tests\\": "tests"
}
}
}

View File

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace PHPNative\Storage;
use PHPNative\Framework\App;
use Zumba\JsonSerializer\JsonSerializer;
class Storage
{
public function __construct(private JsonSerializer $jsonSerializer, private App $appConfig)
{
}
public function saveModel(object $model): void
{
$path = $this->getLocalAppData() . DIRECTORY_SEPARATOR . md5($model::class). '.json';
if(!file_exists($this->getLocalAppData())) {
mkdir($this->getLocalAppData(), 0777, true);
}
file_put_contents($path, $this->jsonSerializer->serialize($model));
}
/**
* @template T
* @param class-string<T> $className
* @return T
*/
public function loadModel(string $className): object
{
$path = $this->getLocalAppData() . DIRECTORY_SEPARATOR . md5($className). '.json';
if(file_exists($path)) {
return $this->jsonSerializer->unserialize(file_get_contents($path));
}else{
return new $className();
}
}
private function getLocalAppData() {
$homeDir = $_SERVER['HOME'] ?? '';
if(empty($homeDir)) {
$homeDir = getenv('HOME');
}
if(empty($homeDir) && $this->is_windows()) {
$homeData = $_SERVER['LOCALAPPDATA'] ?? '';
$homeDir = $homeData;
}
if(empty($homeDir) && function_exists('exec')) {
if($this->is_windows()) {
$homeDir = exec('echo %userprofile%');
} else {
$homeDir = exec('echo ~');
}
}
return implode(DIRECTORY_SEPARATOR ,[$homeDir, $this->appConfig->getName()]);
}
private function is_windows() {
return strncasecmp(PHP_OS, "WIN", 3) === 0;
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace PHPNative\Tailwind\Data;
enum Icon:int
{
case plus = 57669;
}

View File

@ -8,6 +8,7 @@ use PHPNative\Tailwind\Style\Margin;
use PHPNative\Tailwind\Style\MediaQueryEnum;
use PHPNative\Tailwind\Style\Padding;
use PHPNative\Tailwind\Style\StateEnum;
use PHPNative\Tailwind\Style\Text;
class StyleCollection extends TypedCollection
{
@ -40,6 +41,8 @@ class StyleCollection extends TypedCollection
\PHPNative\Tailwind\Parser\Margin::merge($tmp[$style->style::class], $style->style);
}elseif(isset($tmp[$style->style::class]) && $style->style::class === Border::class) {
\PHPNative\Tailwind\Parser\Border::merge($tmp[$style->style::class], $style->style);
}elseif(isset($tmp[$style->style::class]) && $style->style::class === Text::class) {
\PHPNative\Tailwind\Parser\Text::merge($tmp[$style->style::class], $style->style);
}else{
$tmp[$style->style::class] = $style->style;
}

View File

@ -4,12 +4,43 @@ declare(strict_types=1);
namespace PHPNative\Tailwind\Parser;
use PHPNative\Tailwind\Style\AlignEnum;
class Text implements Parser
{
public static function parse(string $style): ?\PHPNative\Tailwind\Style\Text
{
$color = new \PHPNative\Tailwind\Style\Color();
preg_match_all('/text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)/', $style, $output_array);
if (count($output_array[0]) > 0) {
$size = match ((string)$output_array[1][0]) {
'xs' => 12,
'sm' => 14,
'base' => 16,
'lg' => 18,
'xl' => 20,
'2xl' => 24,
'3xl' => 30,
'4xl' => 36,
'5xl' => 48,
'6xl' => 60,
'7xl' => 72,
'8xl' => 96,
'9xl' => 128,
};
return new \PHPNative\Tailwind\Style\Text(size: $size);
}
preg_match_all('/text-(center|right|left)/', $style, $output_array);
if (count($output_array[0]) > 0) {
return match ((string)$output_array[1][0]) {
'left' => new \PHPNative\Tailwind\Style\Text(align: AlignEnum::left),
'right' => new \PHPNative\Tailwind\Style\Text(align: AlignEnum::right),
'center' => new \PHPNative\Tailwind\Style\Text(align: AlignEnum::center),
};
}
preg_match_all('/text-(.*)/', $style, $output_array);
if (count($output_array[0]) > 0) {
$colorStyle = $output_array[1][0];
@ -19,4 +50,26 @@ class Text implements Parser
return null;
}
public static function merge(\PHPNative\Tailwind\Style\Text $style1, \PHPNative\Tailwind\Style\Text $style2): void
{
if($style2->color->red != -1) {
$style1->color->red = $style2->color->red;
}
if($style2->color->green != -1) {
$style1->color->green = $style2->color->green;
}
if($style2->color->blue != -1) {
$style1->color->blue = $style2->color->blue;
}
if($style2->color->alpha != -1) {
$style1->color->alpha = $style2->color->alpha;
}
if($style2->size != 16) {
$style1->size = $style2->size;
}
if($style2->align != AlignEnum::left) {
$style1->align = $style2->align;
}
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace PHPNative\Tailwind\Style;
enum AlignEnum
{
case left;
case center;
case right;
}

View File

@ -6,6 +6,7 @@ enum StateEnum
{
case normal;
case hover;
case hoverfocus;
case focus;
case active;
}

View File

@ -6,7 +6,7 @@ namespace PHPNative\Tailwind\Style;
class Text implements Style
{
public function __construct(public Color $color = new Color())
public function __construct(public Color $color = new Color(), public AlignEnum $align = AlignEnum::left, public int $size = 16)
{
}
}

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace PHPNative\Tailwind\Tests;
use PHPNative\Tailwind\Parser\Text;
use PHPNative\Tailwind\Style\AlignEnum;
use PHPUnit\Framework\TestCase;
/**
@ -32,4 +33,18 @@ class TextTest extends TestCase
$this->assertSame(219, $text->color->blue);
$this->assertSame(255, $text->color->alpha);
}
public function test_text_align(): void
{
/** @var \PHPNative\Tailwind\Style\Text $text */
$text = Text::parse("flex text-center");
$this->assertInstanceOf(\PHPNative\Tailwind\Style\Text::class, $text);
$this->assertSame(AlignEnum::center, $text->align);
$text = Text::parse("flex text-left");
$this->assertInstanceOf(\PHPNative\Tailwind\Style\Text::class, $text);
$this->assertSame(AlignEnum::left, $text->align);
$text = Text::parse("flex text-right");
$this->assertInstanceOf(\PHPNative\Tailwind\Style\Text::class, $text);
$this->assertSame(AlignEnum::right, $text->align);
}
}

View File

@ -5,18 +5,15 @@ namespace PHPNative\UI;
use PHPNative\UI\Collection\Views;
use PHPNative\UI\Trait\Id;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\Widget\Container;
class BaseView implements View
class BaseView extends Container
{
use Style;
use Id;
public ?Views $views = null;
public function __construct()
{
}
public function getViews(): ?Views
{
return $this->views;

View File

@ -4,24 +4,24 @@ declare(strict_types=1);
namespace PHPNative\UI\Widget;
use PHPNative\UI\Collection\Views;
use PHPNative\UI\Trait\Action\Click;
use PHPNative\UI\Trait\Id;
use PHPNative\UI\Trait\State;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\View;
class Button implements View
class Button extends Container implements View
{
use Style;
use Click;
use State;
use Id;
public function __construct(public string $label)
public function __construct(public ?Views $views = null, string $style = "")
{
parent::__construct($style);
}
public function getViews(): ?\PHPNative\UI\Collection\Views
{
return $this->views;
}
}

View File

@ -7,6 +7,7 @@ namespace PHPNative\UI\Widget;
use PHPNative\UI\Collection\Views;
use PHPNative\UI\Trait\Action\Scrollbar;
use PHPNative\UI\Trait\Id;
use PHPNative\UI\Trait\State;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\View;
@ -14,6 +15,7 @@ class Container implements View
{
use Style;
use Scrollbar;
use State;
use Id;
public function __construct(string $style = "")

View File

@ -0,0 +1,26 @@
<?php
namespace PHPNative\UI\Widget;
use PHPNative\UI\Collection\Views;
use PHPNative\UI\Trait\Id;
use PHPNative\UI\Trait\State;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\View;
class Icon implements View
{
use Style;
use State;
use Id;
public function __construct(public \PHPNative\Tailwind\Data\Icon $icon = \PHPNative\Tailwind\Data\Icon::plus, public int $size = 30, string $style = '')
{
$this->style = $style;
}
public function getViews(): ?Views
{
return null;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace PHPNative\UI\Widget;
use PHPNative\UI\Collection\Views;
use PHPNative\UI\Trait\Id;
use PHPNative\UI\Trait\State;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\View;
class Image implements View
{
use Style;
use State;
use Id;
public function __construct(public string $src = "", string $style = '')
{
$this->style = $style;
}
public function getViews(): ?Views
{
return null;
}
}

View File

@ -9,13 +9,13 @@ use PHPNative\UI\Trait\State;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\View;
class Label implements View
class Text implements View
{
use Style;
use State;
use Id;
public function __construct(public string $label, string $style = '')
public function __construct(public ?string $text, string $style = '')
{
$this->style = $style;
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace PHPNative\UI\Widget;
use PHPNative\UI\Trait\Id;
use PHPNative\UI\Trait\State;
use PHPNative\UI\Trait\Style;
use PHPNative\UI\View;
class TextEdit implements View
{
use Style;
use State;
use Id;
public int $textEditIndex = 0;
public function __construct(public string $value = "", public ?string $placeholder = null, string $style = '')
{
$this->style = $style;
}
public function getViews(): ?\PHPNative\UI\Collection\Views
{
}
}