198 lines
4.7 KiB
C++
198 lines
4.7 KiB
C++
// Copyright (c) 2023 Dominic Masters
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
#include "UIComponent.hpp"
|
|
|
|
using namespace Dawn;
|
|
|
|
|
|
UIComponent::UIComponent(SceneItem *item) :
|
|
SceneItemComponent(item),
|
|
alignment(glm::vec4(0, 0, 128, 128)),
|
|
alignUnitLeft(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
|
alignUnitTop(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
|
alignUnitRight(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
|
alignUnitBottom(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
|
alignX(UI_COMPONENT_ALIGN_START),
|
|
alignY(UI_COMPONENT_ALIGN_START),
|
|
alignmentNeedsUpdating(true)
|
|
{
|
|
|
|
}
|
|
|
|
UIComponentDimensional * UIComponent::getParentDimensional() {
|
|
auto parent = this->transform->getParent();
|
|
if(parent == nullptr) return nullptr;
|
|
auto dimensional = parent->item->getComponent<UIComponentDimensional>();
|
|
assertNotNull(dimensional);
|
|
return dimensional;
|
|
}
|
|
|
|
void UIComponent::updateAlignment() {
|
|
if(!this->alignmentNeedsUpdating) return;
|
|
|
|
auto align = (glm::vec4)this->alignment;
|
|
auto dimensional = this->getParentDimensional();
|
|
auto translate = this->transform->getLocalPosition();
|
|
|
|
assertNotNull(dimensional);
|
|
|
|
float_t parentWidth, parentHeight;
|
|
parentWidth = dimensional->getWidth();
|
|
parentHeight = dimensional->getHeight();
|
|
|
|
UIComponent::calculateDimensions(
|
|
this->alignX,
|
|
this->alignUnitLeft,
|
|
this->alignUnitRight,
|
|
&translate.x,
|
|
&this->width,
|
|
parentWidth,
|
|
this->getContentWidth(),
|
|
glm::vec2(align[0], align[2])
|
|
);
|
|
UIComponent::calculateDimensions(
|
|
this->alignY,
|
|
this->alignUnitTop,
|
|
this->alignUnitBottom,
|
|
&translate.y,
|
|
&this->height,
|
|
parentHeight,
|
|
this->getContentHeight(),
|
|
glm::vec2(align[1], align[3])
|
|
);
|
|
|
|
this->transform->setLocalPosition(translate);
|
|
this->alignmentNeedsUpdating = false;
|
|
this->eventAlignmentUpdated.invoke();
|
|
}
|
|
|
|
float_t UIComponent::calculateAlignmentValue(
|
|
float_t alignmentValue,
|
|
float_t parentSize,
|
|
enum UIComponentAlignUnit unit
|
|
) {
|
|
if(unit == UI_COMPONENT_ALIGN_UNIT_SCALE) return alignmentValue;
|
|
return (alignmentValue / 100.0f) * parentSize;
|
|
}
|
|
|
|
void UIComponent::calculateDimensions(
|
|
enum UIComponentAlign align,
|
|
enum UIComponentAlignUnit unitStart,
|
|
enum UIComponentAlignUnit unitEnd,
|
|
float_t *position,
|
|
float_t *size,
|
|
float_t outerSize,
|
|
float_t innerSize,
|
|
glm::vec2 alignment
|
|
) {
|
|
assertNotNull(position);
|
|
assertNotNull(size);
|
|
|
|
switch(align) {
|
|
case UI_COMPONENT_ALIGN_STRETCH: {
|
|
// For stretch:
|
|
// Alignment 0 becomes START offset, Alignment 1 becomes END Offset
|
|
*position = UIComponent::calculateAlignmentValue(
|
|
alignment[0],
|
|
outerSize,
|
|
unitStart
|
|
);
|
|
*size = outerSize - (*position + UIComponent::calculateAlignmentValue(
|
|
alignment[1],
|
|
outerSize,
|
|
unitEnd
|
|
));
|
|
break;
|
|
}
|
|
|
|
case UI_COMPONENT_ALIGN_START: {
|
|
// For start:
|
|
// Alignment 0 becomes START offset, Alignment 1 becomes SIZE
|
|
*position = UIComponent::calculateAlignmentValue(
|
|
alignment[0],
|
|
outerSize,
|
|
unitStart
|
|
);
|
|
*size = UIComponent::calculateAlignmentValue(
|
|
alignment[1],
|
|
outerSize,
|
|
unitEnd
|
|
);
|
|
break;
|
|
}
|
|
|
|
case UI_COMPONENT_ALIGN_MIDDLE: {
|
|
*size = mathMax<float_t>(
|
|
innerSize,
|
|
UIComponent::calculateAlignmentValue(
|
|
alignment[1],
|
|
outerSize,
|
|
unitEnd
|
|
)
|
|
);
|
|
*position = (outerSize / 2.0f) - (*size / 2.0f) + UIComponent::calculateAlignmentValue(
|
|
alignment[0],
|
|
outerSize,
|
|
unitStart
|
|
);
|
|
break;
|
|
}
|
|
|
|
case UI_COMPONENT_ALIGN_END: {
|
|
*size = UIComponent::calculateAlignmentValue(
|
|
alignment[0],
|
|
outerSize,
|
|
unitStart
|
|
);
|
|
*position = outerSize - *size - UIComponent::calculateAlignmentValue(
|
|
alignment[1],
|
|
outerSize,
|
|
unitEnd
|
|
);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
assertUnreachable();
|
|
break;
|
|
}
|
|
}
|
|
|
|
UICanvas * UIComponent::getCanvas() {
|
|
// TODO: Cache this on first hit.
|
|
auto parent = this->transform->getParent();
|
|
while(parent != nullptr) {
|
|
auto canvas = parent->item->getComponent<UICanvas>();
|
|
if(canvas != nullptr) return canvas;
|
|
parent = parent->getParent();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
float_t UIComponent::getWidth() {
|
|
return this->width;
|
|
}
|
|
|
|
float_t UIComponent::getHeight() {
|
|
return this->height;
|
|
}
|
|
|
|
void UIComponent::onStart() {
|
|
useEffect([&]{
|
|
this->alignmentNeedsUpdating = true;
|
|
}, { &alignment, &alignX, &alignY });
|
|
|
|
useEffect([&]{
|
|
this->updateAlignment();
|
|
|
|
auto child = this->item->findChildren<UIComponent>();
|
|
auto itChild = child.begin();
|
|
while(itChild != child.end()) {
|
|
(*itChild)->alignmentNeedsUpdating = true;
|
|
++itChild;
|
|
}
|
|
}, alignmentNeedsUpdating)();
|
|
} |