Backup
This commit is contained in:
parent
3558819899
commit
37c2a1db67
@ -37,7 +37,8 @@ final class KanbanTaskCard extends Container
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->boardView->selectTask($this->boardId, $this->task);
|
// Start drag operation on click
|
||||||
|
$this->boardView->beginDrag($this->boardId, $this->task, $this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,6 +91,7 @@ final class KanbanBoardView extends Container
|
|||||||
private array $boardViews = [];
|
private array $boardViews = [];
|
||||||
private null|string $selectedTaskId = null;
|
private null|string $selectedTaskId = null;
|
||||||
private null|string $selectedBoardId = null;
|
private null|string $selectedBoardId = null;
|
||||||
|
private null|array $dragState = null;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly string $storagePath,
|
private readonly string $storagePath,
|
||||||
@ -158,6 +160,41 @@ final class KanbanBoardView extends Container
|
|||||||
$this->renderBoards();
|
$this->renderBoards();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function beginDrag(string $boardId, array $task, KanbanTaskCard $card): void
|
||||||
|
{
|
||||||
|
$vp = $card->getViewport();
|
||||||
|
|
||||||
|
$ghost = new Container('bg-yellow-300 border-2 border-red-600 rounded px-3 py-2 shadow-2xl');
|
||||||
|
$ghost->addComponent(new Label($task['title'], 'text-sm text-black'));
|
||||||
|
$ghost->setViewport(clone $vp);
|
||||||
|
$ghost->setContentViewport(clone $vp);
|
||||||
|
$ghost->setOverlay(true);
|
||||||
|
|
||||||
|
$this->addComponent($ghost);
|
||||||
|
|
||||||
|
$this->dragState = [
|
||||||
|
'fromBoardId' => $boardId,
|
||||||
|
'task' => $task,
|
||||||
|
'ghost' => $ghost,
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->statusLabel->setText('Drag gestartet: ' . $task['title']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleDrag(float $mouseX, float $mouseY): void
|
||||||
|
{
|
||||||
|
if ($this->dragState === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/** @var Container $ghost */
|
||||||
|
$ghost = $this->dragState['ghost'];
|
||||||
|
$vp = $ghost->getViewport();
|
||||||
|
$vp->x = (int) ($mouseX - $vp->width / 2);
|
||||||
|
$vp->y = (int) ($mouseY - $vp->height / 2);
|
||||||
|
$ghost->setViewport($vp);
|
||||||
|
$ghost->setContentViewport(clone $vp);
|
||||||
|
}
|
||||||
|
|
||||||
public function moveSelectedToBoard(string $targetBoardId): void
|
public function moveSelectedToBoard(string $targetBoardId): void
|
||||||
{
|
{
|
||||||
if ($this->selectedTaskId === null) {
|
if ($this->selectedTaskId === null) {
|
||||||
@ -218,6 +255,46 @@ final class KanbanBoardView extends Container
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handleMouseRelease(float $mouseX, float $mouseY, int $button): void
|
||||||
|
{
|
||||||
|
parent::handleMouseRelease($mouseX, $mouseY, $button);
|
||||||
|
|
||||||
|
if ($button !== 1 || $this->dragState === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine drop target board
|
||||||
|
$targetBoardId = null;
|
||||||
|
foreach ($this->boardViews as $boardId => $info) {
|
||||||
|
$vp = $info['column']->getViewport();
|
||||||
|
if (
|
||||||
|
$mouseX >= $vp->x &&
|
||||||
|
$mouseX <= ($vp->x + $vp->width) &&
|
||||||
|
$mouseY >= $vp->y &&
|
||||||
|
$mouseY <= ($vp->y + $vp->height)
|
||||||
|
) {
|
||||||
|
$targetBoardId = $boardId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove ghost
|
||||||
|
if (($this->dragState['ghost'] ?? null) instanceof Container) {
|
||||||
|
$this->dragState['ghost']->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = $this->dragState;
|
||||||
|
$this->dragState = null;
|
||||||
|
|
||||||
|
if ($targetBoardId !== null) {
|
||||||
|
$this->selectedBoardId = $state['fromBoardId'];
|
||||||
|
$this->selectedTaskId = $state['task']['id'];
|
||||||
|
$this->moveSelectedToBoard($targetBoardId);
|
||||||
|
} else {
|
||||||
|
$this->statusLabel->setText('Drag abgebrochen.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function renderBoards(): void
|
private function renderBoards(): void
|
||||||
{
|
{
|
||||||
$this->clearChildren();
|
$this->clearChildren();
|
||||||
|
|||||||
@ -7,26 +7,27 @@
|
|||||||
"id": "task_691661d89de735.41071535",
|
"id": "task_691661d89de735.41071535",
|
||||||
"title": "Idee sammeln",
|
"title": "Idee sammeln",
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "task_691661d89de8e0.86926319",
|
|
||||||
"title": "UI Grundlayout",
|
|
||||||
"note": ""
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "board_691661d89de806.79123800",
|
"id": "board_691661d89de806.79123800",
|
||||||
"title": "In Arbeit",
|
"title": "In Arbeit",
|
||||||
"tasks": []
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "task_691661d89de858.46479539",
|
||||||
|
"title": "API anbinden",
|
||||||
|
"note": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "board_691661d89de894.20053237",
|
"id": "board_691661d89de894.20053237",
|
||||||
"title": "Erledigt",
|
"title": "Erledigt",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"id": "task_691661d89de858.46479539",
|
"id": "task_691661d89de8e0.86926319",
|
||||||
"title": "API anbinden",
|
"title": "UI Grundlayout",
|
||||||
"note": ""
|
"note": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -344,6 +344,19 @@ abstract class Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional: handle drag (mouse move with pressed button).
|
||||||
|
* Default: propagate to children.
|
||||||
|
*/
|
||||||
|
public function handleDrag(float $mouseX, float $mouseY): void
|
||||||
|
{
|
||||||
|
foreach ($this->children as $child) {
|
||||||
|
if (method_exists($child, 'handleDrag')) {
|
||||||
|
$child->handleDrag($mouseX, $mouseY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function layout(null|TextRenderer $textRenderer = null): void
|
public function layout(null|TextRenderer $textRenderer = null): void
|
||||||
{
|
{
|
||||||
$this->normalStylesCached = StyleParser::parse($this->style)->getValidStyles(
|
$this->normalStylesCached = StyleParser::parse($this->style)->getValidStyles(
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class Window
|
|||||||
private Viewport $viewport;
|
private Viewport $viewport;
|
||||||
private bool $shouldBeReLayouted = true;
|
private bool $shouldBeReLayouted = true;
|
||||||
private float $pixelRatio = 1.0;
|
private float $pixelRatio = 1.0;
|
||||||
private float $uiScale = 2.0;
|
private float $uiScale = 1.0;
|
||||||
private bool $shouldClose = false;
|
private bool $shouldClose = false;
|
||||||
private $onResize = null;
|
private $onResize = null;
|
||||||
private $onFpsChange = null;
|
private $onFpsChange = null;
|
||||||
@ -51,15 +51,19 @@ class Window
|
|||||||
$flags = SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_RESIZABLE;
|
$flags = SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_RESIZABLE;
|
||||||
|
|
||||||
$this->window = sdl_create_window($title, $width, $height, $flags);
|
$this->window = sdl_create_window($title, $width, $height, $flags);
|
||||||
|
|
||||||
if (!$this->window) {
|
if (!$this->window) {
|
||||||
throw new \Exception('Failed to create window: ' . sdl_get_error());
|
throw new \Exception('Failed to create window: ' . sdl_get_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get window ID for event routing
|
// Get window ID for event routing
|
||||||
$this->windowId = sdl_get_window_id($this->window);
|
$this->windowId = sdl_get_window_id($this->window);
|
||||||
|
// Use display scale as UI scale (e.g. 2.0 on HiDPI)
|
||||||
$this->uiScale = sdl_get_window_display_scale($this->window);
|
if (function_exists('sdl_get_window_display_scale')) {
|
||||||
|
$scale = sdl_get_window_display_scale($this->window);
|
||||||
|
if ($scale > 0.1 && $scale <= 4.0) {
|
||||||
|
$this->uiScale = (float) $scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Enable text input for this window
|
// Enable text input for this window
|
||||||
sdl_start_text_input($this->window);
|
sdl_start_text_input($this->window);
|
||||||
|
|
||||||
@ -237,6 +241,10 @@ class Window
|
|||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
$this->shouldClose = true;
|
$this->shouldClose = true;
|
||||||
|
// Drag handling: mouse move while left button is pressed
|
||||||
|
if ($this->leftButtonDown && $this->rootComponent) {
|
||||||
|
$this->rootComponent->handleDrag($this->mouseX, $this->mouseY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
@ -283,8 +291,9 @@ class Window
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_MOUSE_MOTION:
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
$newMouseX = (float) ($event['x'] ?? 0);
|
// Convert physical pixels to logical coordinates using uiScale
|
||||||
$newMouseY = (float) ($event['y'] ?? 0);
|
$newMouseX = (float) ($event['x'] ?? 0) / $this->uiScale;
|
||||||
|
$newMouseY = (float) ($event['y'] ?? 0) / $this->uiScale;
|
||||||
|
|
||||||
$this->mouseX = $newMouseX;
|
$this->mouseX = $newMouseX;
|
||||||
$this->mouseY = $newMouseY;
|
$this->mouseY = $newMouseY;
|
||||||
@ -316,6 +325,10 @@ class Window
|
|||||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
$button = $event['button'] ?? 0;
|
$button = $event['button'] ?? 0;
|
||||||
|
|
||||||
|
if ($button === 1) {
|
||||||
|
$this->leftButtonDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Check overlays first (in reverse z-index order - highest first)
|
// Check overlays first (in reverse z-index order - highest first)
|
||||||
if ($this->rootComponent) {
|
if ($this->rootComponent) {
|
||||||
$overlays = $this->rootComponent->collectOverlays();
|
$overlays = $this->rootComponent->collectOverlays();
|
||||||
@ -342,6 +355,10 @@ class Window
|
|||||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
$button = $event['button'] ?? 0;
|
$button = $event['button'] ?? 0;
|
||||||
|
|
||||||
|
if ($button === 1) {
|
||||||
|
$this->leftButtonDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Propagate release to root component
|
// Propagate release to root component
|
||||||
if ($this->rootComponent) {
|
if ($this->rootComponent) {
|
||||||
$this->rootComponent->handleMouseRelease($this->mouseX, $this->mouseY, $button);
|
$this->rootComponent->handleMouseRelease($this->mouseX, $this->mouseY, $button);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user