You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.3 KiB
181 lines
4.3 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App;
|
|
|
|
/**
|
|
* Calculate the layout of a collection of screens.
|
|
*
|
|
* @author Adam Pippin <hello@adampippin.ca>
|
|
*/
|
|
class Layout
|
|
{
|
|
/**
|
|
* List of screens this layout uses.
|
|
* @var array<string,array>
|
|
*/
|
|
protected $_screens;
|
|
|
|
/**
|
|
* Relations between the screens.
|
|
* @var array[]
|
|
*/
|
|
protected $_links;
|
|
|
|
/**
|
|
* Initialize a new layout.
|
|
*
|
|
* @param array[] $screens
|
|
* @param array[] $links
|
|
*/
|
|
public function __construct(array $screens, array $links)
|
|
{
|
|
$this->_screens = $screens;
|
|
$this->_links = $links;
|
|
}
|
|
|
|
/**
|
|
* Fetch the names of the screens this layout depends on.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
public function getScreenNames(): array
|
|
{
|
|
return array_keys($this->_screens);
|
|
}
|
|
|
|
/**
|
|
* Execute this layout.
|
|
*
|
|
* @param Configuration $config
|
|
* @param ILayoutDriver $driver
|
|
* @return void
|
|
*/
|
|
public function execute(Configuration $config, ILayoutDriver $driver): void
|
|
{
|
|
$primary_name = $config->getPrimaryScreenName();
|
|
$primary = $config->getPrimaryScreen();
|
|
|
|
$layout_stack = [$primary_name];
|
|
$did_layout = false;
|
|
$layout = [$primary_name => ['x' => 0, 'y' => 0]];
|
|
|
|
foreach ($this->_screens as $screen_name => $screen_data)
|
|
{
|
|
if (isset($screen_data['width']) && isset($screen_data['height']))
|
|
{
|
|
$config->getScreen($screen_name)->setDimensions($screen_data['width'], $screen_data['height']);
|
|
}
|
|
}
|
|
|
|
while (sizeof($layout_stack))
|
|
{
|
|
$did_layout = false;
|
|
$match_screen = array_pop($layout_stack);
|
|
foreach ($this->_links as $link)
|
|
{
|
|
$target_name = $link['display'];
|
|
$source_name = $link['above'] ?? $link['below'] ?? $link['right_of'] ?? $link['left_of'];
|
|
if ($source_name == $match_screen)
|
|
{
|
|
$did_layout = true;
|
|
|
|
$calculate_layout = null;
|
|
if (isset($link['above']))
|
|
{
|
|
/**
|
|
* @return int[]
|
|
*/
|
|
$calculate_layout = static function(int $s_x, int $s_y, int $s_w, int $s_h, int $d_x, int $d_y, int $d_w, int $d_h): array {
|
|
$center = $s_x + ($s_w / 2);
|
|
$x = $center - ($d_w / 2);
|
|
$y = $s_y - $d_h;
|
|
|
|
return [$x, $y];
|
|
};
|
|
}
|
|
elseif (isset($link['below']))
|
|
{
|
|
/**
|
|
* @return int[]
|
|
*/
|
|
$calculate_layout = static function(int $s_x, int $s_y, int $s_w, int $s_h, int $d_x, int $d_y, int $d_w, int $d_h): array {
|
|
$center = $s_x + ($s_w / 2);
|
|
$x = $center - ($d_w / 2);
|
|
$y = $s_y + $s_h;
|
|
|
|
return [$x, $y];
|
|
};
|
|
}
|
|
elseif (isset($link['left_of']))
|
|
{
|
|
/**
|
|
* @return int[]
|
|
*/
|
|
$calculate_layout = static function(int $s_x, int $s_y, int $s_w, int $s_h, int $d_x, int $d_y, int $d_w, int $d_h): array {
|
|
return [$s_x - $d_w, $s_y];
|
|
};
|
|
}
|
|
elseif (isset($link['right_of']))
|
|
{
|
|
/**
|
|
* @return int[]
|
|
*/
|
|
$calculate_layout = static function(int $s_x, int $s_y, int $s_w, int $s_h, int $d_x, int $d_y, int $d_w, int $d_h): array {
|
|
return [$s_x + $s_w, $s_y];
|
|
};
|
|
}
|
|
|
|
$source = $config->getScreen($source_name);
|
|
$target = $config->getScreen($target_name);
|
|
|
|
if (isset($layout[$source_name]))
|
|
{
|
|
$s_x = $layout[$source_name]['x'];
|
|
$s_y = $layout[$source_name]['y'];
|
|
}
|
|
else
|
|
{
|
|
[$s_x, $s_y] = $source->getOffset();
|
|
}
|
|
[$s_w, $s_h] = $source->getDimensions();
|
|
|
|
if (isset($layout[$target_name]))
|
|
{
|
|
$d_x = $layout[$target_name]['x'];
|
|
$d_y = $layout[$target_name]['y'];
|
|
}
|
|
else
|
|
{
|
|
[$d_x, $d_y] = $target->getOffset();
|
|
}
|
|
[$d_w, $d_h] = $target->getDimensions();
|
|
|
|
[$x, $y] = $calculate_layout($s_x, $s_y, $s_w, $s_h, $d_x, $d_y, $d_w, $d_h);
|
|
|
|
$layout[$target_name] = ['x' => $x, 'y' => $y];
|
|
$layout_stack[] = $target_name;
|
|
}
|
|
}
|
|
}
|
|
|
|
$min_x = PHP_INT_MAX;
|
|
$min_y = PHP_INT_MAX;
|
|
|
|
foreach ($layout as $screen_name => $screen_offset)
|
|
{
|
|
$min_x = min($screen_offset['x'], $min_x);
|
|
$min_y = min($screen_offset['y'], $min_y);
|
|
}
|
|
|
|
foreach ($layout as $screen_name => $screen_offset)
|
|
{
|
|
[$current_x, $current_y] = $config->getScreen($screen_name)->getOffset();
|
|
if ($current_x != $screen_offset['x'] - $min_x || $current_y != $screen_offset['y'] - $min_y)
|
|
{
|
|
$config->getScreen($screen_name)->setOffset($screen_offset['x'] - $min_x, $screen_offset['y'] - $min_y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|