Location: PHPKode > projects > Lithron > lithron-1.0.2/lithron/workers/WorkerBlock.php
<?php

class WorkerBlock extends WorkerPlugin
{
	const BWR_OK = 0;
	const BWR_FULL = 1;
	const BWR_COLUMNBREAK = 2;
	
	public function getPrefWidth()
	{
		$akku = array();
		$lb = null;
		$sub = $this->firstChildWorker;
		while($sub)
		{
			if ($sub->isInline())
			{
				Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getPrefWidth() - processing inline child ".$sub->DOMNode->nodeName."</span>", "Layout", $this->Level+1);
				$saveid = $sub->save();
				do
				{
					if ($lb === null) $lb = new LineBox(Lithron::INFINITY);
					$ret = $sub->flowInto($lb);	
					if ($ret == LineBox::FLOW_NEWLINE || $ret == LineBox::FLOW_COLUMNBREAK || $ret == LineBox::FLOW_FULL)
					{
						$akku[] = $lb->getWidth();
						$lb = null;						
					}
				}
				while ($ret != LineBox::FLOW_DONE);
				$sub->restore($saveid);
			}
			elseif (!$sub->isPositioned() && !$sub->isMarker())
			{
				Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getPrefWidth() - processing static child ".$sub->DOMNode->nodeName."</span>", "Layout", $this->Level+1);
				if ($lb !== null)
				{
					$akku[] = $lb->getWidth();
					$lb = null;						
				}

				if ($sub->typeOfWidth("<percentage>"))
					$cw = Lithron::INFINITY;
				else 
					$cw = $sub->propWidth();
				if ($cw == "auto") $cw = $sub->getPrefWidth();
				$mw = $sub->propMaxWidth();
				if ($mw == "none") $mw = Lithron::INFINITY;
				$cw = max($sub->propMinWidth(), min($cw, $mw));	
				$akku[] = $sub->calcMBPHoriz() + $cw;			
			}
			$sub = $sub->nextSiblingWorker;
		}
		if ($lb !== null)
		{
			$akku[] = $lb->getWidth();
			$lb = null;						
		}
		$res = count($akku) == 0 ? 0 : max($akku);
		Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getPrefWidth() = $res</span>", "Layout", $this->Level);
		return $res;
	}
	
	public function getWidth($containerwidth = null)
	{
		$cw = $this->propWidth();
		if ($cw == "auto") $cw = $this->getPrefWidth(); 
		elseif ($this->typeOfWidth("<percentage>"))
		{
			if ($containerwidth !== null)
			{
				$match = $this->matchOfWidth("<percentage>");
				$cw = 0.01 * $match[0] * $containerwidth; 
			}
			else
				$cw = $this->getPrefWidth();
		}
		$mw = $this->propMaxWidth(); 
		if ($mw == "none") $mw = Lithron::INFINITY;
		$cw = max($this->propMinWidth(), min($cw, $mw));
		Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getWidth($containerwidth) = $cw</span>", "Layout", $this->Level);
		return $cw;				
	}

	public function getPrefHeight($width)
	{
		$akku = 0;
		$lb = null;
		$sub = $this->firstChildWorker;
		while($sub)
		{
			if ($sub->isInline())
			{
				Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getPrefHeight() - processing inline child ".$sub->DOMNode->nodeName."</span>", "Layout", $this->Level+1);
				$saveid = $sub->save();
				do
				{
					if ($lb === null) $lb = new LineBox($width);
					$ret = $sub->flowInto($lb);	
					if ($ret == LineBox::FLOW_NEWLINE || $ret == LineBox::FLOW_FULL)
					{
						$akku += $lb->getHeight();
						$lb = null;						
					}
				}
				while ($ret != LineBox::FLOW_DONE);
				$sub->restore($saveid);
			}
			elseif (!$sub->isPositioned() && !$sub->isMarker())
			{
				Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getPrefHeight() - processing static child ".$sub->DOMNode->nodeName."</span>", "Layout", $this->Level+1);
				if ($lb !== null)
				{
					$akku += $lb->getHeight();
					$lb = null;						
				}
				$ch = $sub->propHeight(); 
				if ($ch == "auto") $ch = $sub->getPrefHeight($width - $sub->calcMBPHoriz()); 
				$mh = $sub->propMaxHeight();
				if ($mh == "none") $mh = Lithron::INFINITY;
				$ch = max($sub->propMinHeight(), min($ch, $mh));	
				$akku += $sub->calcMBPVert() + $ch;
			}			
			$sub = $sub->nextSiblingWorker;
		}
		if ($lb !== null)
		{
			$akku += $lb->getHeight();
			$lb = null;						
		}
		Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getPrefHeight($width) = $akku</span>", "Layout", $this->Level);
		return $akku;
	}

	public function getHeight($width)
	{
		$ch = $this->propHeight();
		if ($ch == "auto") $ch = $this->getPrefHeight($width); 
		$mh = $this->propMaxHeight(); 
		if ($mh == "none") $mh = Lithron::INFINITY;
		$ch = max($this->propMinHeight(), min($ch, $mh));
		Lithron::trace("<span style=\"color:blue;\">".$this->DOMNode->nodeName.".getHeight($width) = $ch</span>", "Layout", $this->Level);
		return $ch;				
	}
	
	
	protected function getFirstWorker()
	{
		return $this->firstChildWorker;
	}

	protected function getNextWorker($cur_worker)
	{
		return $cur_worker->nextSiblingWorker;
	}


	protected function workSetup(&$trace, &$wellpath, &$sub, &$tracemode)
	{
		if (count($trace))
		{
			$sub = array_shift($trace);
			$tracemode = true;
		}
		else
		{
			$sub = $this->getFirstWorker();
			$tracemode = false;
		}
		
		if (is_array($wellpath))
			$wellpath[] = $this;
	}


	private function drawBackground($rop, $width, $height)
	{
		$bgcol = $this->propBackgroundColor();
		if ($bgcol != "transparent")
		{
			$rop->PRELI_setfillcolor($bgcol);
			$pl = $this->propPaddingLeft();
			$pt = $this->propPaddingTop();
			$rop->PRE_translate(-$pl, $pt);
			$rop->PRELI_rect($width + $this->calcPHoriz(), $height + $this->calcPVert());
			$rop->PRE_translate($pl, -$pt);
		}
	}

	private function drawBorders($rop, $width, $height)
	{
		// TODO
		$rop->PRE_save();

		$pl = $this->calcPLeft() + $this->calcBLeft()/2;
		$pt = $this->calcPTop() + $this->calcBTop()/2;
		$rop->PRE_translate(-$pl, $pt);

        if ($this->propBorderStrokeMode() == "single")
        {
            $map = array(
                "Top" => array(0,0),
                "Right" => array($width + $this->calcPHoriz()+$this->calcBHoriz()/2, 0),
                "Bottom" => array($width + $this->calcPHoriz()+$this->calcBHoriz()/2, -$height - $this->calcPVert() - $this->calcBVert()/2),
                "Left" => array(0, -$height - $this->calcPVert() - $this->calcBVert()/2)
            );
            foreach($map AS $side => $pos)
            {
                $fcolor = "propBorderStrokeColor";
                $color = $this->$fcolor();
                $fwidth = "propBorderStrokeWidth";
                $width = $this->$fwidth();

                if ($side == "Top") {
                    if ($color != "colorprop") $rop->PRELI_setstrokecolor($color);
                    $rop->PRE_setlinewidth($width);
                    if ($this->propBorderStrokePattern() !== "none") $rop->PRE_setdashpattern("dasharray={".$this->propBorderStrokePattern()."}");
                    $rop->PRE_setlinejoin($this->propBorderStrokeJoin());
                    $rop->PRE_setlinecap($this->propBorderStrokeCap());
                    $rop->PRE_moveto(0,0);
                }
                $rop->PRE_lineto($pos[0], $pos[1]);
                if ($side == "Left") $rop->PRE_closepath_stroke();
            }
        }
        else
        {
            // TODO
            Lithron::log("Can not draw borders", LOG_DEBUG, "WorkerBlock");
        }

        $rop->PRE_translate($pl, -$pt);

        $rop->PRE_restore();
	}

	private function workSubWorker($sub, $subrop, $child_w, $child_h, &$remain, $trace = array(), $wellpath = null)
	{
		$subrop->setDimensions($child_w, $child_h);
		$mx = $sub->calcMBPLeft();
		$my = $sub->calcMBPTop();
		$subrop->PRE_save();
		#echo "<br>";
        $complete_h = $child_h + $sub->calcMBPVert();
		if ($rot = $sub->propRotation())
		{
			$subrop->PRE_translate(0, -$complete_h);
			$subrop->PRE_rotate($rot);
			$rot_trans = 2*M_PI*$rot/360.0;
			$subrop->PRE_translate(sin($rot_trans), cos($rot_trans));
		}
		$subrop->PRE_translate($mx, -$my);
		$ret = $sub->work($subrop, $child_w, $child_h, $trace, $wellpath);
		$subrop->POST_restore();
		$subrop->POSTLI_positioned();
		$subrop->POST_translate(0, -$complete_h);
		$remain -= $child_h + $sub->calcMBPVert();
		return $ret;
	}
	
	private function workLineBox($rop, &$lb, &$remain)
	{
		if ($lb !== null)
		{
			$lbh = $lb->getHeight();
			if ($lbh == 0)
			{
				$lb = null;
				return self::BWR_OK;
			}
			if ($remain + Lithron::EPSILON < $lbh) 
			{
				$lb->revert();
				$lb = null;
				return self::BWR_FULL;
			}
			$subrop = new RenderOperation();
			$rop->addChild($subrop);
			$subrop->PRE_save();
			$lb->render($subrop);
			$subrop->POST_restore();
			$subrop->POST_translate(0, -$lb->getHeight());
			$remain -= $lbh;
			Lithron::trace("<span style=\"color:brown;\">".$this->DOMNode->nodeName.".work() - added linebox with height $lbh</span><br/>".$lb->dump(), "Layout", $this->Level+1);
			$lb = null;
		}
		return self::BWR_OK;
	}
	
	private function leaveTrace($wellpath, $sub)
	{
		if ($wellpath !== null)
		{
			$wp = $wellpath;
			$wp[] = $sub;
			$mywell = array_shift($wp);
			array_shift($wp);
			$mywell->setTracePath($wp);
			Lithron::trace("<span style=\"font-weight:bold;\">TRACEPATH TO ".$sub->DOMNode->nodeName." SET</span>", "Layout");
		}
	}
	

	public function work($rop, $width, $height, $trace = array(), $wellpath = null)
	{		
		Lithron::trace("<span style=\"color:brown;\">".$this->DOMNode->nodeName.".work() - Start</span>", "Layout", $this->Level);

		$this->workSetup($trace, $wellpath, $sub, $tracemode);
		$this->drawBackground($rop, $width, $height);
		$this->drawBorders($rop, $width, $height);
		
		$lb = null;
		$flow_remaining_h = $height;
		$res_work = self::BWR_OK;
		while ($sub)
		{
			if ($sub->isPositioned())
			{
				// absolute and fixed
				$subrop = new RenderOperation($sub);
				$subrop->setPosition($sub->propTop(), $sub->propRight(), $sub->propBottom(), $sub->propLeft());
				$this->findContainingRop()->addPositioned($subrop);
				$child_w = $sub->getWidth();
				$child_h = $sub->getHeight($child_w);
				Lithron::trace("<span style=\"color:brown;\">".$this->DOMNode->nodeName.".work() - processing positioned child ".$sub->DOMNode->nodeName." with size ($child_w/$child_h)</span>", "Layout", $this->Level+1);
				$this->workSubWorker($sub, $subrop, $child_w, $child_h, $dummy);
			}
			elseif ($sub->isInline())
			{

				Lithron::trace("<span style=\"color:brown;\">".$this->DOMNode->nodeName.".work() - processing inline child ".$sub->DOMNode->nodeName."</span>", "Layout", $this->Level+1);

				$this->leaveTrace($wellpath, $sub);

				if ($sub->isContainedInFixed())
					$saveid = $sub->save();
				do
				{
					if ($lb === null) $lb = new LineBox($width);
					$res_flow = $sub->flowInto($lb);	
					if ($res_flow == LineBox::FLOW_NEWLINE || $res_flow == LineBox::FLOW_FULL)
						$res_work = $this->workLineBox($rop, $lb, $flow_remaining_h);
				}
				while ($res_flow != LineBox::FLOW_DONE && $res_flow != LineBox::FLOW_COLUMNBREAK && $res_work == self::BWR_OK);
				if ($sub->isContainedInFixed())
					$sub->restore($saveid);

				if ($res_flow == LineBox::FLOW_COLUMNBREAK)
					$res_work = self::BWR_COLUMNBREAK;
			}
			else
			{
				$res_work = $this->workLineBox($rop, $lb, $flow_remaining_h);
				if ($res_work == self::BWR_OK)
				{
					if ($sub->isMarker())
					{
						// marker
						$subrop = new RenderOperation($sub);
						$rop->addPositioned($subrop);
						$child_w = $sub->getWidth();
						$pref_h = $sub->getHeight($child_w);
						$max_h = $flow_remaining_h - $sub->calcMBPVert();
						$child_h = min($max_h, $pref_h);
						Lithron::trace("<span style=\"color:brown;\">".$this->DOMNode->nodeName.".work() - processing marker child ".$sub->DOMNode->nodeName." with size ($child_w/$child_h)</span>", "Layout", $this->Level+1);
						$res_work = $this->workSubWorker($sub, $subrop, $child_w, $child_h, $dummy);
					}
					else
					{
						// static and relative
						$this->leaveTrace($wellpath, $sub);

						$child_w = min($sub->getWidth($width - $sub->calcMBPHoriz()), $width - $sub->calcMBPHoriz());
						$pref_h = $sub->getHeight($child_w);
						$max_h = $flow_remaining_h - $sub->calcMBPVert();
						if (($pref_h > $max_h) && $sub->propBreakable() == "no")
						{
							$res_work = self::BWR_FULL;							
						}
						else
						{
							$subrop = new RenderOperation($sub);
							$rop->addChild($subrop);
							$child_h = min($max_h, $pref_h);
							Lithron::trace("<span style=\"color:brown;\">".$this->DOMNode->nodeName.".work() - processing static child ".$sub->DOMNode->nodeName." with size ($child_w/$child_h) - ".($flow_remaining_h)." left</span>", "Layout", $this->Level+1);
							$res_work = $this->workSubWorker($sub, $subrop, $child_w, $child_h, $flow_remaining_h, $trace, $wellpath);
						}
					}					
				}
			}				
			
			$trace = array();
			$break_now = $res_work != self::BWR_OK; 
			$col = $break_now ? "red" : "green";
			Lithron::trace("<span style=\"color:$col;\">".$this->DOMNode->nodeName.".work() - finished processing child ".$sub->DOMNode->nodeName." - (".($height-$flow_remaining_h)."/$height) - ".($break_now?"CHILD WANTS BREAK":"CONTINUE")."</span>", "Layout", $this->Level+1);
			$sub = $break_now ? null : $this->getNextWorker($sub);
		}
		
		if ($res_work == self::BWR_OK)
		{
			$res_work = $this->workLineBox($rop, $lb, $flow_remaining_h);
		}
		elseif ($res_work == self::BWR_COLUMNBREAK)
		{
			$this->workLineBox($rop, $lb, $flow_remaining_h);
		}
		elseif ($lb !== null) 
		{
			$lb->revert();
			$res_work = self::BWR_FULL;
		}

		$break_now = $res_work != self::BWR_OK; 
		$col = $break_now ? "red" : "green";
		Lithron::trace("<span style=\"color:$col;\">".$this->DOMNode->nodeName.".work() - End</span>", "Layout", $this->Level);
		return $res_work;
	}
	


					/*
					if ($break_now && $wellpath !== null)
					{
						$wp = $wellpath;
						$wp[] = $sub;
						$mywell = array_shift($wp);
						array_shift($wp);
						$mywell->setTracePath($wp);
						Lithron::trace("<b style=\"color:red;\">TRACEPATH TO ".$sub->DOMNode->nodeName." SET</b>", "Layout", $this->Level);
					}
					if (!$break_now || $wellpath === null || $sub->propBreakable() == "yes")
					{
						$subrop = new RenderOperation($sub);
						$rop->addChild($subrop);
						$child_h = $break_now ? $max_h : $pref_h;
	
						$this->workSubWorker($sub, $subrop, $child_w, $child_h, $flow_remaining_h);
					}
					*/

					




	
}


?>
Return current item: Lithron