libprogress.php
changeset 22 04c2f743c6ec
equal deleted inserted replaced
21:d86ea89358ec 22:04c2f743c6ec
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * Class for drawing progress bars in a vt100 console.
       
     5  * @author Dan Fuhry
       
     6  * @license Public domain
       
     7  */
       
     8 
       
     9 class ProgressBar
       
    10 {
       
    11   /**
       
    12    * Shell escape character.
       
    13    * @const string
       
    14    */
       
    15   
       
    16   const SHELL_ESCAPE = "\x1B";
       
    17   
       
    18   /**
       
    19    * Carriage return (0x0D)
       
    20    * @const string
       
    21    */
       
    22   
       
    23   const CARRIAGE_RETURN = "\r";
       
    24   
       
    25   /**
       
    26    * Colors of the foreground, background, foreground text, and background text, respectively
       
    27    * @var int
       
    28    * @var int
       
    29    * @var int
       
    30    * @var int
       
    31    */
       
    32   
       
    33   private $color_bar, $color_empty, $color_text, $color_emptytext;
       
    34   
       
    35   /**
       
    36    * Text to the left of the bar.
       
    37    * @var string
       
    38    */
       
    39   
       
    40   private $bar_left;
       
    41   
       
    42   /**
       
    43    * Text to the right of the bar.
       
    44    * @var string
       
    45    */
       
    46   
       
    47   private $bar_right;
       
    48   
       
    49   /**
       
    50    * Text in the middle of the bar.
       
    51    * @var string
       
    52    */
       
    53   
       
    54   private $bar_text;
       
    55   
       
    56   /**
       
    57    * The current location of the bar in %.
       
    58    * @var int
       
    59    */
       
    60   
       
    61   private $bar_pos = 0;
       
    62   
       
    63   /**
       
    64    * Position where the text should start.
       
    65    * @var int
       
    66    */
       
    67   
       
    68   private $text_pos = 0;
       
    69   
       
    70   /**
       
    71    * Width of the current terminal.
       
    72    * @var int
       
    73    */
       
    74   
       
    75   private $term_width = 80;
       
    76   
       
    77   /**
       
    78    * Width of the actual bar.
       
    79    * @var int
       
    80    */
       
    81   
       
    82   private $bar_width = 0;
       
    83   
       
    84   /**
       
    85    * State of the bar's color. Used to avoid echoing tons of color codes.
       
    86    * @var int
       
    87    */
       
    88   
       
    89   private $color_state = 0;
       
    90   
       
    91   /**
       
    92    * Color state constants
       
    93    * @const int
       
    94    * @const int
       
    95    * @const int
       
    96    * @const int
       
    97    * @const int
       
    98    */
       
    99   
       
   100   const COLOR_STATE_RESET = 0;
       
   101   const COLOR_STATE_FULL_HIDE = 1;
       
   102   const COLOR_STATE_FULL_SHOW = 2;
       
   103   const COLOR_STATE_EMPTY_HIDE = 3;
       
   104   const COLOR_STATE_EMPTY_SHOW = 4;
       
   105   
       
   106   /**
       
   107    * Constructor. All parameters are optional. Color choices are defined in color_to_code.
       
   108    * @param string $bar_left
       
   109    * @param string $bar_right
       
   110    * @param string $bar_text
       
   111    * @param string $color_bar
       
   112    * @param string $color_empty
       
   113    * @param string $color_text
       
   114    * @param string $color_emptytext
       
   115    */
       
   116   
       
   117   public function __construct($bar_left = '[', $bar_right = ']', $bar_text = '', $color_bar = 'red', $color_empty = 'black', $color_text = 'white', $color_emptytext = 'cyan')
       
   118   {
       
   119     $this->bar_left = $bar_left;
       
   120     $this->bar_right = $bar_right;
       
   121     $this->color_bar = $this->color_to_code($color_bar);
       
   122     $this->color_empty = $this->color_to_code($color_empty);
       
   123     $this->color_text = $this->color_to_code($color_text);
       
   124     $this->color_emptytext = $this->color_to_code($color_emptytext);
       
   125     
       
   126     if ( isset($_SERVER['COLUMNS']) )
       
   127     {
       
   128       $this->term_width = intval($_SERVER['COLUMNS']);
       
   129     }
       
   130     $this->bar_width = $this->term_width - strlen($this->bar_left) - strlen($this->bar_right);
       
   131     
       
   132     $this->update_text_quiet($bar_text);
       
   133   }
       
   134   
       
   135   /**
       
   136    * Updates the text on the progress bar and recalculates the position without redrawing.
       
   137    * @param string Text in the bar. If omitted, blanked.
       
   138    */
       
   139   
       
   140   public function update_text_quiet($bar_text = '')
       
   141   {
       
   142     $this->bar_text = strval($bar_text);
       
   143     
       
   144     if ( !empty($this->bar_text) )
       
   145     {
       
   146       $this->text_pos = round(( $this->bar_width / 2 ) - ( strlen($this->bar_text) / 2 ));
       
   147     }
       
   148   }
       
   149   
       
   150   /**
       
   151    * Updates the text on the progress bar, recalculates the position, and redraws.
       
   152    * @param string Text in the bar. If omitted, blanked.
       
   153    */
       
   154   
       
   155   function update_text($bar_text = '')
       
   156   {
       
   157     $this->update_text_quiet($bar_text);
       
   158     $this->set($this->bar_pos);
       
   159   }
       
   160   
       
   161   /**
       
   162    * Starts output of the bar.
       
   163    */
       
   164   
       
   165   function start()
       
   166   {
       
   167     echo self::CARRIAGE_RETURN;
       
   168     echo $this->bar_left;
       
   169   }
       
   170   
       
   171   /**
       
   172    * Closes the bar.
       
   173    */
       
   174   
       
   175   function end()
       
   176   {
       
   177     $this->set($this->bar_pos, $this->bar_width);
       
   178     echo "\n";
       
   179   }
       
   180   
       
   181   /**
       
   182    * Sets the position of the bar.
       
   183    * @param int Position in %. If a second parameter is set, this is treated as a numerator with the second parameter being the denominator and that is used to calculate position.
       
   184    * @param int Optional. Total number of units to allow fraction usage instead of percentage.
       
   185    */
       
   186   
       
   187   function set($pos, $max = 100)
       
   188   {
       
   189     // if our pos is higher than 100%, reduce it
       
   190     if ( $pos > $max )
       
   191       $pos = $max;
       
   192     
       
   193     // arithmetic one-liner
       
   194     // this is where we should stop showing the "full" color and instead use "empty"
       
   195     $bar_pos = round($this->bar_width * ( $pos / $max ));
       
   196     $this->bar_pos = 100 * ( $pos / $max );
       
   197     
       
   198     // reset the cursor
       
   199     echo self::CARRIAGE_RETURN . $this->bar_left;
       
   200     
       
   201     // print everything out
       
   202     for ( $i = 0; $i < $this->bar_width; $i++ )
       
   203     {
       
   204       $char = ' ';
       
   205       $hide = true;
       
   206       if ( !empty($this->bar_text) )
       
   207       {
       
   208         // we have some text to display in the middle; see where we are.
       
   209         $show_text = ( $i >= $this->text_pos && $i < ( $this->text_pos + strlen($this->bar_text) ) );
       
   210         if ( $show_text )
       
   211         {
       
   212           $char = substr($this->bar_text, $i - $this->text_pos, 1);
       
   213           if ( strlen($char) < 1 )
       
   214             $char = ' ';
       
   215           else
       
   216             $hide = false;
       
   217         }
       
   218       }
       
   219       // determine color
       
   220       if ( $i > $bar_pos )
       
   221       {
       
   222         $hide ? $this->set_color_empty_hide() : $this->set_color_empty_show();
       
   223       }
       
   224       else
       
   225       {
       
   226         $hide ? $this->set_color_full_hide() : $this->set_color_full_show();
       
   227       }
       
   228       echo $char;
       
   229     }
       
   230     $this->set_color_reset();
       
   231     echo $this->bar_right;
       
   232   }
       
   233   
       
   234   #
       
   235   # PRIVATE METHODS
       
   236   #
       
   237   
       
   238   function set_color_full_hide()
       
   239   {
       
   240     if ( $this->color_state == self::COLOR_STATE_FULL_HIDE )
       
   241       return;
       
   242     $this->color_state = self::COLOR_STATE_FULL_HIDE;
       
   243     
       
   244     $fgcolor = 30 + $this->color_bar;
       
   245     $bgcolor = $fgcolor + 10;
       
   246     echo self::SHELL_ESCAPE . "[0;{$fgcolor};{$bgcolor};8m";
       
   247   }
       
   248   
       
   249   function set_color_full_show()
       
   250   {
       
   251     if ( $this->color_state == self::COLOR_STATE_FULL_SHOW )
       
   252       return;
       
   253     $this->color_state = self::COLOR_STATE_FULL_SHOW;
       
   254     
       
   255     $fgcolor = 30 + $this->color_text;
       
   256     $bgcolor = 40 + $this->color_bar;
       
   257     echo self::SHELL_ESCAPE . "[0;1;{$fgcolor};{$bgcolor}m";
       
   258   }
       
   259   
       
   260   function set_color_empty_hide()
       
   261   {
       
   262     if ( $this->color_state == self::COLOR_STATE_EMPTY_HIDE )
       
   263       return;
       
   264     $this->color_state = self::COLOR_STATE_EMPTY_HIDE;
       
   265     
       
   266     $fgcolor = 30 + $this->color_empty;
       
   267     $bgcolor = $fgcolor + 10;
       
   268     echo self::SHELL_ESCAPE . "[0;{$fgcolor};{$bgcolor};8m";
       
   269   }
       
   270   
       
   271   function set_color_empty_show()
       
   272   {
       
   273     if ( $this->color_state == self::COLOR_STATE_EMPTY_SHOW )
       
   274       return;
       
   275     $this->color_state = self::COLOR_STATE_EMPTY_SHOW;
       
   276     
       
   277     $fgcolor = 30 + $this->color_emptytext;
       
   278     $bgcolor = 40 + $this->color_empty;
       
   279     echo self::SHELL_ESCAPE . "[0;1;{$fgcolor};{$bgcolor}m";
       
   280   }
       
   281   
       
   282   function set_color_reset()
       
   283   {
       
   284     if ( $this->color_state == self::COLOR_STATE_RESET )
       
   285       return;
       
   286     $this->color_state = self::COLOR_STATE_RESET;
       
   287     
       
   288     echo self::SHELL_ESCAPE . "[0m";
       
   289   }
       
   290   
       
   291   /**
       
   292    * Converts a color name to an ASCII color code. Valid color names are black, red, green, yellow, blue, magenta, cyan, and white.
       
   293    * @param string Color name
       
   294    * @return int
       
   295    */
       
   296   
       
   297   private function color_to_code($color)
       
   298   {
       
   299     static $colors = array(
       
   300       'black' => 0,
       
   301       'red' => 1,
       
   302       'green' => 2,
       
   303       'yellow' => 3,
       
   304       'blue' => 4,
       
   305       'magenta' => 5,
       
   306       'cyan' => 6,
       
   307       'white' => 7
       
   308     );
       
   309     return ( isset($colors[$color]) ) ? $colors[$color] : $colors['white'];
       
   310   }
       
   311 }