public function render($ge)
 {
     //BpRectangle::render($ge);
     $sx = $ge->tx($this->sx());
     $sy = $ge->ty($this->sy());
     $ex = $ge->tx($this->ex());
     $ey = $ge->ty($this->ey());
     $width = $ex - $sx - $this->margin * 2;
     $height = $ey - $sy - $this->margin * 2;
     $lines = array();
     $cur_words = array();
     $cur_width = 0;
     $cur_line = '';
     if ($this->font_size) {
         $font_size = $this->font_size;
         $line_height = BpFontMetrics::getLineHeightFromFontSize($this->font, $this->string, $this->font_size);
     } else {
         $font_size = BpFontMetrics::getFontSizeFromLineHeight($this->font, $this->string, $this->line_height);
         $line_height = $this->line_height;
     }
     $words = explode(' ', $this->string);
     foreach ($words as $word) {
         $my_words = $cur_words;
         $my_words[] = $word;
         $cur_width = BpFontMetrics::getWidth($this->font, implode(' ', $my_words), $font_size);
         if ($cur_width <= $width) {
             $cur_words[] = $word;
         } else {
             $lines[] = implode(' ', $cur_words);
             $cur_words = array($word);
         }
     }
     $lines[] = implode(' ', $cur_words);
     $cur_pos = $sy + $this->margin;
     switch ($this->alignment) {
         case BpTextBox::CENTRE:
             $constraint = $sx + ($ex - $sx) / 2;
             break;
         case BpTextBox::LEFT:
             $constraint = $sx;
             break;
         case BpTextBox::RIGHT:
             throw new Exception('unimplemented BpTextBox::RIGHT in BpTextBox::render()');
             break;
         default:
             throw new Exception('Invalid alignment: ' . $this->alignment);
             break;
     }
     $rounded = $line_height;
     //ceil($line_height);
     $texts = array();
     foreach ($lines as $line) {
         $metrics = new BpFontMetrics($this->font, $line, 0);
         switch ($this->alignment) {
             case BpTextBox::CENTRE:
                 $metrics->constrainXCentre($constraint);
                 break;
             case BpTextBox::LEFT:
                 $metrics->constrainLeft($constraint);
                 break;
             case BpTextBox::RIGHT:
                 throw new Exception('unimplemented BpTextBox::RIGHT in BpTextBox::render()');
                 break;
             default:
                 throw new Exception('Invalid alignment: ' . $this->alignment);
                 break;
         }
         $metrics->constrainTop($cur_pos);
         $metrics->constrainBottom($cur_pos + $line_height);
         $metrics->maxFontSize($font_size);
         $cur_text = new BpText($this->z, $this->text_colour, $metrics);
         $texts[] = $cur_text;
         $cur_pos += $rounded;
     }
     if ($cur_pos > $this->ey) {
         $this->ey = $cur_pos + $this->margin;
     }
     BpRectangle::render($ge);
     foreach ($texts as $cur_text) {
         $cur_text->render($ge);
     }
 }
 protected function origin()
 {
     $metrics = new BpFontMetrics('Activa', '0', 0);
     $metrics->constrainTop($this->height() - $this->horizMargin() + $this->vertMargin() / 4);
     $metrics->constrainBottom($this->height() - $this->horizMargin() + $this->vertMargin() / 2);
     $metrics->constrainXCentre($this->horizMargin() / 3 * 2);
     $ret = new BpText(0, 'black', $metrics);
     return $ret;
 }