<commit_before>#include "LinearContainer.hpp"

#include "../util/Gravity.hpp"
#include "../util/LayoutDim.hpp"
#include "../util/util.hpp"

#include <cmath>


using namespace morda;



namespace{
	
const char* D_Margins = "margins";
const char* D_Weight = "weight";

class Info{
public:
	float weight;
	Vec2r dim;
	float margin;//actual margin between child widgets
	Gravity gravity;
	LeftBottomRightTop margins;
};

}//~namespace



LinearContainer::LinearContainer(const stob::Node* desc) :
		Widget(desc),
		Container(desc),
		PaddedWidget(desc),
		LinearWidget(desc),
		GravitatingWidget(desc)
{}



//override
void LinearContainer::OnResize(){
	unsigned longIndex = this->GetLongIndex();
	unsigned transIndex = this->GetTransIndex();
	
	std::vector<Info> infoArray(this->Children().size());
	
	//Calculate rigid size, net weight and store weights and margins
	float rigid = this->Padding()[longIndex] + this->Padding()[2 + longIndex];
	float netWeight = 0;
	
	{
		auto info = infoArray.begin();
		for(auto i = this->Children().cbegin(); i != this->Children().cend(); ++i, ++info){
			ASSERT(info != infoArray.end())
			if(const stob::Node* layout = (*i)->GetPropertyNode(Container::D_Layout())){
				if(const stob::Node* weight = layout->GetProperty(D_Weight)){
					info->weight = weight->AsFloat();
					netWeight += info->weight;
				}else{
					info->weight = 0;
				}

				LayoutDim dim = LayoutDim::FromLayout(*layout);
				info->dim = (*i)->Measure(dim.ForWidget(*this, *(*i)));
				
				if(const stob::Node* g = layout->Child(Gravity::D_Gravity()).node()){
					info->gravity = Gravity::FromSTOB(*g);
				}else{
					info->gravity = this->gravity();
				}
				
				if(const stob::Node* margins = layout->Child(D_Margins).node()){
					info->margins = LeftBottomRightTop::FromSTOB(*margins);
				}else{
					info->margins = LeftBottomRightTop::Default();
				}
			}else{
				info->dim = (*i)->GetMinDim();
				info->weight = 0;
				info->gravity = this->gravity();
				info->margins = LeftBottomRightTop::Default();
			}
			
			if(info != infoArray.begin()){//if not first child
				info->margin = std::max(
						(info - 1)->margins[this->IsReverse() ? longIndex : (longIndex + 2)],
						info->margins[this->IsReverse() ? (longIndex + 2) : longIndex]
					);
			}else{
				info->margin = 0;
			}
			
			rigid += info->dim[longIndex] + info->margin;
		}
	}
	
	//arrange widgets
	{
		float flexible = this->Rect().d[longIndex] - rigid;
		ting::util::ClampBottom(flexible, 0.0f);
		if(!std::isfinite(flexible)){
			flexible = 0;
		}
		ASSERT_INFO(flexible >= 0, "flexible = " << flexible)
		
		float pos = this->Padding()[this->IsReverse() ? (longIndex + 2) : longIndex];//start arranging widgets from padding
		auto info = infoArray.begin();
		for(auto i = this->Children().begin(); i != this->Children().end(); ++i, ++info){
			Vec2r newSize(info->dim);
			
			if(netWeight > 0){
				newSize[longIndex] += (info->weight / netWeight) * flexible;
			}

			Vec2r newPos;
			if((this->IsVertical() && !this->IsReverse()) || (!this->IsVertical() && this->IsReverse())){
				newPos[longIndex] = this->Rect().d[longIndex] - pos - info->margin - newSize[longIndex];
			}else{
				newPos[longIndex] = pos + info->margin;
			}
			pos += info->margin + newSize[longIndex];

			(*i)->Resize(RoundVec(newSize));
			
			newPos[transIndex] = info->gravity.PosForRect(*this, (*i)->Rect().d)[transIndex];
			
			(*i)->MoveTo(newPos);
		}
	}
}



//override
morda::Vec2r LinearContainer::ComputeMinDim()const NOEXCEPT{
	unsigned longIndex = this->GetLongIndex();
	unsigned transIndex = this->GetTransIndex();
	
	morda::Vec2r minDim(0);
	
	float prevMargin = 0;
	
	for(Widget::T_ChildrenList::const_iterator i = this->Children().begin(); i != this->Children().end(); ++i){
		LeftBottomRightTop margins = LeftBottomRightTop::Default();
		morda::Vec2r dim = (*i)->GetMinDim();
		if((*i)->Prop()){
			if(const stob::Node* layout = (*i)->Prop()->Child(Container::D_Layout()).node()){
				if(const stob::Node* m = layout->Child(D_Margins).node()){
					margins = LeftBottomRightTop::FromSTOB(*m);
				}
				
				{
					LayoutDim ld = LayoutDim::FromLayout(*layout);
					
					//FRACTION min size is minDim
					for(unsigned j = 0; j != 2; ++j){
						if(ld[j].unit == LayoutDim::FRACTION){
							ld[j].unit = LayoutDim::PIXEL;
							ld[j].value = dim[j];
						}
					}
					
					dim = (*i)->Measure(ld.ForWidget(*this, *(*i)));
				}
			}
		}
		
		if(minDim[transIndex] < dim[transIndex]){
			minDim[transIndex] = dim[transIndex];
		}
		minDim[longIndex] += dim[longIndex];
		
		//margin works for non-first children only
		if(i != this->Children().begin()){//if not first child
			minDim[longIndex] += std::max(
					prevMargin,
					margins[this->IsReverse() ? (longIndex + 2) : longIndex]
				);
		}
		
		prevMargin = margins[this->IsReverse() ? longIndex : (longIndex + 2)];
	}<commit_msg>fraction min size is 0<commit_after>#include "LinearContainer.hpp"

#include "../util/Gravity.hpp"
#include "../util/LayoutDim.hpp"
#include "../util/util.hpp"

#include <cmath>


using namespace morda;



namespace{
	
const char* D_Margins = "margins";
const char* D_Weight = "weight";

class Info{
public:
	float weight;
	Vec2r dim;
	float margin;//actual margin between child widgets
	Gravity gravity;
	LeftBottomRightTop margins;
};

}//~namespace



LinearContainer::LinearContainer(const stob::Node* desc) :
		Widget(desc),
		Container(desc),
		PaddedWidget(desc),
		LinearWidget(desc),
		GravitatingWidget(desc)
{}



//override
void LinearContainer::OnResize(){
	unsigned longIndex = this->GetLongIndex();
	unsigned transIndex = this->GetTransIndex();
	
	std::vector<Info> infoArray(this->Children().size());
	
	//Calculate rigid size, net weight and store weights and margins
	float rigid = this->Padding()[longIndex] + this->Padding()[2 + longIndex];
	float netWeight = 0;
	
	{
		auto info = infoArray.begin();
		for(auto i = this->Children().cbegin(); i != this->Children().cend(); ++i, ++info){
			ASSERT(info != infoArray.end())
			if(const stob::Node* layout = (*i)->GetPropertyNode(Container::D_Layout())){
				if(const stob::Node* weight = layout->GetProperty(D_Weight)){
					info->weight = weight->AsFloat();
					netWeight += info->weight;
				}else{
					info->weight = 0;
				}

				LayoutDim dim = LayoutDim::FromLayout(*layout);
				info->dim = (*i)->Measure(dim.ForWidget(*this, *(*i)));
				
				if(const stob::Node* g = layout->Child(Gravity::D_Gravity()).node()){
					info->gravity = Gravity::FromSTOB(*g);
				}else{
					info->gravity = this->gravity();
				}
				
				if(const stob::Node* margins = layout->Child(D_Margins).node()){
					info->margins = LeftBottomRightTop::FromSTOB(*margins);
				}else{
					info->margins = LeftBottomRightTop::Default();
				}
			}else{
				info->dim = (*i)->GetMinDim();
				info->weight = 0;
				info->gravity = this->gravity();
				info->margins = LeftBottomRightTop::Default();
			}
			
			if(info != infoArray.begin()){//if not first child
				info->margin = std::max(
						(info - 1)->margins[this->IsReverse() ? longIndex : (longIndex + 2)],
						info->margins[this->IsReverse() ? (longIndex + 2) : longIndex]
					);
			}else{
				info->margin = 0;
			}
			
			rigid += info->dim[longIndex] + info->margin;
		}
	}
	
	//arrange widgets
	{
		float flexible = this->Rect().d[longIndex] - rigid;
		ting::util::ClampBottom(flexible, 0.0f);
		if(!std::isfinite(flexible)){
			flexible = 0;
		}
		ASSERT_INFO(flexible >= 0, "flexible = " << flexible)
		
		float pos = this->Padding()[this->IsReverse() ? (longIndex + 2) : longIndex];//start arranging widgets from padding
		auto info = infoArray.begin();
		for(auto i = this->Children().begin(); i != this->Children().end(); ++i, ++info){
			Vec2r newSize(info->dim);
			
			if(netWeight > 0){
				newSize[longIndex] += (info->weight / netWeight) * flexible;
			}

			Vec2r newPos;
			if((this->IsVertical() && !this->IsReverse()) || (!this->IsVertical() && this->IsReverse())){
				newPos[longIndex] = this->Rect().d[longIndex] - pos - info->margin - newSize[longIndex];
			}else{
				newPos[longIndex] = pos + info->margin;
			}
			pos += info->margin + newSize[longIndex];

			(*i)->Resize(RoundVec(newSize));
			
			newPos[transIndex] = info->gravity.PosForRect(*this, (*i)->Rect().d)[transIndex];
			
			(*i)->MoveTo(newPos);
		}
	}
}



//override
morda::Vec2r LinearContainer::ComputeMinDim()const NOEXCEPT{
	unsigned longIndex = this->GetLongIndex();
	unsigned transIndex = this->GetTransIndex();
	
	morda::Vec2r minDim(0);
	
	float prevMargin = 0;
	
	for(Widget::T_ChildrenList::const_iterator i = this->Children().begin(); i != this->Children().end(); ++i){
		LeftBottomRightTop margins = LeftBottomRightTop::Default();
		morda::Vec2r dim = (*i)->GetMinDim();
		if((*i)->Prop()){
			if(const stob::Node* layout = (*i)->Prop()->Child(Container::D_Layout()).node()){
				if(const stob::Node* m = layout->Child(D_Margins).node()){
					margins = LeftBottomRightTop::FromSTOB(*m);
				}
				
				{
					LayoutDim ld = LayoutDim::FromLayout(*layout);
					
					//FRACTION min size is 0
					for(unsigned j = 0; j != 2; ++j){
						if(ld[j].unit == LayoutDim::FRACTION){
							ld[j].unit = LayoutDim::PIXEL;
							ld[j].value = 0;
						}
					}
					
					dim = (*i)->Measure(ld.ForWidget(*this, *(*i)));
				}
			}
		}
		
		if(minDim[transIndex] < dim[transIndex]){
			minDim[transIndex] = dim[transIndex];
		}
		minDim[longIndex] += dim[longIndex];
		
		//margin works for non-first children only
		if(i != this->Children().begin()){//if not first child
			minDim[longIndex] += std::max(
					prevMargin,
					margins[this->IsReverse() ? (longIndex + 2) : longIndex]
				);
		}
		
		prevMargin = margins[this->IsReverse() ? longIndex : (longIndex + 2)];
	}
{'fraction_non_alphanumeric': 0.1890923974214673, 'fraction_numerical': 0.005627749923257956, 'mean_word_length': 3.6565030967127203, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 147, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '234097', 'n_tokens_mistral': 4030, 'n_tokens_neox': 3300, 'n_words': 634}