Updated ncurses library, now event driven!
git-svn-id: file:///srv/svn/scanner/trunk@18 a0501263-5b7a-4423-a8ba-1edf086583e7
This commit is contained in:
parent
d1d164b8ec
commit
a3dfc6d2b8
9 changed files with 1007 additions and 648 deletions
|
@ -17,27 +17,44 @@ require_once( 'ncurses.php' );
|
||||||
* @package Nc
|
* @package Nc
|
||||||
* @subpackage Example
|
* @subpackage Example
|
||||||
*/
|
*/
|
||||||
class MyApp extends NcApp {
|
|
||||||
function run() {
|
define( 'DEBUG', 1 );
|
||||||
$nc_main = new NcWindow( $this, 0, 0, 0, 0 );
|
class LogView extends NcTableView {
|
||||||
$nc_main->title( 'Hello There' );
|
public function __construct($parent, $height, $width, $y, $x, $params = array()) {
|
||||||
$nc_main->write( 0, 0, file_get_contents( __FILE__ ) );
|
parent::__construct($parent, $height, $width, $y, $x, $params);
|
||||||
$nc_main->get_char();
|
// If we don't prevent the event logging table from logging its own signals,
|
||||||
$nc_small = new NcWindow( $nc_main, 10, 60, 5, 20 );
|
// it'll find itself in a recursive spiral into memory usage hell
|
||||||
$nc_small->title( 'Progress Bars' );
|
$this->emit_log_filter[] = 'change';
|
||||||
ncurses_attron( NCURSES_A_REVERSE );
|
|
||||||
$bar_1 = new NcProgressBar( $nc_small, 0, 0, 0, 100, true );
|
|
||||||
$bar_1->pos( 57 );
|
|
||||||
$bar_2 = new NcProgressBar( $nc_small, 0, 1, 0, 100, false );
|
|
||||||
$bar_2->pos( 11 );
|
|
||||||
$nc_small->write( 3, 0, 'Text Input:' );
|
|
||||||
$input = new NcTextInput( $nc_small, -12, 3, 12 );
|
|
||||||
$foo = $input->get();
|
|
||||||
$nc_small->write_centered( 4, 'Press any key to destroy this window' );
|
|
||||||
$nc_small->get_char();
|
|
||||||
$nc_small->hide();
|
|
||||||
$nc_main->get_char();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$app = new MyApp();
|
|
||||||
|
class MyEventApp extends NcApp {
|
||||||
|
function init() {
|
||||||
|
$this->screen->title('Ncurses Example Application');
|
||||||
|
$input = array();
|
||||||
|
for($i = 0; $i < 3; $i++) {
|
||||||
|
$input[] = new NcTextInput($this->screen, 0, 2*$i, 0);
|
||||||
|
}
|
||||||
|
$log = new LogView($this->screen, $this->screen->height() - 11, 0, 7, 0, array(
|
||||||
|
'columns' => array(
|
||||||
|
'class' => 'Class',
|
||||||
|
'message' => 'Message'
|
||||||
|
)
|
||||||
|
));
|
||||||
|
$log->title('Application Log');
|
||||||
|
$progress = new NcProgressBar($this->screen, 0, $this->screen->height() - 4, 0);
|
||||||
|
$button = new NcButton($this->screen, 3, 10, $this->screen->height() - 3, 0, 'Quit');
|
||||||
|
Signaler::connect($this, 'log', $log, 'load');
|
||||||
|
Signaler::connect($log, 'change', $progress, 'pos');
|
||||||
|
Signaler::connect($this, 'log_items', $progress, 'max');
|
||||||
|
Signaler::connect($button, 'clicked', $this, 'quit');
|
||||||
|
$log->load($this->log);
|
||||||
|
}
|
||||||
|
function log(&$object, $message) {
|
||||||
|
parent::log($object, $message);
|
||||||
|
$this->emit('log_items', count($this->log) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$app = new MyEventApp();
|
||||||
|
$app->exec();
|
||||||
?>
|
?>
|
||||||
|
|
63
ncurses/ncurses.button.php
Normal file
63
ncurses/ncurses.button.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Button
|
||||||
|
*
|
||||||
|
* @package Nc
|
||||||
|
*/
|
||||||
|
class NcButton extends NcWindow {
|
||||||
|
protected $label = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* Creates a new button widget
|
||||||
|
*
|
||||||
|
* @param NcWindow $parent Parent window
|
||||||
|
* @param integer $width Width
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param float $max Maximum value
|
||||||
|
* @param boolean $show_pct Display the percentage alongside the progress bar
|
||||||
|
*/
|
||||||
|
public function __construct( &$parent, $height, $width, $y, $x, $label = '', $frame = true) {
|
||||||
|
parent::__construct( $parent, $height, $width, $y, $x, $frame );
|
||||||
|
$this->label($label);
|
||||||
|
}
|
||||||
|
public function title($value = false) {
|
||||||
|
parent::title('');
|
||||||
|
}
|
||||||
|
public function label($value = false) {
|
||||||
|
if( $value === false ) {
|
||||||
|
return $this->label;
|
||||||
|
} else {
|
||||||
|
if( $this->active() ) {
|
||||||
|
$this->attribute_on( NCURSES_A_REVERSE );
|
||||||
|
}
|
||||||
|
$this->write_centered(floor($this->height() / 2), $value);
|
||||||
|
$this->attribute_off(NCURSES_A_REVERSE);
|
||||||
|
$this->label = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function click() {
|
||||||
|
$this->emit('clicked');
|
||||||
|
}
|
||||||
|
public function focus() {
|
||||||
|
parent::focus();
|
||||||
|
$this->label($this->label);
|
||||||
|
}
|
||||||
|
public function blur() {
|
||||||
|
parent::blur();
|
||||||
|
$this->label($this->label);
|
||||||
|
}
|
||||||
|
public function on_key_press($key) {
|
||||||
|
switch( $key ) {
|
||||||
|
case 13:
|
||||||
|
// RETURN
|
||||||
|
$this->click();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parent::on_key_press($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
|
@ -12,13 +12,23 @@
|
||||||
* @package Nc
|
* @package Nc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
require_once('signals.php');
|
||||||
|
include_once('ncurses.window.php');
|
||||||
|
include_once('ncurses.button.php');
|
||||||
|
include_once('ncurses.progressbar.php');
|
||||||
|
include_once('ncurses.textinput.php');
|
||||||
|
include_once('ncurses.tableview.php');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PHP ncurses application
|
* PHP ncurses application
|
||||||
*
|
*
|
||||||
* @package Nc
|
* @package Nc
|
||||||
*/
|
*/
|
||||||
abstract class NcApp {
|
abstract class NcApp extends Signaler {
|
||||||
var $screen;
|
protected $nc_screen;
|
||||||
|
protected $screen;
|
||||||
|
protected $log = array();
|
||||||
|
protected $done = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -32,9 +42,11 @@ abstract class NcApp {
|
||||||
ncurses_init();
|
ncurses_init();
|
||||||
$echo ? ncurses_echo() : ncurses_noecho();
|
$echo ? ncurses_echo() : ncurses_noecho();
|
||||||
ncurses_curs_set( (bool)$cursor );
|
ncurses_curs_set( (bool)$cursor );
|
||||||
$this->screen = ncurses_newwin( 0, 0, 0, 0 );
|
$this->nc_screen = ncurses_newwin( 0, 0, 0, 0 );
|
||||||
ncurses_refresh();
|
ncurses_refresh();
|
||||||
$this->run();
|
$this->log($this, 'nCurses Initialized');
|
||||||
|
$this->screen = new NcWindow($this, 0, 0, 0, 0);
|
||||||
|
$this->init();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
|
@ -46,625 +58,29 @@ abstract class NcApp {
|
||||||
ncurses_refresh();
|
ncurses_refresh();
|
||||||
ncurses_end();
|
ncurses_end();
|
||||||
}
|
}
|
||||||
|
public function log(&$object, $message) {
|
||||||
|
if( DEBUG ) {
|
||||||
|
$this->log[] = array(
|
||||||
|
'class' => get_class($object),
|
||||||
|
'message' => $message
|
||||||
|
);
|
||||||
|
$this->emit('log', $this->log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function exec() {
|
||||||
|
if( $this->screen instanceof NcWindow ) {
|
||||||
|
while(!$this->done) {
|
||||||
|
$key = ncurses_getch();
|
||||||
|
$this->screen->on_key_press($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function quit() {
|
||||||
|
$this->done = true;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This is a placeholder function for application code
|
* This is a placeholder function for application code
|
||||||
*/
|
*/
|
||||||
abstract function run();
|
abstract function init();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ncurses window
|
|
||||||
*
|
|
||||||
* Provides a basic window object. A border can be optionally enabled if the window
|
|
||||||
* is large enough to accomodate it, and is enabled by default. If a title is set,
|
|
||||||
* it will be visible at the top of the border if one exists.
|
|
||||||
*
|
|
||||||
* If a parent window is provided, the window will be registered as a child of the
|
|
||||||
* parent, and will be relatively positioned to the parent.
|
|
||||||
*
|
|
||||||
* @package Nc
|
|
||||||
*/
|
|
||||||
class NcWindow {
|
|
||||||
/**
|
|
||||||
* @var resource nc_window resource for the border window, if one exists
|
|
||||||
*/
|
|
||||||
var $frame;
|
|
||||||
/**
|
|
||||||
* @var resource nc_window resource for the container window
|
|
||||||
*/
|
|
||||||
var $window;
|
|
||||||
/**
|
|
||||||
* @var array nc_panel resources for the window and its container
|
|
||||||
*/
|
|
||||||
var $panels = array();
|
|
||||||
/**
|
|
||||||
* @var array children array of child NcWindow references
|
|
||||||
*/
|
|
||||||
var $children = array();
|
|
||||||
/**
|
|
||||||
* @var NcWindow reference to this object's direct parent, if one exists
|
|
||||||
*/
|
|
||||||
var $parent = false;
|
|
||||||
/**
|
|
||||||
* @var integer Absolute column position of the window
|
|
||||||
*/
|
|
||||||
var $x;
|
|
||||||
/**
|
|
||||||
* @var integer Absolute row position of the window
|
|
||||||
*/
|
|
||||||
var $y;
|
|
||||||
/**
|
|
||||||
* @var integer Width of contained window
|
|
||||||
*/
|
|
||||||
var $width;
|
|
||||||
/**
|
|
||||||
* @var integer Height of contained window
|
|
||||||
*/
|
|
||||||
var $height;
|
|
||||||
/**
|
|
||||||
* @var string Window title
|
|
||||||
*/
|
|
||||||
var $title;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* Builds the requested ncurses window.
|
|
||||||
*
|
|
||||||
* @param NcWindow $parent Parent window
|
|
||||||
* @param integer $height Height
|
|
||||||
* @param integer $width Width
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param integer $x Column
|
|
||||||
* @param boolean $framed Include a frame (border). Required for window titles.
|
|
||||||
*/
|
|
||||||
public function __construct( $parent, $height, $width, $y, $x, $framed = true ) {
|
|
||||||
if( $parent instanceof NcWindow ) {
|
|
||||||
$this->parent = $parent;
|
|
||||||
$this->parent->add_child( $this );
|
|
||||||
$x += $parent->x;
|
|
||||||
$y += $parent->y;
|
|
||||||
$width += $width <= 0 ? $parent->width : 0;
|
|
||||||
$height += $height <= 0 ? $parent->height : 0;
|
|
||||||
}
|
|
||||||
if( $framed ) {
|
|
||||||
$this->frame = ncurses_newwin( $height, $width, $y, $x );
|
|
||||||
ncurses_getmaxyx( $this->frame, $max_y, $max_x );
|
|
||||||
if( $max_y >= 2 && $max_x >= 2 ) {
|
|
||||||
$this->window = ncurses_newwin( $max_y - 2, $max_x - 2, $y + 1, $x + 1 );
|
|
||||||
ncurses_wborder( $this->frame, 0,0, 0,0, 0,0, 0,0 );
|
|
||||||
ncurses_wrefresh( $this->frame );
|
|
||||||
$this->panels[] = ncurses_new_panel( $this->frame );
|
|
||||||
} else {
|
|
||||||
$this->window = $this->frame;
|
|
||||||
$this->frame = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->frame = false;
|
|
||||||
$this->window = ncurses_newwin( $height, $width, $y, $x );
|
|
||||||
ncurses_getmaxyx( $this->window, $max_y, $max_x );
|
|
||||||
}
|
|
||||||
$this->width = $this->frame ? $max_x - 2 : $max_x;
|
|
||||||
$this->height = $this->frame ? $max_y - 2 : $max_y;
|
|
||||||
$this->x = $this->frame ? $x + 1 : $x;
|
|
||||||
$this->y = $this->frame ? $y + 1 : $y;
|
|
||||||
ncurses_wrefresh( $this->window );
|
|
||||||
$this->panels[] = ncurses_new_panel( $this->window );
|
|
||||||
ncurses_update_panels();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
public function __destruct() {
|
|
||||||
foreach( $this->panels as $id => $panel ) {
|
|
||||||
ncurses_del_panel( $this->panels[$id] );
|
|
||||||
}
|
|
||||||
ncurses_delwin( $this->window );
|
|
||||||
if( $this->frame !== false ) {
|
|
||||||
ncurses_delwin( $this->frame );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Set or retrieve a window title
|
|
||||||
*
|
|
||||||
* Sets window title to the value provided, returns the current window title
|
|
||||||
* if one is not.
|
|
||||||
*
|
|
||||||
* @param string $value New window title
|
|
||||||
* @return string Window title
|
|
||||||
*/
|
|
||||||
public function title( $value = false ) {
|
|
||||||
if( $value === false ) {
|
|
||||||
return $this->title;
|
|
||||||
} elseif( $this->frame !== false ) {
|
|
||||||
$this->title = $value;
|
|
||||||
ncurses_wborder( $this->frame, 0,0, 0,0, 0,0, 0,0 );
|
|
||||||
ncurses_mvwaddstr( $this->frame, 0, 1, $this->title );
|
|
||||||
ncurses_update_panels();
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Activate an ncurses output attribute
|
|
||||||
*
|
|
||||||
* @param integer NCURSES_A_* constant
|
|
||||||
*/
|
|
||||||
public function attribute_on( $attribute ) {
|
|
||||||
ncurses_wattron( $this->window, $attribute );
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Deactivate an ncurses output attribute
|
|
||||||
*
|
|
||||||
* @param integer NCURSES_A_* constant
|
|
||||||
*/
|
|
||||||
public function attribute_off( $attribute ) {
|
|
||||||
ncurses_wattroff( $this->window, $attribute );
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Write text to the window
|
|
||||||
*
|
|
||||||
* Writes text to the window at the specified coordinates.
|
|
||||||
* Text is truncated to prevent it overflowing off the side of the window. If
|
|
||||||
* the text contains newlines, it is split and each new line will continue from
|
|
||||||
* the same x position as the first, rather than wrapping back to the far left
|
|
||||||
* side of the window as ncurses normally would.
|
|
||||||
*
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param integer $x Column
|
|
||||||
* @param string $text Text to write
|
|
||||||
* @param boolean $update Update the window upon completion
|
|
||||||
*/
|
|
||||||
public function write( $y, $x, $text, $update = true ) {
|
|
||||||
$y = $y < 0 ? $this->height + $y : $y;
|
|
||||||
$x = $x < 0 ? $this->width + $x : $x;
|
|
||||||
$lines = preg_split( '/\r?(\n|\r)/', $text );
|
|
||||||
foreach( $lines as $id => $line ) {
|
|
||||||
$line = substr( $line, 0, $this->width - $x );
|
|
||||||
ncurses_mvwaddstr( $this->window, $y + $id, $x, $line );
|
|
||||||
}
|
|
||||||
if( $update ) {
|
|
||||||
ncurses_update_panels();
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Write centered text
|
|
||||||
*
|
|
||||||
* Writes text centered horizontally within the window on the specified line.
|
|
||||||
*
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param string $text Text to write
|
|
||||||
* @param boolean $update Update the window upon completion
|
|
||||||
*/
|
|
||||||
public function write_centered( $y, $text, $update = true ) {
|
|
||||||
$this->write(
|
|
||||||
$y,
|
|
||||||
floor( $this->width / 2 ) - floor( strlen( $text ) / 2 ),
|
|
||||||
$text,
|
|
||||||
$update
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Write fixed-width text
|
|
||||||
*
|
|
||||||
* Writes a string truncated or padded with spaces to fill the requested width.
|
|
||||||
* If the width is unspecified or zero, the width is defined as the length from
|
|
||||||
* the starting coordinate to the right edge of the window.
|
|
||||||
*
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param integer $x Column
|
|
||||||
* @param string $text Text to write
|
|
||||||
* @param integer $width Field length
|
|
||||||
* @param boolean $update Update the window upon completion
|
|
||||||
*/
|
|
||||||
public function write_fixed( $y, $x, $text, $width = 0, $update = true ) {
|
|
||||||
$width = $width > 0 ? $width : $this->width - $x;
|
|
||||||
$this->write( $y, $x, $this->_string_fixed( $text, $width ), $update );
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Build a fixed-width string
|
|
||||||
*
|
|
||||||
* Truncates a string if it exceeds the specified width, pads it with spaces
|
|
||||||
* if it is too short.
|
|
||||||
*
|
|
||||||
* @param string $text Text to format
|
|
||||||
* @param integer $width Field length
|
|
||||||
* @return string Fixed-width string
|
|
||||||
*/
|
|
||||||
protected function _string_fixed( $text, $width = 0 ) {
|
|
||||||
$width = $width < 0 ? 0 : $width;
|
|
||||||
$text = substr( $text, 0, $width );
|
|
||||||
$text .= str_repeat( ' ', $width - strlen( $text ) );
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Assign a window as a child of this window
|
|
||||||
*
|
|
||||||
* Children of a window are hidden and shown along with their parent widget.
|
|
||||||
*
|
|
||||||
* @param NcWindow $child Child window
|
|
||||||
*/
|
|
||||||
public function add_child( $child ) {
|
|
||||||
$this->children[] = $child;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Hide the window
|
|
||||||
*
|
|
||||||
* @param boolean $update Update the window upon completion
|
|
||||||
*/
|
|
||||||
public function hide( $update = true ) {
|
|
||||||
foreach( $this->panels as $panel ) {
|
|
||||||
ncurses_hide_panel( $panel );
|
|
||||||
}
|
|
||||||
foreach( $this->children as $child ) {
|
|
||||||
$child->hide( false );
|
|
||||||
}
|
|
||||||
if( $update ) {
|
|
||||||
ncurses_update_panels();
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Show the window
|
|
||||||
*
|
|
||||||
* @param boolean $update Update the window upon completion
|
|
||||||
*/
|
|
||||||
public function show( $update = true ) {
|
|
||||||
foreach( $this->panels as $panel ) {
|
|
||||||
ncurses_show_panel( $panel );
|
|
||||||
}
|
|
||||||
foreach( $this->children as $child ) {
|
|
||||||
$child->show( false );
|
|
||||||
}
|
|
||||||
if( $update ) {
|
|
||||||
ncurses_update_panels();
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Clear the window's contents
|
|
||||||
*
|
|
||||||
* @param boolean $update Update the window upon completion
|
|
||||||
*/
|
|
||||||
public function erase( $update = true ) {
|
|
||||||
ncurses_werase( $this->window );
|
|
||||||
if( $update ) {
|
|
||||||
ncurses_wrefresh( $this->window );
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Read a character from the keyboard and return it
|
|
||||||
*
|
|
||||||
* @param boolean $flush Flush the input buffer before requesting a key
|
|
||||||
* @return integer Keycode
|
|
||||||
*/
|
|
||||||
public function get_char( $flush = true ) {
|
|
||||||
if( $flush ) {
|
|
||||||
ncurses_flushinp();
|
|
||||||
}
|
|
||||||
return ncurses_getch();
|
|
||||||
//return ncurses_wgetch( $this->window );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Progress Bar
|
|
||||||
*
|
|
||||||
* @package Nc
|
|
||||||
*/
|
|
||||||
class NcProgressBar extends NcWindow {
|
|
||||||
/**
|
|
||||||
* @var float Maximum value
|
|
||||||
*/
|
|
||||||
var $max;
|
|
||||||
/**
|
|
||||||
* @var float Current value
|
|
||||||
*/
|
|
||||||
var $value;
|
|
||||||
/**
|
|
||||||
* @var boolean Show percentage
|
|
||||||
*/
|
|
||||||
var $show_pct;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* Creates a new progress bar widget
|
|
||||||
*
|
|
||||||
* @param NcWindow $parent Parent window
|
|
||||||
* @param integer $width Width
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param integer $x Column
|
|
||||||
* @param float $max Maximum value
|
|
||||||
* @param boolean $show_pct Display the percentage alongside the progress bar
|
|
||||||
*/
|
|
||||||
public function __construct( &$parent, $width, $y, $x, $max = 100, $show_pct = true ) {
|
|
||||||
parent::__construct( $parent, 1, $width, $y, $x, false );
|
|
||||||
$this->max = $max;
|
|
||||||
$this->show_pct = $show_pct;
|
|
||||||
$this->pos( 0 );
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Set or get the current value
|
|
||||||
*
|
|
||||||
* @param float $value New value
|
|
||||||
* @return float Current value
|
|
||||||
*/
|
|
||||||
public function pos( $value = false ) {
|
|
||||||
if( $value === false ) {
|
|
||||||
return $this->value;
|
|
||||||
} else {
|
|
||||||
$value = $value > $this->max ? $this->max : $value;
|
|
||||||
$this->value = $value;
|
|
||||||
$this->write( 0, 0, '[', false );
|
|
||||||
$width = $this->width - ( $this->show_pct ? 7 : 2 );
|
|
||||||
$width = $width >= 0 ? $width : 0;
|
|
||||||
$complete = floor( $width * $value / $this->max );
|
|
||||||
$this->write( 0, 1, str_repeat( '#', $complete ), false );
|
|
||||||
$this->write( 0, 1 + $complete, str_repeat( ' ', $width - $complete ), false );
|
|
||||||
$this->write( 0, $width + 1, ']', false );
|
|
||||||
if( $this->show_pct ) {
|
|
||||||
$this->write( 0, $width + 3, sprintf( '%3d%%', floor( $value / $this->max * 100 ) ), false );
|
|
||||||
}
|
|
||||||
ncurses_update_panels();
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get or set maximum value
|
|
||||||
*
|
|
||||||
* @param float $value New maximum
|
|
||||||
* @return float Current maximum
|
|
||||||
*/
|
|
||||||
public function max( $value = false ) {
|
|
||||||
if( $value === false ) {
|
|
||||||
return $this->max;
|
|
||||||
} else {
|
|
||||||
$this->max = $value > 0 ? $value : $this->max;
|
|
||||||
$this->pos( $this->value );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text Input
|
|
||||||
*
|
|
||||||
* @package Nc
|
|
||||||
*/
|
|
||||||
class NcTextInput extends NcWindow {
|
|
||||||
/**
|
|
||||||
* @var string Current value
|
|
||||||
*/
|
|
||||||
var $value = '';
|
|
||||||
/**
|
|
||||||
* @var boolean Active
|
|
||||||
*/
|
|
||||||
var $active = false;
|
|
||||||
/**
|
|
||||||
* @var string Perl regular expression for filtering input
|
|
||||||
*/
|
|
||||||
var $filter = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* Creates a new text input widget
|
|
||||||
*
|
|
||||||
* @param NcWindow $parent Parent window
|
|
||||||
* @param integer $width Width
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param integer $x Column
|
|
||||||
* @param string $value Initial value
|
|
||||||
* @param string $filter Perl regular expression for filtering input
|
|
||||||
*/
|
|
||||||
public function __construct( &$parent, $width, $y, $x, $value = '', $filter = false ) {
|
|
||||||
parent::__construct( $parent, 1, $width, $y, $x, false );
|
|
||||||
$this->value = $value;
|
|
||||||
$this->filter = $filter !== false && @preg_match( $filter, '' ) !== false ? $filter : false;
|
|
||||||
$this->update();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Update the input control on the screen
|
|
||||||
*
|
|
||||||
* Widget is highlighted when active
|
|
||||||
*/
|
|
||||||
public function update() {
|
|
||||||
$this->attribute_on( NCURSES_A_UNDERLINE );
|
|
||||||
if( $this->active ) {
|
|
||||||
$this->attribute_on( NCURSES_A_REVERSE );
|
|
||||||
}
|
|
||||||
$this->write_fixed( 0, 0, substr( $this->value, - $this->width ) );
|
|
||||||
$this->attribute_off( NCURSES_A_UNDERLINE );
|
|
||||||
$this->attribute_off( NCURSES_A_REVERSE );
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get or set value
|
|
||||||
*/
|
|
||||||
public function value( $value = false ) {
|
|
||||||
if( $value === false ) {
|
|
||||||
return $this->value;
|
|
||||||
} else {
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Activate input widget and accept input
|
|
||||||
*
|
|
||||||
* Input ends when the user presses the enter key.
|
|
||||||
* If a filter has been set and the input does not pass the filter, the value
|
|
||||||
* reverts to the previous value, and this function returns false.
|
|
||||||
*
|
|
||||||
* @return string|boolean Text entered, or false
|
|
||||||
*/
|
|
||||||
public function get() {
|
|
||||||
$this->active = true;
|
|
||||||
$this->update();
|
|
||||||
while( $this->active ) {
|
|
||||||
$key = $this->get_char();
|
|
||||||
switch( $key ) {
|
|
||||||
case NCURSES_KEY_BACKSPACE:
|
|
||||||
$this->value = substr( $this->value, 0, strlen( $this->value ) - 1 );
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
$this->active = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if( in_array( $key, range( 32, 126 ) ) ) {
|
|
||||||
$this->value .= chr( $key );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->update();
|
|
||||||
}
|
|
||||||
$this->update();
|
|
||||||
return $this->filter !== false && @preg_match( $this->filter, $this->value ) < 1 ? false : $this->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Table View
|
|
||||||
*
|
|
||||||
* @package Nc
|
|
||||||
*/
|
|
||||||
class NcTableView extends NcWindow {
|
|
||||||
/**
|
|
||||||
* @var array Column headings
|
|
||||||
*/
|
|
||||||
var $columns;
|
|
||||||
/**
|
|
||||||
* @var array Recordset
|
|
||||||
*/
|
|
||||||
var $records;
|
|
||||||
/**
|
|
||||||
* @var integer Currently selected record index
|
|
||||||
*/
|
|
||||||
var $selected;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* Creates a new table view
|
|
||||||
*
|
|
||||||
* @param NcWindow $parent Parent window
|
|
||||||
* @param integer $height Height
|
|
||||||
* @param integer $width Width
|
|
||||||
* @param integer $y Row
|
|
||||||
* @param integer $x Column
|
|
||||||
* @param array Array of optional parameters, as follows:
|
|
||||||
* <code>array(
|
|
||||||
* 'columns' => array( 'key' => 'Column Name', ... ),
|
|
||||||
* 'records' => array( array( 'key' => 'value', ... ), ... )
|
|
||||||
* )</code>
|
|
||||||
*/
|
|
||||||
public function __construct( $parent, $height, $width, $y, $x, $params = array() ) {
|
|
||||||
parent::__construct( $parent, $height, $width, $y, $x );
|
|
||||||
$params = !is_array( $params ) ? array() : $params;
|
|
||||||
$this->columns = isset( $params['columns'] ) && is_array( $params['columns'] ) ? $params['columns'] : array();
|
|
||||||
$this->records = isset( $params['records'] ) && is_array( $params['records'] ) ? array_values( $params['records'] ) : array();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Redraw the table and select a record
|
|
||||||
*
|
|
||||||
* Redraws the table with the specified record selected and the view scrolled
|
|
||||||
* accordingly.
|
|
||||||
*
|
|
||||||
* @param integer $selected Selected row
|
|
||||||
*/
|
|
||||||
public function update( $selected = 0 ) {
|
|
||||||
$selected = $selected >= 0 ? $selected : 0;
|
|
||||||
$selected = $selected < count( $this->records ) ? $selected : count( $this->records ) - 1;
|
|
||||||
$this->selected = $selected;
|
|
||||||
$cols = isset( $this->columns ) && is_array( $this->columns ) ? $this->columns : array();
|
|
||||||
if( count( $cols ) == 0 ) {
|
|
||||||
// If there's no columns defined, try and grab 'em from the keys from the first record
|
|
||||||
$record = $this->records[0];
|
|
||||||
$record = is_array( $record ) ? $record : array( $record );
|
|
||||||
foreach( array_keys( $record ) as $col ) {
|
|
||||||
$cols[$col] = $col;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$column_ids = array_keys( $cols );
|
|
||||||
$column_widths = $rows = array();
|
|
||||||
foreach( $cols as $id => $column ) {
|
|
||||||
$column_widths[$id] = strlen( $column );
|
|
||||||
}
|
|
||||||
foreach( $this->records as $id => $record ) {
|
|
||||||
$record = is_array( $record ) ? $record : array( $record );
|
|
||||||
$fields = array();
|
|
||||||
foreach( $column_ids as $col ) {
|
|
||||||
$field = isset( $record[$col] ) ? $record[$col] : '';
|
|
||||||
$field = is_scalar( $field ) ? $field : gettype( $field );
|
|
||||||
$fields[$col] = $field;
|
|
||||||
$column_widths[$col] = $column_widths[$col] < strlen( $field ) ? strlen( $field ) : $column_widths[$col];
|
|
||||||
}
|
|
||||||
$rows[] = $fields;
|
|
||||||
}
|
|
||||||
foreach( $cols as $id => $col ) {
|
|
||||||
$cols[$id] = $col . str_repeat( ' ', $column_widths[$id] - strlen( $col ) );
|
|
||||||
}
|
|
||||||
$this->attribute_on( NCURSES_A_UNDERLINE );
|
|
||||||
$this->attribute_on( NCURSES_A_BOLD );
|
|
||||||
$this->write_fixed( 0, 0, implode( ' ', $cols ), 0, false );
|
|
||||||
$this->attribute_off( NCURSES_A_UNDERLINE );
|
|
||||||
$this->attribute_off( NCURSES_A_BOLD );
|
|
||||||
|
|
||||||
$max_items = ( $this->height - 2 );
|
|
||||||
$offset = ( $selected > $max_items ) ? $selected - $max_items : 0;
|
|
||||||
foreach( $rows as $id => $row ) {
|
|
||||||
if( $id < $offset ) {
|
|
||||||
continue;
|
|
||||||
} elseif( $id - $offset > $max_items ) {
|
|
||||||
// We've reached the maximum row height for this window
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
foreach( $row as $col => $field ) {
|
|
||||||
$row[$col] = $field . str_repeat( ' ', $column_widths[$col] - strlen( $field ) );
|
|
||||||
}
|
|
||||||
if( $selected == $id ) {
|
|
||||||
$this->attribute_on( NCURSES_A_REVERSE );
|
|
||||||
}
|
|
||||||
$this->write_fixed( $id - $offset + 1, 0, implode( ' | ', $row ), 0, false );
|
|
||||||
$this->attribute_off( NCURSES_A_REVERSE );
|
|
||||||
}
|
|
||||||
$x = 0;
|
|
||||||
foreach( array_values( $column_widths ) as $id => $width ) {
|
|
||||||
$x += $width + ( $id == 0 ? 1 : 3 );
|
|
||||||
// Every Column
|
|
||||||
ncurses_wmove( $this->window, 1, $x );
|
|
||||||
ncurses_wvline( $this->window, NCURSES_ACS_VLINE, $this->height - 1 );
|
|
||||||
// Header Row
|
|
||||||
ncurses_wmove( $this->window, 0, $x );
|
|
||||||
$this->attribute_on( NCURSES_A_UNDERLINE );
|
|
||||||
ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 );
|
|
||||||
$this->attribute_off( NCURSES_A_UNDERLINE );
|
|
||||||
// Highlighted Row
|
|
||||||
if( count( $this->records ) > 0 ) {
|
|
||||||
ncurses_wmove( $this->window, $selected - $offset + 1, $x );
|
|
||||||
$this->attribute_on( NCURSES_A_REVERSE );
|
|
||||||
ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 );
|
|
||||||
$this->attribute_off( NCURSES_A_REVERSE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Finally, update
|
|
||||||
ncurses_wrefresh( $this->window );
|
|
||||||
ncurses_doupdate();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Load a recordset
|
|
||||||
*
|
|
||||||
* Recordset should be an array in the following format:
|
|
||||||
* <code>array( array( 'key' => 'value', ... ), ... )</code>
|
|
||||||
*
|
|
||||||
* @param array $records Recordset
|
|
||||||
* @return boolean True if recordset loaded successfully, false otherwise
|
|
||||||
*/
|
|
||||||
public function load( $records ) {
|
|
||||||
if( !is_array( $records ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$this->records = array_values( $records );
|
|
||||||
$this->update();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
81
ncurses/ncurses.progressbar.php
Normal file
81
ncurses/ncurses.progressbar.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Progress Bar
|
||||||
|
*
|
||||||
|
* @package Nc
|
||||||
|
*/
|
||||||
|
class NcProgressBar extends NcWindow {
|
||||||
|
/**
|
||||||
|
* @var float Maximum value
|
||||||
|
*/
|
||||||
|
var $max;
|
||||||
|
/**
|
||||||
|
* @var float Current value
|
||||||
|
*/
|
||||||
|
var $value;
|
||||||
|
/**
|
||||||
|
* @var boolean Show percentage
|
||||||
|
*/
|
||||||
|
var $show_pct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* Creates a new progress bar widget
|
||||||
|
*
|
||||||
|
* @param NcWindow $parent Parent window
|
||||||
|
* @param integer $width Width
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param float $max Maximum value
|
||||||
|
* @param boolean $show_pct Display the percentage alongside the progress bar
|
||||||
|
*/
|
||||||
|
public function __construct( &$parent, $width, $y, $x, $max = 100, $show_pct = true ) {
|
||||||
|
parent::__construct( $parent, 1, $width, $y, $x, false );
|
||||||
|
$this->enabled = false; // Cannot accept focus
|
||||||
|
$this->max = $max;
|
||||||
|
$this->show_pct = $show_pct;
|
||||||
|
$this->pos( 0 );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set or get the current value
|
||||||
|
*
|
||||||
|
* @param float $value New value
|
||||||
|
* @return float Current value
|
||||||
|
*/
|
||||||
|
public function pos( $value = false ) {
|
||||||
|
if( $value === false ) {
|
||||||
|
return $this->value;
|
||||||
|
} else {
|
||||||
|
$value = $value > $this->max ? $this->max : $value;
|
||||||
|
$this->value = $value;
|
||||||
|
$this->write( 0, 0, '[', false );
|
||||||
|
$width = $this->width - ( $this->show_pct ? 7 : 2 );
|
||||||
|
$width = $width >= 0 ? $width : 0;
|
||||||
|
$complete = floor( $width * $value / $this->max );
|
||||||
|
$this->write( 0, 1, str_repeat( '#', $complete ), false );
|
||||||
|
$this->write( 0, 1 + $complete, str_repeat( ' ', $width - $complete ), false );
|
||||||
|
$this->write( 0, $width + 1, ']', false );
|
||||||
|
if( $this->show_pct ) {
|
||||||
|
$this->write( 0, $width + 3, sprintf( '%3d%%', floor( $value / $this->max * 100 ) ), false );
|
||||||
|
}
|
||||||
|
ncurses_update_panels();
|
||||||
|
ncurses_doupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get or set maximum value
|
||||||
|
*
|
||||||
|
* @param float $value New maximum
|
||||||
|
* @return float Current maximum
|
||||||
|
*/
|
||||||
|
public function max( $value = false ) {
|
||||||
|
if( $value === false ) {
|
||||||
|
return $this->max;
|
||||||
|
} else {
|
||||||
|
$this->max = $value > 0 ? $value : $this->max;
|
||||||
|
$this->pos( $this->value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
169
ncurses/ncurses.tableview.php
Normal file
169
ncurses/ncurses.tableview.php
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Table View
|
||||||
|
*
|
||||||
|
* @package Nc
|
||||||
|
*/
|
||||||
|
class NcTableView extends NcWindow {
|
||||||
|
/**
|
||||||
|
* @var array Column headings
|
||||||
|
*/
|
||||||
|
var $columns;
|
||||||
|
/**
|
||||||
|
* @var array Recordset
|
||||||
|
*/
|
||||||
|
var $records;
|
||||||
|
/**
|
||||||
|
* @var integer Currently selected record index
|
||||||
|
*/
|
||||||
|
var $selected;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* Creates a new table view
|
||||||
|
*
|
||||||
|
* @param NcWindow $parent Parent window
|
||||||
|
* @param integer $height Height
|
||||||
|
* @param integer $width Width
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param array Array of optional parameters, as follows:
|
||||||
|
* <code>array(
|
||||||
|
* 'columns' => array( 'key' => 'Column Name', ... ),
|
||||||
|
* 'records' => array( array( 'key' => 'value', ... ), ... )
|
||||||
|
* )</code>
|
||||||
|
*/
|
||||||
|
public function __construct( $parent, $height, $width, $y, $x, $params = array() ) {
|
||||||
|
parent::__construct( $parent, $height, $width, $y, $x );
|
||||||
|
$params = !is_array( $params ) ? array() : $params;
|
||||||
|
$this->columns = isset( $params['columns'] ) && is_array( $params['columns'] ) ? $params['columns'] : array();
|
||||||
|
$this->records = isset( $params['records'] ) && is_array( $params['records'] ) ? array_values( $params['records'] ) : array();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Redraw the table and select a record
|
||||||
|
*
|
||||||
|
* Redraws the table with the specified record selected and the view scrolled
|
||||||
|
* accordingly.
|
||||||
|
*
|
||||||
|
* @param integer $selected Selected row
|
||||||
|
*/
|
||||||
|
public function update( $selected = null ) {
|
||||||
|
$selected = $selected === null ? $this->selected : $selected;
|
||||||
|
$selected = $selected >= 0 ? $selected : 0;
|
||||||
|
$selected = $selected < count( $this->records ) ? $selected : count( $this->records ) - 1;
|
||||||
|
$this->selected = $selected;
|
||||||
|
$cols = isset( $this->columns ) && is_array( $this->columns ) ? $this->columns : array();
|
||||||
|
if( count( $cols ) == 0 ) {
|
||||||
|
// If there's no columns defined, try and grab 'em from the keys from the first record
|
||||||
|
$record = $this->records[0];
|
||||||
|
$record = is_array( $record ) ? $record : array( $record );
|
||||||
|
foreach( array_keys( $record ) as $col ) {
|
||||||
|
$cols[$col] = $col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$column_ids = array_keys( $cols );
|
||||||
|
$column_widths = $rows = array();
|
||||||
|
foreach( $cols as $id => $column ) {
|
||||||
|
$column_widths[$id] = strlen( $column );
|
||||||
|
}
|
||||||
|
foreach( $this->records as $id => $record ) {
|
||||||
|
$record = is_array( $record ) ? $record : array( $record );
|
||||||
|
$fields = array();
|
||||||
|
foreach( $column_ids as $col ) {
|
||||||
|
$field = isset( $record[$col] ) ? $record[$col] : '';
|
||||||
|
$field = is_scalar( $field ) ? $field : gettype( $field );
|
||||||
|
$fields[$col] = $field;
|
||||||
|
$column_widths[$col] = $column_widths[$col] < strlen( $field ) ? strlen( $field ) : $column_widths[$col];
|
||||||
|
}
|
||||||
|
$rows[] = $fields;
|
||||||
|
}
|
||||||
|
foreach( $cols as $id => $col ) {
|
||||||
|
$cols[$id] = $col . str_repeat( ' ', $column_widths[$id] - strlen( $col ) );
|
||||||
|
}
|
||||||
|
$this->attribute_on( NCURSES_A_UNDERLINE );
|
||||||
|
$this->attribute_on( NCURSES_A_BOLD );
|
||||||
|
$this->write_fixed( 0, 0, implode( ' ', $cols ), 0, false );
|
||||||
|
$this->attribute_off( NCURSES_A_UNDERLINE );
|
||||||
|
$this->attribute_off( NCURSES_A_BOLD );
|
||||||
|
|
||||||
|
$max_items = ( $this->height - 2 );
|
||||||
|
$offset = ( $selected > $max_items ) ? $selected - $max_items : 0;
|
||||||
|
foreach( $rows as $id => $row ) {
|
||||||
|
if( $id < $offset ) {
|
||||||
|
continue;
|
||||||
|
} elseif( $id - $offset > $max_items ) {
|
||||||
|
// We've reached the maximum row height for this window
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach( $row as $col => $field ) {
|
||||||
|
$row[$col] = $field . str_repeat( ' ', $column_widths[$col] - strlen( $field ) );
|
||||||
|
}
|
||||||
|
if( $selected == $id ) {
|
||||||
|
$this->attribute_on( NCURSES_A_REVERSE );
|
||||||
|
}
|
||||||
|
$this->write_fixed( $id - $offset + 1, 0, implode( ' | ', $row ), 0, false );
|
||||||
|
$this->attribute_off( NCURSES_A_REVERSE );
|
||||||
|
}
|
||||||
|
$x = 0;
|
||||||
|
foreach( array_values( $column_widths ) as $id => $width ) {
|
||||||
|
$x += $width + ( $id == 0 ? 1 : 3 );
|
||||||
|
// Every Column
|
||||||
|
ncurses_wmove( $this->window, 1, $x );
|
||||||
|
ncurses_wvline( $this->window, NCURSES_ACS_VLINE, $this->height - 1 );
|
||||||
|
// Header Row
|
||||||
|
ncurses_wmove( $this->window, 0, $x );
|
||||||
|
$this->attribute_on( NCURSES_A_UNDERLINE );
|
||||||
|
ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 );
|
||||||
|
$this->attribute_off( NCURSES_A_UNDERLINE );
|
||||||
|
// Highlighted Row
|
||||||
|
if( count( $this->records ) > 0 ) {
|
||||||
|
ncurses_wmove( $this->window, $selected - $offset + 1, $x );
|
||||||
|
$this->attribute_on( NCURSES_A_REVERSE );
|
||||||
|
ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 );
|
||||||
|
$this->attribute_off( NCURSES_A_REVERSE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Finally, update
|
||||||
|
ncurses_wrefresh( $this->window );
|
||||||
|
ncurses_doupdate();
|
||||||
|
$this->emit('change', $this->selected);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Load a recordset
|
||||||
|
*
|
||||||
|
* Recordset should be an array in the following format:
|
||||||
|
* <code>array( array( 'key' => 'value', ... ), ... )</code>
|
||||||
|
*
|
||||||
|
* @param array $records Recordset
|
||||||
|
* @return boolean True if recordset loaded successfully, false otherwise
|
||||||
|
*/
|
||||||
|
public function load( $records ) {
|
||||||
|
if( !is_array( $records ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->records = array_values( $records );
|
||||||
|
$this->update();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function on_key_press($key) {
|
||||||
|
switch( $key ) {
|
||||||
|
case NCURSES_KEY_UP:
|
||||||
|
$this->update($this->selected - 1);
|
||||||
|
break;
|
||||||
|
case NCURSES_KEY_DOWN:
|
||||||
|
$this->update($this->selected + 1);
|
||||||
|
break;
|
||||||
|
case NCURSES_KEY_PPAGE:
|
||||||
|
$this->update($this->selected - $this->height - 2 );
|
||||||
|
break;
|
||||||
|
case NCURSES_KEY_NPAGE:
|
||||||
|
$this->update($this->selected + $this->height - 2 );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parent::on_key_press($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
135
ncurses/ncurses.textinput.php
Normal file
135
ncurses/ncurses.textinput.php
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Text Input
|
||||||
|
*
|
||||||
|
* @package Nc
|
||||||
|
*/
|
||||||
|
class NcTextInput extends NcWindow {
|
||||||
|
/**
|
||||||
|
* @var string Current value
|
||||||
|
*/
|
||||||
|
var $value = '';
|
||||||
|
/**
|
||||||
|
* @var string Last value
|
||||||
|
*/
|
||||||
|
var $last_value = '';
|
||||||
|
/**
|
||||||
|
* @var boolean Active
|
||||||
|
*/
|
||||||
|
var $active = false;
|
||||||
|
/**
|
||||||
|
* @var string Perl regular expression for filtering input
|
||||||
|
*/
|
||||||
|
var $filter = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* Creates a new text input widget
|
||||||
|
*
|
||||||
|
* @param NcWindow $parent Parent window
|
||||||
|
* @param integer $width Width
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param string $value Initial value
|
||||||
|
* @param string $filter Perl regular expression for filtering input
|
||||||
|
*/
|
||||||
|
public function __construct( &$parent, $width, $y, $x, $value = '', $filter = false ) {
|
||||||
|
parent::__construct( $parent, 1, $width, $y, $x, false );
|
||||||
|
$this->last_value = $this->value = $value;
|
||||||
|
$this->filter = $filter !== false && @preg_match( $filter, '' ) !== false ? $filter : false;
|
||||||
|
$this->update();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Update the input control on the screen
|
||||||
|
*
|
||||||
|
* Widget is highlighted when active
|
||||||
|
*/
|
||||||
|
public function update() {
|
||||||
|
$this->attribute_on( NCURSES_A_UNDERLINE );
|
||||||
|
if( $this->active ) {
|
||||||
|
$this->attribute_on( NCURSES_A_REVERSE );
|
||||||
|
}
|
||||||
|
$this->write_fixed( 0, 0, substr( $this->value, - $this->width ) );
|
||||||
|
$this->attribute_off( NCURSES_A_UNDERLINE );
|
||||||
|
$this->attribute_off( NCURSES_A_REVERSE );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get or set value
|
||||||
|
*/
|
||||||
|
public function value( $value = false ) {
|
||||||
|
if( $value === false ) {
|
||||||
|
return $this->value;
|
||||||
|
} else {
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Activate input widget and accept input
|
||||||
|
*
|
||||||
|
* Input ends when the user presses the enter key.
|
||||||
|
* If a filter has been set and the input does not pass the filter, the value
|
||||||
|
* reverts to the previous value, and this function returns false.
|
||||||
|
*
|
||||||
|
* @return string|boolean Text entered, or false
|
||||||
|
*/
|
||||||
|
public function get() {
|
||||||
|
$this->active = true;
|
||||||
|
$this->update();
|
||||||
|
while( $this->active ) {
|
||||||
|
$key = $this->get_char();
|
||||||
|
switch( $key ) {
|
||||||
|
case NCURSES_KEY_BACKSPACE:
|
||||||
|
$this->value = substr( $this->value, 0, strlen( $this->value ) - 1 );
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
$this->active = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if( in_array( $key, range( 32, 126 ) ) ) {
|
||||||
|
$this->value .= chr( $key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->update();
|
||||||
|
}
|
||||||
|
$this->update();
|
||||||
|
return $this->filter !== false && @preg_match( $this->filter, $this->value ) < 1 ? false : $this->value;
|
||||||
|
}
|
||||||
|
public function focus() {
|
||||||
|
parent::focus();
|
||||||
|
$this->active = true;
|
||||||
|
$this->update();
|
||||||
|
}
|
||||||
|
public function blur() {
|
||||||
|
$this->active = false;
|
||||||
|
$this->update();
|
||||||
|
parent::blur();
|
||||||
|
}
|
||||||
|
public function on_key_press($key) {
|
||||||
|
switch( $key ) {
|
||||||
|
case NCURSES_KEY_BACKSPACE:
|
||||||
|
$this->value = substr( $this->value, 0, strlen( $this->value ) - 1 );
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
// ESC
|
||||||
|
$this->value = $this->last_value;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
// TAB
|
||||||
|
case 13:
|
||||||
|
// RETURN
|
||||||
|
if( $this->value !== $this->last_value ) {
|
||||||
|
$this->emit('change', $this->value);
|
||||||
|
}
|
||||||
|
$this->blur();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if( in_array( $key, range( 32, 126 ) ) ) {
|
||||||
|
$this->value .= chr( $key );
|
||||||
|
}
|
||||||
|
parent::on_key_press($key);
|
||||||
|
}
|
||||||
|
$this->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
425
ncurses/ncurses.window.php
Normal file
425
ncurses/ncurses.window.php
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHP ncurses library
|
||||||
|
*
|
||||||
|
* Provides a clean, object-oriented interface to the PHP ncurses functions to ease
|
||||||
|
* the creation of elaborate, functional CLI applications.
|
||||||
|
*
|
||||||
|
* @author Correl J. Roush <correl@gmail.com>
|
||||||
|
* @copyright Copyright (c) 2008, Correl J. Roush
|
||||||
|
* @version 0.1
|
||||||
|
*
|
||||||
|
* @package Nc
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('signals.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ncurses window
|
||||||
|
*
|
||||||
|
* Provides a basic window object. A border can be optionally enabled if the window
|
||||||
|
* is large enough to accomodate it, and is enabled by default. If a title is set,
|
||||||
|
* it will be visible at the top of the border if one exists.
|
||||||
|
*
|
||||||
|
* If a parent window is provided, the window will be registered as a child of the
|
||||||
|
* parent, and will be relatively positioned to the parent.
|
||||||
|
*
|
||||||
|
* @package Nc
|
||||||
|
*/
|
||||||
|
class NcWindow extends Signaler {
|
||||||
|
protected static $max_id = 0;
|
||||||
|
protected $id = 0;
|
||||||
|
/**
|
||||||
|
* @var resource nc_window resource for the border window, if one exists
|
||||||
|
*/
|
||||||
|
protected $frame;
|
||||||
|
/**
|
||||||
|
* @var resource nc_window resource for the container window
|
||||||
|
*/
|
||||||
|
protected $window;
|
||||||
|
/**
|
||||||
|
* @var array nc_panel resources for the window and its container
|
||||||
|
*/
|
||||||
|
protected $panels = array();
|
||||||
|
/**
|
||||||
|
* @var array children array of child NcWindow references
|
||||||
|
*/
|
||||||
|
protected $children = array();
|
||||||
|
/**
|
||||||
|
* @var NcWindow reference to this object's direct parent, if one exists
|
||||||
|
*/
|
||||||
|
protected $parent = false;
|
||||||
|
protected $app = false;
|
||||||
|
/**
|
||||||
|
* @var int ID of the current active object
|
||||||
|
*/
|
||||||
|
public static $active_window = false;
|
||||||
|
public static $windows = array();
|
||||||
|
/**
|
||||||
|
* @var integer Absolute column position of the window
|
||||||
|
*/
|
||||||
|
protected $x;
|
||||||
|
/**
|
||||||
|
* @var integer Absolute row position of the window
|
||||||
|
*/
|
||||||
|
protected $y;
|
||||||
|
/**
|
||||||
|
* @var integer Width of contained window
|
||||||
|
*/
|
||||||
|
protected $width;
|
||||||
|
/**
|
||||||
|
* @var integer Height of contained window
|
||||||
|
*/
|
||||||
|
protected $height;
|
||||||
|
/**
|
||||||
|
* @var string Window title
|
||||||
|
*/
|
||||||
|
protected $title;
|
||||||
|
protected $enabled = true;
|
||||||
|
protected $visible = true;
|
||||||
|
protected $shortcuts = array();
|
||||||
|
protected $emit_log_filter = array('keypress');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* Builds the requested ncurses window.
|
||||||
|
*
|
||||||
|
* @param NcWindow $parent Parent window
|
||||||
|
* @param integer $height Height
|
||||||
|
* @param integer $width Width
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param boolean $framed Include a frame (border). Required for window titles.
|
||||||
|
*/
|
||||||
|
public function __construct( &$parent, $height, $width, $y, $x, $framed = true ) {
|
||||||
|
$this->id = count(self::$windows);
|
||||||
|
self::$windows[] = &$this;
|
||||||
|
if( self::$active_window === false ) {
|
||||||
|
self::$active_window = $this->id;
|
||||||
|
}
|
||||||
|
if( $parent instanceof NcWindow ) {
|
||||||
|
$this->parent = &$parent;
|
||||||
|
$this->app = &$parent->app;
|
||||||
|
$x += $parent->x;
|
||||||
|
$y += $parent->y;
|
||||||
|
$width += $width <= 0 ? $parent->width : 0;
|
||||||
|
$height += $height <= 0 ? $parent->height : 0;
|
||||||
|
} elseif( $parent instanceof NcApp ) {
|
||||||
|
$this->app = &$parent;
|
||||||
|
}
|
||||||
|
if( $framed ) {
|
||||||
|
$this->frame = ncurses_newwin( $height, $width, $y, $x );
|
||||||
|
ncurses_getmaxyx( $this->frame, $max_y, $max_x );
|
||||||
|
if( $max_y >= 2 && $max_x >= 2 ) {
|
||||||
|
$this->window = ncurses_newwin( $max_y - 2, $max_x - 2, $y + 1, $x + 1 );
|
||||||
|
ncurses_wborder( $this->frame, 0,0, 0,0, 0,0, 0,0 );
|
||||||
|
ncurses_wrefresh( $this->frame );
|
||||||
|
$this->panels[] = ncurses_new_panel( $this->frame );
|
||||||
|
} else {
|
||||||
|
$this->window = $this->frame;
|
||||||
|
$this->frame = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->frame = false;
|
||||||
|
$this->window = ncurses_newwin( $height, $width, $y, $x );
|
||||||
|
ncurses_getmaxyx( $this->window, $max_y, $max_x );
|
||||||
|
}
|
||||||
|
$this->width = $this->frame ? $max_x - 2 : $max_x;
|
||||||
|
$this->height = $this->frame ? $max_y - 2 : $max_y;
|
||||||
|
$this->x = $this->frame ? $x + 1 : $x;
|
||||||
|
$this->y = $this->frame ? $y + 1 : $y;
|
||||||
|
ncurses_wrefresh( $this->window );
|
||||||
|
$this->panels[] = ncurses_new_panel( $this->window );
|
||||||
|
ncurses_update_panels();
|
||||||
|
if( $this->parent instanceof NcWindow ) {
|
||||||
|
$this->parent->add_child( $this );
|
||||||
|
}
|
||||||
|
|
||||||
|
self::connect($this, '__emit', $this, '__emit');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
public function __destruct() {
|
||||||
|
foreach( $this->panels as $id => $panel ) {
|
||||||
|
ncurses_del_panel( $this->panels[$id] );
|
||||||
|
}
|
||||||
|
ncurses_delwin( $this->window );
|
||||||
|
if( $this->frame !== false ) {
|
||||||
|
ncurses_delwin( $this->frame );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function get_window($id) {
|
||||||
|
return self::$windows[$id];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set or retrieve a window title
|
||||||
|
*
|
||||||
|
* Sets window title to the value provided, returns the current window title
|
||||||
|
* if one is not.
|
||||||
|
*
|
||||||
|
* @param string $value New window title
|
||||||
|
* @return string Window title
|
||||||
|
*/
|
||||||
|
public function title( $value = false ) {
|
||||||
|
if( $value === false ) {
|
||||||
|
return $this->title;
|
||||||
|
} elseif( $this->frame !== false ) {
|
||||||
|
$this->title = $value;
|
||||||
|
ncurses_wborder( $this->frame, 0,0, 0,0, 0,0, 0,0 );
|
||||||
|
ncurses_mvwaddstr( $this->frame, 0, 1, $this->title );
|
||||||
|
ncurses_update_panels();
|
||||||
|
ncurses_doupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function height() { return $this->height; }
|
||||||
|
public function width() { return $this->width; }
|
||||||
|
public function enabled() { return (bool)$this->enabled; }
|
||||||
|
public function active() { return (bool)($this->id === self::$active_window); }
|
||||||
|
/**
|
||||||
|
* Activate an ncurses output attribute
|
||||||
|
*
|
||||||
|
* @param integer NCURSES_A_* constant
|
||||||
|
*/
|
||||||
|
public function attribute_on( $attribute ) {
|
||||||
|
ncurses_wattron( $this->window, $attribute );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Deactivate an ncurses output attribute
|
||||||
|
*
|
||||||
|
* @param integer NCURSES_A_* constant
|
||||||
|
*/
|
||||||
|
public function attribute_off( $attribute ) {
|
||||||
|
ncurses_wattroff( $this->window, $attribute );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Write text to the window
|
||||||
|
*
|
||||||
|
* Writes text to the window at the specified coordinates.
|
||||||
|
* Text is truncated to prevent it overflowing off the side of the window. If
|
||||||
|
* the text contains newlines, it is split and each new line will continue from
|
||||||
|
* the same x position as the first, rather than wrapping back to the far left
|
||||||
|
* side of the window as ncurses normally would.
|
||||||
|
*
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param string $text Text to write
|
||||||
|
* @param boolean $update Update the window upon completion
|
||||||
|
*/
|
||||||
|
public function write( $y, $x, $text, $update = true ) {
|
||||||
|
$y = $y < 0 ? $this->height + $y : $y;
|
||||||
|
$x = $x < 0 ? $this->width + $x : $x;
|
||||||
|
$lines = preg_split( '/\r?(\n|\r)/', $text );
|
||||||
|
foreach( $lines as $id => $line ) {
|
||||||
|
$line = substr( $line, 0, $this->width - $x );
|
||||||
|
ncurses_mvwaddstr( $this->window, $y + $id, $x, $line );
|
||||||
|
}
|
||||||
|
if( $update ) {
|
||||||
|
ncurses_update_panels();
|
||||||
|
ncurses_doupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Write centered text
|
||||||
|
*
|
||||||
|
* Writes text centered horizontally within the window on the specified line.
|
||||||
|
*
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param string $text Text to write
|
||||||
|
* @param boolean $update Update the window upon completion
|
||||||
|
*/
|
||||||
|
public function write_centered( $y, $text, $update = true ) {
|
||||||
|
$this->write(
|
||||||
|
$y,
|
||||||
|
floor( $this->width / 2 ) - floor( strlen( $text ) / 2 ),
|
||||||
|
$text,
|
||||||
|
$update
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Write fixed-width text
|
||||||
|
*
|
||||||
|
* Writes a string truncated or padded with spaces to fill the requested width.
|
||||||
|
* If the width is unspecified or zero, the width is defined as the length from
|
||||||
|
* the starting coordinate to the right edge of the window.
|
||||||
|
*
|
||||||
|
* @param integer $y Row
|
||||||
|
* @param integer $x Column
|
||||||
|
* @param string $text Text to write
|
||||||
|
* @param integer $width Field length
|
||||||
|
* @param boolean $update Update the window upon completion
|
||||||
|
*/
|
||||||
|
public function write_fixed( $y, $x, $text, $width = 0, $update = true ) {
|
||||||
|
$width = $width > 0 ? $width : $this->width - $x;
|
||||||
|
$this->write( $y, $x, $this->_string_fixed( $text, $width ), $update );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Build a fixed-width string
|
||||||
|
*
|
||||||
|
* Truncates a string if it exceeds the specified width, pads it with spaces
|
||||||
|
* if it is too short.
|
||||||
|
*
|
||||||
|
* @param string $text Text to format
|
||||||
|
* @param integer $width Field length
|
||||||
|
* @return string Fixed-width string
|
||||||
|
*/
|
||||||
|
protected function _string_fixed( $text, $width = 0 ) {
|
||||||
|
$width = $width < 0 ? 0 : $width;
|
||||||
|
$text = substr( $text, 0, $width );
|
||||||
|
$text .= str_repeat( ' ', $width - strlen( $text ) );
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Assign a window as a child of this window
|
||||||
|
*
|
||||||
|
* Children of a window are hidden and shown along with their parent widget.
|
||||||
|
*
|
||||||
|
* @param NcWindow $child Child window
|
||||||
|
*/
|
||||||
|
public function add_child( $child ) {
|
||||||
|
$this->children[$child->id] = $child;
|
||||||
|
if( count($this->children) == 1 ) {
|
||||||
|
// Make the first child active
|
||||||
|
self::$active_window = $child->id;
|
||||||
|
$child->focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Hide the window
|
||||||
|
*
|
||||||
|
* @param boolean $update Update the window upon completion
|
||||||
|
*/
|
||||||
|
public function hide( $update = true ) {
|
||||||
|
foreach( $this->panels as $panel ) {
|
||||||
|
ncurses_hide_panel( $panel );
|
||||||
|
}
|
||||||
|
foreach( $this->children as $child ) {
|
||||||
|
$child->hide( false );
|
||||||
|
}
|
||||||
|
if( $update ) {
|
||||||
|
ncurses_update_panels();
|
||||||
|
ncurses_doupdate();
|
||||||
|
}
|
||||||
|
$this->visible = false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Show the window
|
||||||
|
*
|
||||||
|
* @param boolean $update Update the window upon completion
|
||||||
|
*/
|
||||||
|
public function show( $update = true ) {
|
||||||
|
foreach( $this->panels as $panel ) {
|
||||||
|
ncurses_show_panel( $panel );
|
||||||
|
}
|
||||||
|
foreach( $this->children as $child ) {
|
||||||
|
$child->show( false );
|
||||||
|
}
|
||||||
|
if( $update ) {
|
||||||
|
ncurses_update_panels();
|
||||||
|
ncurses_doupdate();
|
||||||
|
}
|
||||||
|
$this->visible = true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Clear the window's contents
|
||||||
|
*
|
||||||
|
* @param boolean $update Update the window upon completion
|
||||||
|
*/
|
||||||
|
public function erase( $update = true ) {
|
||||||
|
ncurses_werase( $this->window );
|
||||||
|
if( $update ) {
|
||||||
|
ncurses_wrefresh( $this->window );
|
||||||
|
ncurses_doupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read a character from the keyboard and return it
|
||||||
|
*
|
||||||
|
* @param boolean $flush Flush the input buffer before requesting a key
|
||||||
|
* @return integer Keycode
|
||||||
|
*/
|
||||||
|
public function get_char( $flush = true ) {
|
||||||
|
if( $flush ) {
|
||||||
|
ncurses_flushinp();
|
||||||
|
}
|
||||||
|
return ncurses_getch();
|
||||||
|
//return ncurses_wgetch( $this->window );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shortcut($key, $object = null) {
|
||||||
|
$key = ord(strtolower(chr($key)));
|
||||||
|
if( $object !== null ) {
|
||||||
|
$this->shortcuts[$key] = $object;
|
||||||
|
} elseif( in_array($key, array_keys($this->shortcuts)) ) {
|
||||||
|
unset($this->shortcuts[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Event slots */
|
||||||
|
public function log($message) {
|
||||||
|
if( $this->app ) {
|
||||||
|
$this->app->log($this, "[{$this->id}] $message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function __emit($signal, $args) {
|
||||||
|
if( !in_array($signal, $this->emit_log_filter) ) {
|
||||||
|
foreach($args as $key => $value) {
|
||||||
|
$args[$key] = (string)$value;
|
||||||
|
}
|
||||||
|
$args = implode(',', $args);
|
||||||
|
$this->log("Emitted {$signal}({$args})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function focus() {
|
||||||
|
self::$active_window = $this->id;
|
||||||
|
$this->emit('focus');
|
||||||
|
}
|
||||||
|
public function blur() {
|
||||||
|
$this->emit('blur');
|
||||||
|
if( $this->parent instanceof NcWindow ) {
|
||||||
|
$this->parent->focus_next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function disable() {
|
||||||
|
$this->enabled = false;
|
||||||
|
$this->blur();
|
||||||
|
}
|
||||||
|
public function focus_next() {
|
||||||
|
$next = false;
|
||||||
|
$first = false;
|
||||||
|
foreach( $this->children as $child ) {
|
||||||
|
if( $child->visible && $child->enabled ) {
|
||||||
|
if( $first === false ) {
|
||||||
|
$first = $child;
|
||||||
|
}
|
||||||
|
$next = &$child;
|
||||||
|
if( self::$active_window && $next->id > self::$active_window ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( $next === false ) {
|
||||||
|
$next = &$this;
|
||||||
|
} elseif( $next->id == self::$active_window ) {
|
||||||
|
$next = &$first;
|
||||||
|
}
|
||||||
|
$next->focus();
|
||||||
|
}
|
||||||
|
public function on_key_press($key) {
|
||||||
|
if( self::$active_window === $this->id ) {
|
||||||
|
// This is the active window, handle input
|
||||||
|
switch($key) {
|
||||||
|
case 9:
|
||||||
|
// TAB
|
||||||
|
$this->blur();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pass it along to the active child widget
|
||||||
|
self::get_window(self::$active_window)->on_key_press($key);
|
||||||
|
}
|
||||||
|
$this->emit('keypress', $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
53
ncurses/signals.php
Normal file
53
ncurses/signals.php
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
class Signaler {
|
||||||
|
private $_listeners = array();
|
||||||
|
protected static $current = false;
|
||||||
|
|
||||||
|
static public function connect(Signaler &$emitter, $signal, &$responder, $slot) {
|
||||||
|
if( !is_object($responder) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
elseif( !method_exists($responder, $slot) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if( !array_key_exists($signal, $emitter->_listeners) ) {
|
||||||
|
$emitter->_listeners[$signal] = array();
|
||||||
|
}
|
||||||
|
$emitter->_listeners[$signal][] = array(
|
||||||
|
'object' => &$responder,
|
||||||
|
'method' => $slot
|
||||||
|
);
|
||||||
|
}
|
||||||
|
protected function emit() {
|
||||||
|
self::$current = &$this;
|
||||||
|
$args = func_get_args();
|
||||||
|
if( count($args) == 0 ) {
|
||||||
|
// Called without any arguments, raise an error
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$signal = array_shift($args);
|
||||||
|
$sent = 0;
|
||||||
|
if( array_key_exists($signal, $this->_listeners) ) {
|
||||||
|
foreach( $this->_listeners[$signal] as $key => $listener ) {
|
||||||
|
if(
|
||||||
|
!is_object($listener['object'])
|
||||||
|
|| !method_exists($listener['object'], $listener['method'])
|
||||||
|
) {
|
||||||
|
// Something happened to the object since it was connected,
|
||||||
|
// and it is no longer usable. Drop it.
|
||||||
|
unset($this->_listeners[$key]);
|
||||||
|
} else {
|
||||||
|
// Everything's good, set the callback loose.
|
||||||
|
$result = call_user_func_array(array($listener['object'], $listener['method']), $args);
|
||||||
|
if( $result !== false ) {
|
||||||
|
$sent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Special signal for debugging purposes
|
||||||
|
if( $signal !== '__emit' ) { $this->emit('__emit', $signal, $args); }
|
||||||
|
return $sent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
12
scanner.php
12
scanner.php
|
@ -361,10 +361,10 @@ if( $curses ) {
|
||||||
$nc_faults->update( $nc_faults->selected + 1 );
|
$nc_faults->update( $nc_faults->selected + 1 );
|
||||||
break;
|
break;
|
||||||
case NCURSES_KEY_PPAGE:
|
case NCURSES_KEY_PPAGE:
|
||||||
$nc_faults->update( $nc_faults->selected - $nc_faults->height - 1 );
|
$nc_faults->update( $nc_faults->selected - $nc_faults->height() - 1 );
|
||||||
break;
|
break;
|
||||||
case NCURSES_KEY_NPAGE:
|
case NCURSES_KEY_NPAGE:
|
||||||
$nc_faults->update( $nc_faults->selected + $nc_faults->height - 1 );
|
$nc_faults->update( $nc_faults->selected + $nc_faults->height() - 1 );
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
case 13:
|
case 13:
|
||||||
|
@ -395,8 +395,8 @@ if( $curses ) {
|
||||||
$filename = $nc_save_file_input->get();
|
$filename = $nc_save_file_input->get();
|
||||||
$nc_save_confirm = new NcWindow( $nc_save, -10, -10, 5, 5 );
|
$nc_save_confirm = new NcWindow( $nc_save, -10, -10, 5, 5 );
|
||||||
$nc_save_confirm->title( get_class( $modules['output'] ) );
|
$nc_save_confirm->title( get_class( $modules['output'] ) );
|
||||||
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height / 2 ) - 2, "Save results to '{$filename}'?" );
|
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height() / 2 ) - 2, "Save results to '{$filename}'?" );
|
||||||
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height / 2 ), '[Y]es [N]o [C]ancel' );
|
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height() / 2 ), '[Y]es [N]o [C]ancel' );
|
||||||
$valid_key = false;
|
$valid_key = false;
|
||||||
while( !$valid_key ) {
|
while( !$valid_key ) {
|
||||||
switch( $nc_save_confirm->get_char() ) {
|
switch( $nc_save_confirm->get_char() ) {
|
||||||
|
@ -417,8 +417,8 @@ if( $curses ) {
|
||||||
$result = $modules['output']->write( $filename );
|
$result = $modules['output']->write( $filename );
|
||||||
$save_message = ( $result === false ) ? 'Save Failed' : 'Saved successfully';
|
$save_message = ( $result === false ) ? 'Save Failed' : 'Saved successfully';
|
||||||
$nc_save_confirm->erase();
|
$nc_save_confirm->erase();
|
||||||
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height / 2 ) - 2, $save_message );
|
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height() / 2 ) - 2, $save_message );
|
||||||
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height / 2 ), 'Press any key to continue' );
|
$nc_save_confirm->write_centered( floor( $nc_save_confirm->height() / 2 ), 'Press any key to continue' );
|
||||||
$nc_save_confirm->show();
|
$nc_save_confirm->show();
|
||||||
$nc_save_confirm->get_char();
|
$nc_save_confirm->get_char();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue