LayoutVertical.cc 7.82 KB
/*
 * LayoutVertical.hh
 *
 *  Created on: Sep, 2, 2014
 *      Author: AKKA
 */


#include "LayoutVertical.hh"
#include "PlotLogger.hh"
#include "DecoratorPlot.hh"
#include "PlPlotUtil.hh"

#include <boost/range/adaptor/reversed.hpp>

namespace plot {

/**
 * @Brief Add a panel characterized by it's constraint to the layout
 */

void LayoutVertical::addPanel (PanelConstraint panelConstraint, 
							   double preferedWidth/*=-1*/, double preferedHeight/*=-1*/, bool isHeightFixed /*=false*/, double fixedHeight /*0*/) {
	double width=0, height=0;

	switch (panelConstraint) {
	case PanelConstraint::MaxWidth:

		width = 1.0;
		if(isHeightFixed){
			height = fixedHeight;
			break;
		}
		if (preferedHeight != -1)
			height = preferedHeight;
		else
			height = _requestPanelHeight;

		break;

	case PanelConstraint::Square:

		if (preferedWidth != -1)
			width = preferedWidth;
		else
			width = _requestPanelHeight / _xyRatio;

		if (preferedHeight != -1)
			height = preferedHeight;
		else
			height = _requestPanelHeight;

		break;
	default:
		// TODO lever exception ici ???
		break;
	}

	_panelsInfo.push_back (new PanelInfo (panelConstraint, preferedWidth, preferedHeight, width, height, isHeightFixed));
}

/**
 * @Brief Reset Layout internal parameters and compute optimized parameters
 * like _panelHeight, _panelWidth, _panelYSpacing...
 */

void LayoutVertical::reset (void) {
	// Reset current panels and position
	_curPanel	= 0;
	_curYPosition = 0;
	_maxWidthConstraintFound = false;

	// Compute general data for the layout depending on
	// - the number of panel
	// - their constraint
	_panelYSpacing	= _requestPanelSpacing;

	double layoutWidth, layoutHeight;
	double fixedHeight;
	computeLayoutSize (layoutWidth, layoutHeight,fixedHeight);

	// Normalize width & height if more than 1
	if(layoutHeight > (1 - fixedHeight)){
		for (auto panelInfo : _panelsInfo) {
			if(!panelInfo->_isHeightFixed){
				if(fixedHeight > 0.){
					panelInfo->_preferedHeight /= (1/(layoutHeight-fixedHeight));
					panelInfo->_height /= (1/(layoutHeight-fixedHeight));
				}
				else{
					panelInfo->_preferedHeight /= layoutHeight;
					panelInfo->_height /= layoutHeight;
				}
			}
		}
		_panelYSpacing /= (layoutHeight+fixedHeight);
	}

	if (layoutWidth > 1) {
		for (auto panelInfo : _panelsInfo) {
			if (panelInfo->_constraint != PanelConstraint::MaxWidth) {
				panelInfo->_preferedWidth /= layoutWidth;
				panelInfo->_width /= layoutWidth;
			}
		}
	}

	// Expand _requestPanelHeight if necessary and asked
	if ((layoutHeight <(1-fixedHeight) ) && (layoutWidth <= 1) && (_autoExpand == true)) {
		expand (1.01);
		expand (1.001);
		expand (1.0001);
	}
}

/**
 * @Brief Increase panelHeight by step until layoutHeight reach (but not over step) 1.0
 */

void LayoutVertical::expand (double ratio) {
	double fixedHeight;
	double layoutWidth, layoutHeight;
	do
	{
		// Increase panelHeight by step and keep the same ratio for panelSpacing
		_panelYSpacing	*= ratio;

		for (auto panelInfo : _panelsInfo) {
			if(!panelInfo->_isHeightFixed)
				panelInfo->_height *= ratio;
			if (panelInfo->_constraint != PanelConstraint::MaxWidth) {
				if (panelInfo->_preferedWidth != -1) {
					panelInfo->_width = panelInfo->_preferedWidth;
				} else {
					panelInfo->_width *= ratio;
				}
			}
		}
		computeLayoutSize (layoutWidth, layoutHeight,fixedHeight);
	} while ((layoutHeight < 1.0-fixedHeight) && (layoutWidth <= 1.0));

	// Restore last valid value for panelHeight and panelSpacing
	_panelYSpacing	/= ratio;

	for (auto panelInfo : _panelsInfo) {
		if(!panelInfo->_isHeightFixed)
			panelInfo->_height /= ratio;
		if (panelInfo->_constraint != PanelConstraint::MaxWidth) {
			if (panelInfo->_preferedWidth == -1) {
				panelInfo->_width /= ratio;
			}
		}
	}
	computeLayoutSize (layoutWidth, layoutHeight,fixedHeight);
}

void LayoutVertical::computeLayoutSize (double &layoutWidth, double &layoutHeight, double &fixedHeight) {
	layoutWidth = 0;
	layoutHeight = 0;
	fixedHeight = 0;
	_firstPanelHeightDelta = 0;
	bool maxWidthConstraintFound = false;

	for (auto panelInfo : _panelsInfo) {
		if (panelInfo->_isHeightFixed)
			fixedHeight += (panelInfo->_height+ _panelYSpacing);
		else
			layoutHeight += (panelInfo->_height + _panelYSpacing);
		
		if (panelInfo->_width > layoutWidth)
			layoutWidth = panelInfo->_width;

		if ((maxWidthConstraintFound == false) &&
			(panelInfo->_constraint == PanelConstraint::MaxWidth)) {
			maxWidthConstraintFound = true;
			_firstPanelHeightDelta = (_firstPanelHeightFactor-1.0) * panelInfo->_height;
			layoutHeight += _firstPanelHeightDelta;
		}
	}

	// Remove one spacing if more than 1 panel
	if (_panelsInfo.size () > 1)
		layoutHeight -= _panelYSpacing;
}

Bounds & LayoutVertical::getNextBounds (PanelConstraint panelConstraint) {

	PanelInfo *panelInfo = _panelsInfo.at(_curPanel);

	// Computes panels position on the layout depending on their constraints
	switch (panelConstraint) {

	case PanelConstraint::MaxWidth:
		_computedPanelBounds._x = 0;
		_computedPanelBounds._y = _curYPosition;
		_computedPanelBounds._width = 1.0;
		_computedPanelBounds._height = panelInfo->_height;

		// The first MaxWidth panel can have an extra panel height
		if (_maxWidthConstraintFound == false) {
			_maxWidthConstraintFound = true;
			_computedPanelBounds._height	+= _firstPanelHeightDelta;
			_curYPosition 					+= _firstPanelHeightDelta;
		}

		_curPanel++;
		_curYPosition += (panelInfo->_height + _panelYSpacing);
		break;

	case PanelConstraint::Square:
		// Compute x position of the SquarePanel on the line (centered)
		_computedPanelBounds._x = 0.5 - (panelInfo->_width / 2.0);
		_computedPanelBounds._y = _curYPosition;

		_computedPanelBounds._width = panelInfo->_width;
		_computedPanelBounds._height = panelInfo->_height;

		_curPanel++;
		_curYPosition += (panelInfo->_height + _panelYSpacing);
		break;

	default:
		// TODO lever exception ici ???
		break;
	}

	return _computedPanelBounds;
}

void LayoutVertical::computePanelsPosition (std::vector<boost::shared_ptr<PanelPlotOutput>> _plots,  std::map<std::string, ParameterData> *parameterValues) {
	// Add panels constraint to the layout

	bool isFirstPlot = true;
	for (auto plot : boost::adaptors::reverse(_plots)) {
		if (!plot->isStandalone())
			continue;

		double height = 0;
		if(plot->isHeightFixed()){
			bool isLegendHeightAdded = false;
			for (auto parameter : plot->_parameterAxesList)
			{
				SeriesProperties lSeries;
				for (auto lSeries : parameter.getYSeriePropertiesList())
				{
					boost::shared_ptr<Axis> lAxis( plot->_panel->getAxis(lSeries.getXAxisId()));
					Font legendFont(lAxis->getLegendFont(plot->_panel.get()));
					PlPlotUtil::setPlFont(legendFont);
					CharSize legendSize = PlPlotUtil::getCharacterSizeInPlPage(plot->_panel->_page);
					unsigned int nbComponent = lSeries.getIndexList(parameterValues).size();
					if(plot->subTypeName()=="tickPlot"){
						if (!isLegendHeightAdded){
							if(isFirstPlot){
								height += 0.05;
							}
							height += (nbComponent + 2) * legendSize.second*1.4;
							isLegendHeightAdded = true;
						}
						else{
							height += 0.05+ (nbComponent + 1) * legendSize.second*1.4;
						}
					}
					else if(plot->subTypeName()=="statusPlot"){
						if(isFirstPlot){
							if(!isLegendHeightAdded){
								height +=  5.3*legendSize.second;
								isLegendHeightAdded = true;
							}	
						}
						else{
							height += 0.025;
						}
						height += nbComponent*0.025 + nbComponent*legendSize.second*2.4;
					}
					else{
						continue;
					}
				}
			}
			
		}
		
		this->addPanel ( plot->getLayoutConstraint(),
							plot->_panel->_preferedWidth,
							plot->_panel->_preferedHeight,
							plot->isHeightFixed(),
							height);
		if(isFirstPlot)
			isFirstPlot = false;
	}

	// Reset layout
	this->reset();


	for (auto plot : boost::adaptors::reverse(_plots)) {
		if (!plot->isStandalone())
			continue;

		plot->_panel->_bounds = this->getNextBounds (plot->getLayoutConstraint());
	}
}

}