Skip to content

Instantly share code, notes, and snippets.

@oranj
Created May 18, 2012 19:49
Show Gist options
  • Save oranj/2727284 to your computer and use it in GitHub Desktop.
Save oranj/2727284 to your computer and use it in GitHub Desktop.
Shell based application rendering system.
<?php
include(dirname(__FILE__).'/shelly.php');
$Window = new ShellWindow();
$item1 = new ShellItem(30, 20, Array('left' => 5, 'top' => 3), 'X', 'yellow');
$item2 = new ShellItem('10', '10', Array('right' => 5, 'bottom' => 10), '*', 'red');
$Window->add_children($item1, $item2);
$Window->draw();
<?php
class ShellItem {
const SIZE_MODE_SCALE = 0;
const SIZE_MODE_CONST = 1;
private $width;
private $height;
private $width_mode;
private $height_mode;
private $anchors;
private $parent;
private $children;
private $border_color;
private $border_width;
private $border_style;
private $padding;
private $stream;
public static function terminal_width() {
return (int)trim(`tput cols`);
}
public static function terminal_height() {
return (int)trim(`tput lines`);
}
public static function terminal_clear() {
system('clear');
}
public static function terminal_set_cursor_position($row, $column) {
echo "\033[".$row.";".$column."H";
}
public static $foreground_colors = array(
'bold' => '1', 'dim' => '2',
'black' => '0;30', 'dark_gray' => '1;30',
'blue' => '0;34', 'light_blue' => '1;34',
'green' => '0;32', 'light_green' => '1;32',
'cyan' => '0;36', 'light_cyan' => '1;36',
'red' => '0;31', 'light_red' => '1;31',
'purple' => '0;35', 'light_purple' => '1;35',
'brown' => '0;33', 'yellow' => '1;33',
'light_gray' => '0;37', 'white' => '1;37',
'normal' => '0;39',
);
public static $background_colors = array(
'black' => '40', 'red' => '41',
'green' => '42', 'yellow' => '43',
'blue' => '44', 'magenta' => '45',
'cyan' => '46', 'light_gray' => '47',
);
public static function colorize($text, $foreground, $background = false) {
$str = "\033[".self::$foreground_colors[$foreground]."m";
if ($background) {
$str .= "\033[".self::$background_colors[$background]."m";
}
$str .= $text;
$str .= "\033[0m";
return $str;
}
public function width() {
if (! is_null($this->anchors['left']) && ! is_null($this->anchors['right'])) {
return $this->parent->width() - $this->parent->inset();
} else if (! is_null($this->parent)) {
switch($this->width_mode) {
case self::SIZE_MODE_SCALE:
return ($this->width / 100) * $this->parent->width();
break;
case self::SIZE_MODE_CONST:
return $this->width;
break;
default:
break;
}
} else {
return self::terminal_width();
}
}
public function height() {
if (! is_null($this->anchors['top']) && ! is_null($this->anchors['bottom'])) {
return $this->parent->height() - $this->parent->inset();
} else if (! is_null($this->parent)) {
switch($this->height_mode) {
case self::SIZE_MODE_SCALE:
return ($this->height / 100) * $this->parent->height();
break;
case self::SIZE_MODE_CONST:
return $this->height;
break;
default:
break;
}
} else {
return self::terminal_height() - 1;
}
}
public function inset() {
return $this->padding + $this->border_width;
}
public function offset() {
$node = $this->parent;
$top = $left = 0;
while (! is_null($node)) {
$offset = $node->offset();
$top += $offset['x'];
$left += $offset['y'];
$node = $node->parent;
}
if ($this->parent) {
$parent_width = $this->parent->width();
$parent_height = $this->parent->height();
} else {
$parent_width = 0;
$parent_height = 0;
}
if (! is_null($this->anchors['left']) && ! is_null($this->anchors['right'])) {
$left += floor(($this->parent->width() - $this->width()) / 2);
} else if (! is_null($this->anchors['left'])) {
$left += $this->anchors['left'];
} else if (! is_null($this->anchors['right'])) {
$left += ($this->parent->width() - ($this->width() + $this->anchors['right']));
}
if (! is_null($this->anchors['top']) && ! is_null($this->anchors['bottom'])) {
$top += floor(($this->parent->height() - $this->height()) / 2);
} else if (! is_null($this->anchors['left'])) {
$top += $this->anchors['top'];
} else if (! is_null($this->anchors['bottom'])) {
$top += ($this->parent->height() - ($this->height() + $this->anchors['bottom']));
}
return Array('x' => $left, 'y' => $top);
}
public function __construct($width, $height, $anchors = array(), $border_style = '#', $border_color = 'blue', $border_width = 1, $padding = 1) {
$this->anchors = Array('left'=>null, 'top'=>null, 'right'=>null, 'bottom'=>null);
$this->width_mode = ((substr($width, -1) == '%')?self::SIZE_MODE_SCALE:self::SIZE_MODE_CONST);
$this->height_mode = ((substr($height, -1) == '%')?self::SIZE_MODE_SCALE:self::SIZE_MODE_CONST);
$this->width = (int)$width;
$this->height = (int)$height;
$this->border_width = $border_width;
$this->border_style = $border_style;
$this->border_color = $border_color;
$this->children = Array();
$this->padding = $padding;
$this->stream = STDERR;
foreach ($this->anchors as $key => $value) {
if (isset($anchors[$key])) {
$this->anchors[$key] = $anchors[$key];
}
}
}
public function add_children() {
$children = func_get_args();
foreach ($children as &$child) {
$this->children []= $child;
$child->set_parent($this);
}
}
public function set_parent($parent) {
$this->parent = $parent;
}
public function draw() {
$offset = $this->offset();
$max_x = $offset['x'] + $this->width();
$max_y = $offset['y'] + $this->height();
$inset = $this->inset();
$inset_x = $offset['x'] + $inset;
$inset_max_x = $max_x - $inset;
$inset_y = $offset['y'] + $inset;
$inset_max_y = $max_y - $inset;
#print_r(Array($offset['x'], $max_x, $offset['y'], $max_y, $this));
$_x = 0;
for ($x = $offset['x']; $x < $max_x; $x++) {
$_y = 0;
for ($y = $offset['y']; $y < $max_y; $y++) {
self::terminal_set_cursor_position($y, $x);
if ($x - $this->border_width < $offset['x'] || $y - $this->border_width < $offset['y'] || $x + $this->border_width >= $max_x || $y + $this->border_width >= $max_y) {
echo self::colorize($this->border_style, $this->border_color);;
} else {
}
$_y++;
}
$_x++;
}
foreach ($this->children as $child) {
$child->draw();
}
self::terminal_set_cursor_position($this->height(), 0);
}
}
class ShellWindow extends ShellItem {
public function __construct() {
parent::__construct(null, null);
}
public function draw() {
self::terminal_clear();
parent::draw();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment