Tool for laying out displays on Linux
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.
 
 

170 lines
3.9 KiB

<?php
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[]
*/
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']))
{
$calculate_layout = function($s_x, $s_y, $s_w, $s_h, $d_x, $d_y, $d_w, $d_h) {
$center = $s_x + ($s_w / 2);
$x = $center - ($d_w / 2);
$y = $s_y - $d_h;
return [$x, $y];
};
}
else if (isset($link['below']))
{
$calculate_layout = function($s_x, $s_y, $s_w, $s_h, $d_x, $d_y, $d_w, $d_h) {
$center = $s_x + ($s_w / 2);
$x = $center - ($d_w / 2);
$y = $s_y + $s_h;
return [$x, $y];
};
}
else if (isset($link['left_of']))
{
$calculate_layout = function($s_x, $s_y, $s_w, $s_h, $d_x, $d_y, $d_w, $d_h) {
return [$s_x - $d_w, $s_y];
};
}
else if (isset($link['right_of']))
{
$calculate_layout = function($s_x, $s_y, $s_w, $s_h, $d_x, $d_y, $d_w, $d_h) {
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
{
list($s_x, $s_y) = $source->getOffset();
}
list($s_w, $s_h) = $source->getDimensions();
if (isset($layout[$target_name]))
{
$d_x = $layout[$target_name]['x'];
$d_y = $layout[$target_name]['y'];
}
else
{
list($d_x, $d_y) = $target->getOffset();
}
list($d_w, $d_h) = $target->getDimensions();
list($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)
{
list($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);
}
}
}
}