Dawn/archive/ui/UIAlignableElement.cpp

247 lines
5.3 KiB
C++

// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIAlignableElement.hpp"
using namespace Dawn;
UIAlignableElement::UIAlignableElement() {
alignUnit[0] = UIAlignmentUnit::SCALE;
alignUnit[1] = UIAlignmentUnit::SCALE;
alignUnit[2] = UIAlignmentUnit::SCALE;
alignUnit[3] = UIAlignmentUnit::SCALE;
eventAlignmentUpdated = [&](const glm::vec2 p, const glm::vec2 s) {
};
}
void UIAlignableElement::updateSelfAlignment(
const glm::vec2 pPos,
const glm::vec2 pSize,
const float_t canvasScale
) {
auto valueAxis = [&](
const enum UIAlignmentUnit unit,
const float_t alignment,
const float_t parentSize,
const float_t ratioSize,
const float_t contentSize
) {
if(alignment == UI_ALIGN_SIZE_AUTO) return contentSize;
switch(unit) {
case UIAlignmentUnit::PIXEL:
return alignment;
case UIAlignmentUnit::SCALE:
return canvasScale * alignment;
case UIAlignmentUnit::PERCENT:
return parentSize * (alignment / 100.0f);
case UIAlignmentUnit::RATIO:
return (alignment / 100.0f) * ratioSize;
default:
assertUnreachable("Invalid UIAlignmentType");
return 0.0f;
}
};
auto alignAxis = [&](
const enum UIAlignmentType type,
const enum UIAlignmentUnit unit0,
const enum UIAlignmentUnit unit1,
const float_t alignment0,
const float_t alignment1,
const float_t parentSize,
const float_t ratioSize,
const float_t contentSize,
float_t &outPosition,
float_t &outSize
) {
switch(type) {
case UIAlignmentType::START:
outPosition = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outSize = valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::MIDDLE:
outSize = valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
outPosition = (parentSize / 2.0f) - (contentSize / 2.0f) + valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::END:
outSize = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outPosition = parentSize - outSize - valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::STRETCH:
outPosition = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outSize = parentSize - (outPosition + valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
));
break;
default:
assertUnreachable("Invalid UIAlignmentType");
}
};
bool_t heightFirst = (
alignUnit[0] == UIAlignmentUnit::RATIO ||
alignUnit[2] == UIAlignmentUnit::RATIO
);
if(heightFirst) {
// Align height first, this will define size.y which we can use as the ratio
// for the width/X axis alignment.
alignAxis(
alignY,
alignUnit[1],
alignUnit[3],
align[1],
align[3],
pSize.y,
0,
this->getContentHeight(),
position.y,
size.y
);
alignAxis(
alignX,
alignUnit[0],
alignUnit[2],
align[0],
align[2],
pSize.x,
size.y,
this->getContentWidth(),
position.x,
size.x
);
} else {
alignAxis(
alignX,
alignUnit[0],
alignUnit[2],
align[0],
align[2],
pSize.x,
0,
this->getContentWidth(),
position.x,
size.x
);
alignAxis(
alignY,
alignUnit[1],
alignUnit[3],
align[1],
align[3],
pSize.y,
size.x,
this->getContentHeight(),
position.y,
size.y
);
}
this->position += pPos;
this->eventAlignmentUpdated(position, size);
}
bool_t UIAlignableElement::hasExplicitWidth() {
if(size.x == 0.0f) return false;
if(
(alignX == UIAlignmentType::STRETCH) ||
(alignX == UIAlignmentType::END)
) {
return align[0] != UI_ALIGN_SIZE_AUTO;
}
return align[2] != UI_ALIGN_SIZE_AUTO;
}
bool_t UIAlignableElement::hasExplicitHeight() {
if(size.y == 0.0f) return false;
if(
(alignY == UIAlignmentType::STRETCH) ||
(alignY == UIAlignmentType::END)
) {
return align[1] != UI_ALIGN_SIZE_AUTO;
}
return align[3] != UI_ALIGN_SIZE_AUTO;
}
float_t UIAlignableElement::getWidth() {
if(hasExplicitWidth()) return size.x;
return getContentWidth();
}
float_t UIAlignableElement::getHeight() {
if(hasExplicitHeight()) return size.y;
return getContentHeight();
}
void UIAlignableElement::updateAlignment(
const glm::vec2 pPos,
const glm::vec2 pSize,
const float_t canvasScale
) {
this->updateSelfAlignment(pPos, pSize, canvasScale);
// Now update children alignment
auto children = getChildren();
for(auto &c : children) {
c->updateAlignment(this->position, this->size, canvasScale);
}
}