247 lines
5.3 KiB
C++
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);
|
|
}
|
|
} |