<?php
/******************************************************************************
* File : $RCSfile: class.container.php,v $
* Project : pdfDOM
* Description : Container object
* Author : Timo A. Hummel <hide@address.com>
* Created : 29.01.2003
* Modified : $Date: 2005/06/23 13:36:22 $
*
* This file is part of the pdfDOM project.
*
* More information:
* http://www.pdfdom.org
* http://www.sf.net/projects/pdfdom
*
* © four for business AG, www.4fb.de
*
* $Id: class.container.php,v 1.3 2005/06/23 13:36:22 timo_h Exp $
******************************************************************************/
define("pdContainerPositioningAbsolute", 1);
define("pdContainerPositioningRelative", 2);
define("pdContainerBackgroundHollow", 100);
define("pdContainerBackgroundSolid", 101);
class pdContainer {
// Attributes
/**
* @access private
* @var string Container type
*/
var $_type;
/**
* @access private
* @var integer Stores the z-index (depth) of this container
*/
var $_z;
/**
* @access private
* @var integer Constant with the position mode (see below)
*/
var $_positioningMode;
/**
* @access private
* @var object Object to which this container should be relative
*/
var $_relativePositioningObject;
/**
* @access private
* @var array Border sizes for this container
*/
var $_border;
/**
* @access private
* @var array Border sizes for this container
*/
var $_bordercolor;
/**
* @access private
* @var array Margin sizes for this container
*/
var $_margin;
/**
* @access private
* @var array Padding sizes for this container
*/
var $_padding;
/**
* @access private
* @var array Array of objects containing all child containers
*/
var $_containers;
/**
* @access private
* @var array Objects which are known to clip the current object
*/
var $_clippingObjects;
/**
* @access private
* @var array Unique ID of this container
*/
var $_uuid;
/**
* @access public
* @var object Coordinate object
*/
var $coordinates;
/**
* @access private
* @var object Page object for which the rendering is being done
*/
var $_page;
/**
* @access private
* @var integer Background mode
*/
var $_background;
/**
* Constructor for the new container
* @param none
*/
function pdContainer ()
{
global $_pdfDom_nextZ;
/* Increase z-index */
$_pdfDom_nextZ++;
/* Pre-initialize arrays */
$this->_containers = array();
$this->_clippingObjects = array();
/* Create coordinate object */
$this->coordinates = new pdCoordinateObject;
/* Set margin, border and padding to zero */
$this->setMargin(0);
$this->setBorder(0);
$this->setPadding(0);
/* Define as standard container */
$this->_type = "standard";
/* Set z-index */
$this->setZ($_pdfDom_nextZ);
/* Set standard solid white background */
$this->setBackground(255,255,255);
$this->setBackgroundMode(pdContainerBackgroundSolid);
/* Create UUID */
$this->_createUUID();
}
/**
* Creates a new unique ID for the current container
* @param none
*/
function _createUUID ()
{
$this->_uuid = uniqid("",true)."-".uniqid("",true);
}
/**
* Sets the z-index of the current container
* @param integer z z-index
*/
function setZ($z)
{
$this->_z = $z;
} // end operation setZ
/**
* Places the current container above the given container
* @param object container container object
*/
function above($container)
{
if (method_exists($container, "getZ"))
{
$this->setZ($container->getZ()+1);
}
} // end operation above
/**
* Sets the background mode for the current container.
*
* Allowed modes:
* pdContainerBackgroundHollow: Don't fill the background
* pdContainerBackgroundSolid : Fills the background with the background color
*
* @param integer mode Background mode
*/
function setBackgroundMode ($mode)
{
$valid_modes = array( pdContainerBackgroundHollow,
pdContainerBackgroundSolid);
if (!in_array($mode, $valid_modes))
{
trigger_error("Invalid mode for setBackgroundMode passed");
return;
}
$this->_backgroundMode = $mode;
}
/**
* Places the current container below the given container
* @param object container Container object
*/
function below($container)
{
if (method_exists($container, "getZ"))
{
$this->setZ($container->getZ()-1);
}
} // end operation below
/**
* sets the container's coordinate mode to absolute positioning
* (e.g. relative to the page's top-left coordinate)
*
* @param none
*/
function setAbsolutePositioning()
{
$this->_positioningMode = pdContainerPositioningAbsolute;
} // end operation setAbsolutePositioning
/**
* Sets the container's coordinate mode to relative positioning.
* The point of origin is always the x/y coordinate of the passed container.
*
* If you need to place your container relative to something else than the
* x/y coordinate (e.g. to the X1 and Y1 coordinate), have a look at the method
* setRelative
*
* @param object container Container object to place this container relative to
*/
function setRelativeToContainer(&$container)
{
$this->_positioningMode = pdContainerPositioningRelative;
$this->_relativePositioningObject = &$container;
} // end operation setRelativeToContainer
/**
* sets the padding for all four sides
* @param integer padding Padding size in millimeters
*/
function setPadding($padding)
{
$this->setPaddingLeft($padding);
$this->setPaddingRight($padding);
$this->setPaddingTop($padding);
$this->setPaddingBottom($padding);
} // end operation setPadding
/**
* sets the border size for all four sides
* @param integer border Border size in millimeters
*/
function setBorder($border)
{
$this->setBorderLeft($border);
$this->setBorderRight($border);
$this->setBorderTop($border);
$this->setBorderBottom($border);
} // end operation setBorder
/**
* sets the border color for all four sides
* @param integer r Red amount (0-255)
* @param integer g Green amount (0-255)
* @param integer b Blue amount (0-255)
*/
function setBorderColor($r, $g, $b)
{
$this->setBorderColorLeft($r, $g, $b);
$this->setBorderColorRight($r, $g, $b);
$this->setBorderColorTop($r, $g, $b);
$this->setBorderColorBottom($r, $g, $b);
} // end operation setBorder
/**
* sets the border color for the left border
* @param integer r Red amount (0-255)
* @param integer g Green amount (0-255)
* @param integer b Blue amount (0-255)
*/
function setBorderColorLeft ($r, $g, $b)
{
$this->_bordercolor["left"] = array($r, $g, $b);
}
/**
* sets the border color for the right border
* @param integer r Red amount (0-255)
* @param integer g Green amount (0-255)
* @param integer b Blue amount (0-255)
*/
function setBorderColorRight ($r, $g, $b)
{
$this->_bordercolor["right"] = array($r, $g, $b);
}
/**
* sets the border color for the top border
* @param integer r Red amount (0-255)
* @param integer g Green amount (0-255)
* @param integer b Blue amount (0-255)
*/
function setBorderColorTop ($r, $g, $b)
{
$this->_bordercolor["top"] = array($r, $g, $b);
}
/**
* sets the border color for the bottom border
* @param integer r Red amount (0-255)
* @param integer g Green amount (0-255)
* @param integer b Blue amount (0-255)
*/
function setBorderColorBottom ($r, $g, $b)
{
$this->_bordercolor["bottom"] = array($r, $g, $b);
}
/**
* sets the margin for all four sides
* @param integer margin Margin size in millimeters
*/
function setMargin($margin)
{
$this->setMarginLeft($margin);
$this->setMarginRight($margin);
$this->setMarginTop($margin);
$this->setMarginBottom($margin);
} // end operation setMargin
/**
* sets the padding for the left side
* @param integer padding Padding in millimeters
*/
function setPaddingLeft($padding)
{
$this->_padding["left"] = $padding;
} // end operation setPaddingLeft
/**
* sets the padding for the right side
* @param integer padding Padding in millimeters
*/
function setPaddingRight($padding)
{
$this->_padding["right"] = $padding;
} // end operation setPaddingRight
/**
* sets the padding for the top side
* @param integer padding Padding in millimeters
*/
function setPaddingTop($padding)
{
$this->_padding["top"] = $padding;
} // end operation setPaddingTop
/**
* sets the padding for the bottom side
* @param integer padding Padding in millimeters
*/
function setPaddingBottom($padding)
{
$this->_padding["bottom"] = $padding;
} // end operation setPaddingBottom
/**
* sets the border size for the left side
* @param integer border Border size in millimeters
*/
function setBorderLeft($border)
{
$this->_border["left"] = $border;
} // end operation setBorderLeft
/**
* sets the border size for the right side
* @param integer border Border size in millimeters
*/
function setBorderRight($border)
{
$this->_border["right"] = $border;
} // end operation setBorderRight
/**
* sets the border size for the top side
* @param integer border Border size in millimeters
*/
function setBorderTop($border)
{
$this->_border["top"] = $border;
} // end operation setBorderTop
/**
* sets the border size for the bottom side
* @param integer border Border size in millimeters
*/
function setBorderBottom($border)
{
$this->_border["bottom"] = $border;
} // end operation setBorderBottom
/**
* sets the margin for the left side
* @param integer margin Margin size in millimeters
*/
function setMarginLeft($margin)
{
$this->_margin["left"] = $margin;
} // end operation setMarginLeft
/**
* sets the margin for the right side
* @param integer margin Margin size in millimeters
*/
function setMarginRight($margin)
{
$this->_margin["right"] = $margin;
} // end operation setMarginRight
/**
* sets the margin for the top side
* @param integer margin Margin size in millimeters
*/
function setMarginTop($margin)
{
$this->_margin["top"] = $margin;
} // end operation setMarginTop
/**
* sets the margin for the bottom side
* @param integer margin Margin size in millimeters
*/
function setMarginBottom($margin)
{
$this->_margin["bottom"] = $margin;
} // end operation setMarginBottom
/**
* returns the padding values for the current container
*
* @param none
* @return array Assoc array with the keys left, right, top and bottom
*/
function getPadding()
{
return($this->_padding);
} // end operation getPadding
/**
* returns the margin values for the current container
*
* @param none
* @return array Assoc array with the keys left, right, top and bottom
*/
function getMargin()
{
return($this->_margin);
} // end operation getMargin
/**
* returns the border size values for the current container
*
* @param none
* @return array Assoc array with the keys left, right, top and bottom
*/
function getBorder()
{
return($this->_border);
} // end operation getBorder
/**
* returns the z-index for the current container
*
* @param none
* @return integer z-index
*/
function getZ()
{
return($this->_z);
} // end operation getBorder
/**
* Sets the background color and automatically sets the background mode
* to solid.
*
* @param integer r Red amount (0-255)
* @param integer g Green amount (0-255)
* @param integer b Blue amount (0-255)
*
*/
function setBackground ($r, $g, $b)
{
$this->_background["r"] = $r;
$this->_background["g"] = $g;
$this->_background["b"] = $b;
$this->setBackgroundMode(pdContainerBackgroundSolid);
}
/**
* returns the outer rectangle for the current container.
* The outer rectangle includes border and margin sizes.
*
* @return array array with the x,y,x1 and y1 coordinates
*/
function getOuterRectangle ()
{
list($x, $y, $x1, $y1) = $this->coordinates->getXYX1Y1();
$x = $x - $this->_border["left"] - $this->_margin["left"];
$y = $y - $this->_border["top"] - $this->_margin["top"];
$x1 = $x1 + $this->_border["right"] + $this->_margin["right"];
$y1 = $y1 + $this->_border["bottom"] + $this->_margin["bottom"];
return array($x, $y, $x1, $y1);
}
/**
* returns the inner rectangle for the current container.
* The inner rectangle includes padding sizes.
*
* @return array array with the x,y,x1 and y1 coordinates
*/
function getInnerRectangle ()
{
list($x, $y, $x1, $y1) = $this->coordinates->getXYX1Y1();
$x = $x + $this->_padding["left"];
$y = $y + $this->_padding["top"];
$x1 = $x1 - $this->_padding["right"];
$y1 = $y1 - $this->_padding["bottom"];
return array($x, $y, $x1, $y1);
}
/**
* sets all objects which are clipping the current object
*
* @param mixed objects Either pass a single object or an array of objects
*/
function setClippingObjects(&$objects)
{
if (is_array($objects))
{
foreach ($objects as $key => $object)
{
if (!array_key_exists($object->getUUID(), $this->_clippingObjects))
{
$this->_clippingObjects[$object->getUUID()] = &$objects[$key];
}
}
} else {
if (is_object($objects))
{
if (!array_key_exists($objects->getUUID(), $this->_clippingObjects))
{
$this->_clippingObjects[$objects->getUUID()] = &$objects;
}
}
}
} // end operation setClippingObjects
/**
* returns the UUID of the current container
*
* @param none
*/
function getUUID ()
{
return ($this->_uuid);
}
/**
* Returns an array of areas which are safe to draw in (e.g. to
* respect clipping of other containers).
*
* This function is only useful to developers who wish to develop
* new container types.
*
* @param integer x
* @param integer y
* @param integer x1
* @param integer y1
*/
function getSafeRects($x, $y, $x1, $y1)
{
$clips = array();
foreach ($this->_clippingObjects as $myobj)
{
$clips[] = $myobj->getOuterRectangle();
}
list($tx, $ty, $tx1, $ty1) = $this->getInnerRectangle();
$src = array(array($x, $y, $x1, $y1));
$res = $this->cutRectangles($src, $clips);
return $res;
} // end operation getSafeRects
/**
* checks if the given container clips with the current
* container.
*
* Warning: This method is not ready for use.
* @todo Not finished
*/
function isClipping ($object, $x, $y, $x1, $y1)
{
$coords = $object->coordinates;
$vx = $coords->getX();
$vy = $coords->getY();
$vx1 = $coords->getX1();
$vy1 = $coords->getY1();
}
/**
*
*/
function cutRectangles ($source, $cutby)
{
foreach ($cutby as $k2 => $cutrectangle)
{
list($cx, $cy, $cx1, $cy1) = $cutrectangle;
$dest = array();
foreach ($source as $key => $rectangle)
{
list($x, $y, $x1, $y1) = $rectangle;
$add = false;
if ($this->isOverlapping($rectangle, $cutrectangle))
{
if ($cx >= $x)
{
$rect1 = array($x, $y, $cx, $y1);
$dest[] = $rect1;
$add = true;
}
if ($cx1 <= $x1)
{
$rect2 = array($cx1, $y, $x1, $y1);
$dest[] = $rect2;
$add = true;
}
} else {
// not overlapping
}
if ($add == false)
{
$dest[] = $rectangle;
}
}
$source = $dest;
}
return $source;
}
/**
* checks if destination is completely within source
*
* @param array source Array with the source x, y, x1 and y1 coordinates
* @param array dest Array with the destination x, y, x1 and y1 coordinates
*/
function isInside ($source, $dest)
{
list($sx, $sy, $sx1, $sy1) = $source;
list($dx, $dy, $dx1, $dy1) = $dest;
if ($sx >= $dx && $sx < $dx1 && $sy > $dy && $sy < $dy1)
{
return true;
}
}
/**
* checks if dest is overlapping source
*
* @param array source Array with the source x, y, x1 and y1 coordinates
* @param array dest Array with the destination x, y, x1 and y1 coordinates
*/
function isOverlapping ($source, $dest)
{
list($sx, $sy, $sx1, $sy1) = $source;
list($dx, $dy, $dx1, $dy1) = $dest;
$horizontal = false;
$vertical = false;
if ($this->isInside($source, $dest))
{
return true;
}
if ($this->isInside($dest, $source))
{
return true;
}
/* Check if the top is inside the object */
if ($dy > $sy && $dy < $sy1 && ($dx <= $sx1 && $dx1 >= $sx))
{
return true;
}
if ($sy > $dy && $sy < $dy1 && ($sx <= $dx1 && $sx1 >= $dx))
{
return true;
}
/* Check if the bottom is inside the object */
if ($dy1 < $sy1 && $dy1> $sy && ($dx <= $sx1 && $dx1 >= $sx))
{
return true;
}
if ($sy1 > $dy1 && $sy1 < $dy && ($sx <= $dx1 && $sx1 >= $dx))
{
return true;
}
/* Check if the left is inside the object */
if ($dx > $sx && $dx < $sx1 && ($dy <= $sy1 && $dy1 >= $sy))
{
return true;
}
if ($sx > $dx && $sx < $dx1 && ($sy <= $dy1 && $sy1 >= $dy))
{
return true;
}
/* Check if the right is inside the object */
if ($dx1 < $sx1 && $dx1> $sx && ($dy <= $sy1 && $dy1 >= $sy))
{
return true;
}
if ($sx1 > $dx1 && $sx1 < $dx && ($sy <= $dy1 && $sy1 >= $dy))
{
return true;
}
return false;
}
/**
* returns all containers which need to be rendered
*
* This function is only useful to developers who wish to develop
* new container types.
*/
function getRenderList (&$root)
{
$this->renderlist = array();
foreach ($this->_containers as $key => $container)
{
$z = $container->getZ();
$root->renderlist[$z][] = &$this->_containers[$key];
$this->_containers[$key]->getRenderList(&$root);
}
}
/**
* returns an unsorted render list of all containers which need to be rendered
*
* This function is only useful to developers who wish to develop
* new container types.
*/
function unsortedRenderList (&$root)
{
$this->unsortedRenderList = array();
foreach ($this->_containers as $key => $container)
{
$root->unsortedRenderList[] = &$this->_containers[$key];
$this->_containers[$key]->unsortedRenderList(&$root);
}
}
/**
* Sets the page object to operate on
*
* @param object page Page object
*/
function setPage ($page)
{
/* Set the handle to the current page */
$this->_page = $page;
}
/**
* Sets the current container relative to another container.
*
* This is a very powerful function, so make sure you read the
* following carefully:
*
* src defines the php fragment which is used to calculate
* the source coordinate.
*
* dst defines the function to set the new coordinate.
*
* Example:
*
* setRelative($myobject, "getY()+10", "moveY");
*
* The statement above defines that when the current container
* is being rendered, it should move its Y-coordinate (defined
* trough moveY) based on $myobject->coordinates->getY() plus 10
* millimeters.
*
*/
function setRelative (&$object, $src, $dst)
{
$this->_relativeTo[] = array(&$object, $src, $dst);
}
/**
* Adds subcontainers to the current container
*/
function addContainer(&$container)
{
$this->_containers[$container->_uuid] = &$container;
} // end operation getSafeRects
function customRender()
{
}
function preRender ()
{
$this->unsortedRenderList(&$this);
foreach ($this->unsortedRenderList as $key => $value)
{
$this->unsortedRenderList[$key]->setPage($this);
$newpages = $this->unsortedRenderList[$key]->preRender(false);
}
}
function sizeCalc ()
{
if ($this->_positioningMode == pdContainerPositioningRelative)
{
$this->coordinates->moveX(
$this->_relativePositioningObject->coordinates->getX() +
$this->coordinates->getX());
$this->coordinates->moveY(
$this->_relativePositioningObject->coordinates->getY() +
$this->coordinates->getY());
}
if (is_array($this->_relativeTo))
{
foreach ($this->_relativeTo as $key => $item)
{
$obj = $this->_relativeTo[$key][0];
$src = $item[1];
$dst = $item[2];
$constr = '$val = $obj->coordinates->'.$src.';';
$constr .= '$this->coordinates->'.$dst.'($val);';
eval($constr);
}
}
$this->unsortedRenderList(&$this);
foreach ($this->unsortedRenderList as $key => $value)
{
$newpages = $this->unsortedRenderList[$key]->sizeCalc();
}
}
/**
* Does ...
*/
function render($root = true)
{
global $_pdfDom_PDF;
if ($this->hidden == true)
{
return;
}
/* Let's render */
$this->renderBackground();
$this->renderBorder();
$this->customRender();
if ($root == true)
{
$this->getRenderList(&$this);
ksort($this->renderlist);
foreach ($this->renderlist as $id => $level)
{
/* Then the actual drawing */
foreach ($level as $id2 => $object)
{
$this->renderlist[$id][$id2]->setPage($this);
$this->renderlist[$id][$id2]->render(false);
}
}
}
} // end operation render
function renderBorder ()
{
global $_pdfDom_PDF;
$border = $this->getBorder();
/* Draw left border */
if ($border["left"] > 0)
{
list($r, $g, $b) = $this->_bordercolor["left"];
$_pdfDom_PDF->setDrawColor($r, $g, $b);
$_pdfDom_PDF->setLineWidth($border["left"]);
$_pdfDom_PDF->line($this->coordinates->getX()-($border["left"]/2), $this->coordinates->getY()+($border["left"] / 2) - $border["top"], $this->coordinates->getX()-($border["left"]/2), $this->coordinates->getY1()-($border["left"]/2)+$border["bottom"]);
}
/* Draw right border */
if ($border["right"] > 0)
{
list($r, $g, $b) = $this->_bordercolor["right"];
$_pdfDom_PDF->setDrawColor($r, $g, $b);
$_pdfDom_PDF->setLineWidth($border["right"]);
$_pdfDom_PDF->line($this->coordinates->getX1()+($border["right"]/2), $this->coordinates->getY()+($border["right"]/2)-$border["top"], $this->coordinates->getX1()+($border["right"]/2), $this->coordinates->getY1()-($border["right"]/2)+$border["bottom"]);
}
/* Draw top border */
if ($border["top"] > 0)
{
list($r, $g, $b) = $this->_bordercolor["top"];
$_pdfDom_PDF->setDrawColor($r, $g, $b);
$_pdfDom_PDF->setLineWidth($border["top"]);
$_pdfDom_PDF->line($this->coordinates->getX()+($border["top"]/2)-($border["left"]), $this->coordinates->getY()-($border["top"]/2), $this->coordinates->getX1()-($border["top"]/2)+$border["right"], $this->coordinates->getY()-($border["top"]/2));
}
/* Draw bottom border */
if ($border["bottom"] > 0)
{
list($r, $g, $b) = $this->_bordercolor["bottom"];
$_pdfDom_PDF->setDrawColor($r, $g, $b);
$_pdfDom_PDF->setLineWidth($border["bottom"]);
$_pdfDom_PDF->line($this->coordinates->getX()+($border["bottom"]/2) - $border["left"], $this->coordinates->getY1()+($border["bottom"]/2), $this->coordinates->getX1()-($border["bottom"]/2) + $border["right"], $this->coordinates->getY1()+($border["bottom"]/2));
}
}
function renderBackground ()
{
global $_pdfDom_PDF;
if ($this->_backgroundMode == pdContainerBackgroundSolid)
{
list($x, $y, $x1, $y1) = $this->coordinates->getXYWH();
$_pdfDom_PDF->setFillColor($this->_background["r"],$this->_background["g"],$this->_background["b"]);
$_pdfDom_PDF->rect($x, $y, $x1, $y1, "F");
}
}
} // end class pdContainer
?>