ewol/ewol/widget/Sizer.cpp

298 lines
9.3 KiB
C++

/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#include <ewol/ewol.h>
#include <ewol/widget/Sizer.h>
#include <ewol/widget/Manager.h>
#undef __class__
#define __class__ "Sizer"
ewol::widget::Sizer::Sizer() :
propertyMode(*this, "mode", modeHori, "The display mode"),
propertyBorderSize(*this, "border", vec2(0,0), "The sizer border size"),
propertyAnimation(*this, "annimation", animationNone, "sizer annimation"),
propertyAnimationTime(*this, "annimation-time", 0, "time of the anniation") {
addObjectType("ewol::widget::Sizer");
propertyMode.add(modeHori, "hori");
propertyMode.add(modeVert, "vert");
propertyAnimation.add(animationNone, "none");
propertyAnimation.add(animationTop, "top");
propertyAnimation.add(animationbuttom, "buttom");
propertyAnimation.add(animationLeft, "left");
propertyAnimation.add(animationRight, "right");
}
void ewol::widget::Sizer::init(enum displayMode _mode) {
ewol::widget::ContainerN::init();
propertyMode.set(_mode);
}
ewol::widget::Sizer::~Sizer() {
//EWOL_DEBUG("[" << getId() << "]={" << getObjectType() << "} sizer : destroy (mode=" << (propertyMode == ewol::widget::Sizer::modeVert?"Vert":"Hori") << ")");
}
void ewol::widget::Sizer::onChangeSize() {
ewol::Widget::onChangeSize();
vec2 tmpBorderSize = propertyBorderSize->getPixel();
EWOL_VERBOSE("[" << getId() << "] update size : " << m_size << " nbElement : " << m_subWidget.size() << " borderSize=" << tmpBorderSize << " from border=" << propertyBorderSize);
vec2 localWidgetSize = m_size - tmpBorderSize*2.0f;
// -1- calculate min-size and expand requested:
vec2 minSize(0.0f, 0.0f);
ivec2 nbWidgetExpand(0,0);
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
vec2 tmpSize = it->getCalculateMinSize();
if (propertyMode == ewol::widget::Sizer::modeVert) {
minSize = vec2(std::max(minSize.x(), tmpSize.x()),
minSize.y() + tmpSize.y());
} else {
minSize = vec2(minSize.x() + tmpSize.x(),
std::max(minSize.y(), tmpSize.y()));
}
bvec2 expand = it->canExpand();
nbWidgetExpand += ivec2(expand.x()==true?1:0,
expand.y()==true?1:0);
}
// -2- Calculate the size to add at every elements...
float deltaExpandSize = 0.0f;
if (nbWidgetExpand != ivec2(0,0)) {
if (propertyMode == ewol::widget::Sizer::modeVert) {
deltaExpandSize = (localWidgetSize.y() - minSize.y()) / float(nbWidgetExpand.y());
} else {
deltaExpandSize = (localWidgetSize.x() - minSize.x()) / float(nbWidgetExpand.x());
}
if (deltaExpandSize<0.0) {
deltaExpandSize=0;
}
}
// -3- Configure all at the min size ...
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
it->setSize(it->getCalculateMinSize());
}
// -4- For each element we apply the minmax range and update if needed
while (deltaExpandSize > 0.0001f) {
float residualNext = 0.0f;
// get the number of element that need to devide...
int32_t countCalculation = nbWidgetExpand.x();
if (propertyMode == ewol::widget::Sizer::modeVert) {
countCalculation = nbWidgetExpand.y();
}
// -4.1- Update every subWidget size
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
vec2 tmpSizeMin = it->getSize();
vec2 tmpSizeMax = it->getCalculateMaxSize();
// Now update his size his size in X and the curent sizer size in Y:
if (propertyMode == ewol::widget::Sizer::modeVert) {
if (it->canExpand().y() == true) {
float sizeExpand = tmpSizeMin.y() + deltaExpandSize;
if (sizeExpand > tmpSizeMax.y()) {
residualNext += (sizeExpand - tmpSizeMax.y());
sizeExpand = tmpSizeMax.y();
countCalculation--;
}
tmpSizeMin.setY(sizeExpand);
}
it->setSize(tmpSizeMin);
} else {
if (it->canExpand().x() == true) {
float sizeExpand = tmpSizeMin.x() + deltaExpandSize;
if (sizeExpand > tmpSizeMax.x()) {
residualNext += (sizeExpand - tmpSizeMax.x());
sizeExpand = tmpSizeMax.x();
countCalculation--;
}
tmpSizeMin.setX(sizeExpand);
}
it->setSize(tmpSizeMin);
}
}
// Reset size add ...
deltaExpandSize = 0.0f;
if (residualNext < 0.0001f) {
break;
}
if (countCalculation <= 0) {
break;
}
if (propertyMode == ewol::widget::Sizer::modeVert) {
deltaExpandSize = residualNext / float(countCalculation);
} else {
deltaExpandSize = residualNext / float(countCalculation);
}
if (deltaExpandSize < 0.0f) {
deltaExpandSize = 0.0f;
break;
}
}
// -5- Update the expand in the second size if vert ==> X and if hori ==> Y
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
// Now update his size his size in X and the curent sizer size in Y:
if (propertyMode == ewol::widget::Sizer::modeVert) {
if (it->canExpand().x() == false) {
continue;
}
vec2 tmpSizeMin = it->getSize();
tmpSizeMin.setX(std::avg(tmpSizeMin.x(), localWidgetSize.x(), it->getCalculateMaxSize().x()));
it->setSize(tmpSizeMin);
} else {
if (it->canExpand().y() == false) {
continue;
}
vec2 tmpSizeMin = it->getSize();
tmpSizeMin.setY(std::avg(tmpSizeMin.y(), localWidgetSize.y(), it->getCalculateMaxSize().y()));
it->setSize(tmpSizeMin);
}
}
// -6- Force size at the entire number:
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
it->setSize(vec2ClipInt32(it->getSize()));
}
// -7- get under Size
vec2 underSize(0,0);
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
vec2 size = it->getSize();
if (propertyMode == ewol::widget::Sizer::modeVert) {
underSize += vec2(0.0f, size.y());
underSize.setX(std::max(underSize.x(), size.x()));
} else {
underSize += vec2(size.x(), 0.0f);
underSize.setY(std::max(underSize.y(), size.y()));
}
}
vec2 deltas = localWidgetSize - underSize;
// -8- Calculate the local origin, depending of the gravity:
vec2 tmpOrigin = m_origin + tmpBorderSize + ewol::gravityGenerateDelta(propertyGravity, deltas);
// -9- Set sub widget origin:
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
vec2 origin;
vec2 size = it->getSize();
if (propertyMode == ewol::widget::Sizer::modeVert) {
origin = vec2ClipInt32(tmpOrigin+m_offset + ewol::gravityGenerateDelta(propertyGravity, vec2(underSize.x()-size.x(),0.0f)));
} else {
origin = vec2ClipInt32(tmpOrigin+m_offset + ewol::gravityGenerateDelta(propertyGravity, vec2(0.0f, underSize.y()-size.y())));
}
it->setOrigin(origin);
if (propertyMode == ewol::widget::Sizer::modeVert) {
tmpOrigin.setY(tmpOrigin.y() + size.y());
} else {
tmpOrigin.setX(tmpOrigin.x() + size.x());
}
}
// -10- Update all subSize at every element:
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
it->onChangeSize();
}
markToRedraw();
}
void ewol::widget::Sizer::calculateMinMaxSize() {
EWOL_VERBOSE("[" << getId() << "] update minimum size");
m_subExpend.setValue(false, false);
m_minSize = propertyMinSize->getPixel();
vec2 tmpBorderSize = propertyBorderSize->getPixel();
EWOL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} set min size : " << m_minSize);
for (auto &it : m_subWidget) {
if (it == nullptr) {
continue;
}
it->calculateMinMaxSize();
if (it->canExpand().x() == true) {
m_subExpend.setX(true);
}
if (it->canExpand().y() == true) {
m_subExpend.setY(true);
}
vec2 tmpSize = it->getCalculateMinSize();
EWOL_VERBOSE("[" << getId() << "] NewMinSize=" << tmpSize);
EWOL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} Get minSize="<< tmpSize);
if (propertyMode == ewol::widget::Sizer::modeVert) {
m_minSize.setY(m_minSize.y() + tmpSize.y());
if (tmpSize.x()>m_minSize.x()) {
m_minSize.setX(tmpSize.x());
}
} else {
m_minSize.setX(m_minSize.x() + tmpSize.x());
if (tmpSize.y()>m_minSize.y()) {
m_minSize.setY(tmpSize.y());
}
}
}
m_minSize += tmpBorderSize*2;
//EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} Result min size : " << m_minSize);
}
int32_t ewol::widget::Sizer::subWidgetAdd(std::shared_ptr<ewol::Widget> _newWidget) {
if (propertyAnimation == animationNone) {
return ewol::widget::ContainerN::subWidgetAdd(_newWidget);
}
// TODO : ...
return ewol::widget::ContainerN::subWidgetAdd(_newWidget);
}
int32_t ewol::widget::Sizer::subWidgetAddStart(std::shared_ptr<ewol::Widget> _newWidget) {
if (propertyAnimation == animationNone) {
return ewol::widget::ContainerN::subWidgetAddStart(_newWidget);
}
// TODO : ...
return ewol::widget::ContainerN::subWidgetAddStart(_newWidget);
}
void ewol::widget::Sizer::subWidgetRemove(std::shared_ptr<ewol::Widget> _newWidget) {
if (propertyAnimation == animationNone) {
ewol::widget::ContainerN::subWidgetRemove(_newWidget);
return;
}
// TODO : ...
ewol::widget::ContainerN::subWidgetRemove(_newWidget);
}
void ewol::widget::Sizer::subWidgetUnLink(std::shared_ptr<ewol::Widget> _newWidget) {
if (propertyAnimation == animationNone) {
ewol::widget::ContainerN::subWidgetUnLink(_newWidget);
return;
}
// TODO : ...
ewol::widget::ContainerN::subWidgetUnLink(_newWidget);
}
void ewol::widget::Sizer::onPropertyChangeValue(const eproperty::Ref& _paramPointer) {
ewol::widget::ContainerN::onPropertyChangeValue(_paramPointer);
if (_paramPointer == propertyMode) {
markToRedraw();
requestUpdateSize();
} else if (_paramPointer == propertyBorderSize) {
markToRedraw();
requestUpdateSize();
}
}