#include "RelationItem.h" #include "GComponent.h" #include "GGroup.h" #include "event/UIEventType.h" #include "utils/WeakPtr.h" NS_FGUI_BEGIN USING_NS_AX; RelationItem::RelationItem(GObject* owner) : _target(nullptr) { _owner = owner; } RelationItem::~RelationItem() { releaseRefTarget(_target.ptr()); } void RelationItem::setTarget(GObject* value) { GObject* old = _target.ptr(); if (old != value) { if (old) releaseRefTarget(old); _target = value; if (value) addRefTarget(value); } } void RelationItem::add(RelationType relationType, bool usePercent) { if (relationType == RelationType::Size) { add(RelationType::Width, usePercent); add(RelationType::Height, usePercent); return; } for (auto& it : _defs) { if (it.type == relationType) return; } internalAdd(relationType, usePercent); } void RelationItem::internalAdd(RelationType relationType, bool usePercent) { if (relationType == RelationType::Size) { internalAdd(RelationType::Width, usePercent); internalAdd(RelationType::Height, usePercent); return; } RelationDef info; info.percent = usePercent; info.type = relationType; info.axis = (relationType <= RelationType::Right_Right || relationType == RelationType::Width || (relationType >= RelationType::LeftExt_Left && relationType <= RelationType::RightExt_Right)) ? 0 : 1; _defs.push_back(info); if (usePercent || relationType == RelationType::Left_Center || relationType == RelationType::Center_Center || relationType == RelationType::Right_Center || relationType == RelationType::Top_Middle || relationType == RelationType::Middle_Middle || relationType == RelationType::Bottom_Middle) _owner->setPixelSnapping(true); } void RelationItem::remove(RelationType relationType) { if (relationType == RelationType::Size) { remove(RelationType::Width); remove(RelationType::Height); return; } for (auto it = _defs.begin(); it != _defs.end(); ++it) { if (it->type == relationType) { _defs.erase(it); break; } } } void RelationItem::copyFrom(const RelationItem& source) { setTarget(source._target.ptr()); _defs.clear(); for (auto& it : source._defs) _defs.push_back(it); } bool RelationItem::isEmpty() const { return _defs.size() == 0; } void RelationItem::applyOnSelfSizeChanged(float dWidth, float dHeight, bool applyPivot) { if (_target == nullptr || _defs.size() == 0) return; float ox = _owner->_position.x; float oy = _owner->_position.y; for (auto& it : _defs) { switch (it.type) { case RelationType::Center_Center: _owner->setX(_owner->_position.x - (0.5 - (applyPivot ? _owner->_pivot.x : 0)) * dWidth); break; case RelationType::Right_Center: case RelationType::Right_Left: case RelationType::Right_Right: _owner->setX(_owner->_position.x - (1 - (applyPivot ? _owner->_pivot.x : 0)) * dWidth); break; case RelationType::Middle_Middle: _owner->setY(_owner->_position.y - (0.5 - (applyPivot ? _owner->_pivot.y : 0)) * dHeight); break; case RelationType::Bottom_Middle: case RelationType::Bottom_Top: case RelationType::Bottom_Bottom: _owner->setY(_owner->_position.y - (1 - (applyPivot ? _owner->_pivot.y : 0)) * dHeight); break; default: break; } } if (ox != _owner->_position.x || oy != _owner->_position.y) { ox = _owner->_position.x - ox; oy = _owner->_position.y - oy; _owner->updateGearFromRelations(1, ox, oy); if (_owner->_parent != nullptr) { const Vector& arr = _owner->_parent->getTransitions(); for (auto& it : arr) it->updateFromRelations(_owner->id, ox, oy); } } } void RelationItem::applyOnXYChanged(GObject* target, const RelationDef& info, float dx, float dy) { float tmp; switch (info.type) { case RelationType::Left_Left: case RelationType::Left_Center: case RelationType::Left_Right: case RelationType::Center_Center: case RelationType::Right_Left: case RelationType::Right_Center: case RelationType::Right_Right: _owner->setX(_owner->_position.x + dx); break; case RelationType::Top_Top: case RelationType::Top_Middle: case RelationType::Top_Bottom: case RelationType::Middle_Middle: case RelationType::Bottom_Top: case RelationType::Bottom_Middle: case RelationType::Bottom_Bottom: _owner->setY(_owner->_position.y + dy); break; case RelationType::Width: case RelationType::Height: break; case RelationType::LeftExt_Left: case RelationType::LeftExt_Right: if (_owner != target->getParent()) { tmp = _owner->getXMin(); _owner->setWidth(_owner->_rawSize.width - dx); _owner->setXMin(tmp + dx); } else _owner->setWidth(_owner->_rawSize.width - dx); break; case RelationType::RightExt_Left: case RelationType::RightExt_Right: if (_owner != target->getParent()) { tmp = _owner->getXMin(); _owner->setWidth(_owner->_rawSize.width + dx); _owner->setXMin(tmp); } else _owner->setWidth(_owner->_rawSize.width + dx); break; case RelationType::TopExt_Top: case RelationType::TopExt_Bottom: if (_owner != target->getParent()) { tmp = _owner->getYMin(); _owner->setHeight(_owner->_rawSize.height - dy); _owner->setYMin(tmp + dy); } else _owner->setHeight(_owner->_rawSize.height - dy); break; case RelationType::BottomExt_Top: case RelationType::BottomExt_Bottom: if (_owner != target->getParent()) { tmp = _owner->getYMin(); _owner->setHeight(_owner->_rawSize.height + dy); _owner->setYMin(tmp); } else _owner->setHeight(_owner->_rawSize.height + dy); break; default: break; } } void RelationItem::applyOnSizeChanged(GObject* target, const RelationDef& info) { float pos = 0, pivot = 0, delta = 0; if (info.axis == 0) { if (target != _owner->_parent) { pos = target->_position.x; if (target->_pivotAsAnchor) pivot = target->_pivot.x; } if (info.percent) { if (_targetData.z != 0) delta = target->_size.width / _targetData.z; } else delta = target->_size.width - _targetData.z; } else { if (target != _owner->_parent) { pos = target->_position.y; if (target->_pivotAsAnchor) pivot = target->_pivot.y; } if (info.percent) { if (_targetData.w != 0) delta = target->_size.height / _targetData.w; } else delta = target->_size.height - _targetData.w; } float v, tmp; switch (info.type) { case RelationType::Left_Left: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() - pos) * delta); else if (pivot != 0) _owner->setX(_owner->_position.x + delta * (-pivot)); break; case RelationType::Left_Center: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() - pos) * delta); else _owner->setX(_owner->_position.x + delta * (0.5f - pivot)); break; case RelationType::Left_Right: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() - pos) * delta); else _owner->setX(_owner->_position.x + delta * (1 - pivot)); break; case RelationType::Center_Center: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() + _owner->_rawSize.width * 0.5f - pos) * delta - _owner->_rawSize.width * 0.5f); else _owner->setX(_owner->_position.x + delta * (0.5f - pivot)); break; case RelationType::Right_Left: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() + _owner->_rawSize.width - pos) * delta - _owner->_rawSize.width); else if (pivot != 0) _owner->setX(_owner->_position.x + delta * (-pivot)); break; case RelationType::Right_Center: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() + _owner->_rawSize.width - pos) * delta - _owner->_rawSize.width); else _owner->setX(_owner->_position.x + delta * (0.5f - pivot)); break; case RelationType::Right_Right: if (info.percent) _owner->setXMin(pos + (_owner->getXMin() + _owner->_rawSize.width - pos) * delta - _owner->_rawSize.width); else _owner->setX(_owner->_position.x + delta * (1 - pivot)); break; case RelationType::Top_Top: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() - pos) * delta); else if (pivot != 0) _owner->setY(_owner->_position.y + delta * (-pivot)); break; case RelationType::Top_Middle: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() - pos) * delta); else _owner->setY(_owner->_position.y + delta * (0.5f - pivot)); break; case RelationType::Top_Bottom: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() - pos) * delta); else _owner->setY(_owner->_position.y + delta * (1 - pivot)); break; case RelationType::Middle_Middle: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() + _owner->_rawSize.height * 0.5f - pos) * delta - _owner->_rawSize.height * 0.5f); else _owner->setY(_owner->_position.y + delta * (0.5f - pivot)); break; case RelationType::Bottom_Top: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() + _owner->_rawSize.height - pos) * delta - _owner->_rawSize.height); else if (pivot != 0) _owner->setY(_owner->_position.y + delta * (-pivot)); break; case RelationType::Bottom_Middle: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() + _owner->_rawSize.height - pos) * delta - _owner->_rawSize.height); else _owner->setY(_owner->_position.y + delta * (0.5f - pivot)); break; case RelationType::Bottom_Bottom: if (info.percent) _owner->setYMin(pos + (_owner->getYMin() + _owner->_rawSize.height - pos) * delta - _owner->_rawSize.height); else _owner->setY(_owner->_position.y + delta * (1 - pivot)); break; case RelationType::Width: if (_owner->_underConstruct && _owner == target->_parent) v = _owner->sourceSize.width - target->initSize.width; else v = _owner->_rawSize.width - _targetData.z; if (info.percent) v = v * delta; if (_target == _owner->_parent) { if (_owner->_pivotAsAnchor) { tmp = _owner->getXMin(); _owner->setSize(target->_size.width + v, _owner->_rawSize.height, true); _owner->setXMin(tmp); } else _owner->setSize(target->_size.width + v, _owner->_rawSize.height, true); } else _owner->setWidth(target->_size.width + v); break; case RelationType::Height: if (_owner->_underConstruct && _owner == target->_parent) v = _owner->sourceSize.height - target->initSize.height; else v = _owner->_rawSize.height - _targetData.w; if (info.percent) v = v * delta; if (_target == _owner->_parent) { if (_owner->_pivotAsAnchor) { tmp = _owner->getYMin(); _owner->setSize(_owner->_rawSize.width, target->_size.height + v, true); _owner->setYMin(tmp); } else _owner->setSize(_owner->_rawSize.width, target->_size.height + v, true); } else _owner->setHeight(target->_size.height + v); break; case RelationType::LeftExt_Left: tmp = _owner->getXMin(); if (info.percent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (-pivot); _owner->setWidth(_owner->_rawSize.width - v); _owner->setXMin(tmp + v); break; case RelationType::LeftExt_Right: tmp = _owner->getXMin(); if (info.percent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (1 - pivot); _owner->setWidth(_owner->_rawSize.width - v); _owner->setXMin(tmp + v); break; case RelationType::RightExt_Left: tmp = _owner->getXMin(); if (info.percent) v = pos + (tmp + _owner->_rawSize.width - pos) * delta - (tmp + _owner->_rawSize.width); else v = delta * (-pivot); _owner->setWidth(_owner->_rawSize.width + v); _owner->setXMin(tmp); break; case RelationType::RightExt_Right: tmp = _owner->getXMin(); if (info.percent) { if (_owner == target->_parent) { if (_owner->_underConstruct) _owner->setWidth(pos + target->_size.width - target->_size.width * pivot + (_owner->sourceSize.width - pos - target->initSize.width + target->initSize.width * pivot) * delta); else _owner->setWidth(pos + (_owner->_rawSize.width - pos) * delta); } else { v = pos + (tmp + _owner->_rawSize.width - pos) * delta - (tmp + _owner->_rawSize.width); _owner->setWidth(_owner->_rawSize.width + v); _owner->setXMin(tmp); } } else { if (_owner == target->_parent) { if (_owner->_underConstruct) _owner->setWidth(_owner->sourceSize.width + (target->_size.width - target->initSize.width) * (1 - pivot)); else _owner->setWidth(_owner->_rawSize.width + delta * (1 - pivot)); } else { v = delta * (1 - pivot); _owner->setWidth(_owner->_rawSize.width + v); _owner->setXMin(tmp); } } break; case RelationType::TopExt_Top: tmp = _owner->getYMin(); if (info.percent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (-pivot); _owner->setHeight(_owner->_rawSize.height - v); _owner->setYMin(tmp + v); break; case RelationType::TopExt_Bottom: tmp = _owner->getYMin(); if (info.percent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (1 - pivot); _owner->setHeight(_owner->_rawSize.height - v); _owner->setYMin(tmp + v); break; case RelationType::BottomExt_Top: tmp = _owner->getYMin(); if (info.percent) v = pos + (tmp + _owner->_rawSize.height - pos) * delta - (tmp + _owner->_rawSize.height); else v = delta * (-pivot); _owner->setHeight(_owner->_rawSize.height + v); _owner->setYMin(tmp); break; case RelationType::BottomExt_Bottom: tmp = _owner->getYMin(); if (info.percent) { if (_owner == target->_parent) { if (_owner->_underConstruct) _owner->setHeight(pos + target->_size.height - target->_size.height * pivot + (_owner->sourceSize.height - pos - target->initSize.height + target->initSize.height * pivot) * delta); else _owner->setHeight(pos + (_owner->_rawSize.height - pos) * delta); } else { v = pos + (tmp + _owner->_rawSize.height - pos) * delta - (tmp + _owner->_rawSize.height); _owner->setHeight(_owner->_rawSize.height + v); _owner->setYMin(tmp); } } else { if (_owner == target->_parent) { if (_owner->_underConstruct) _owner->setHeight(_owner->sourceSize.height + (target->_size.height - target->initSize.height) * (1 - pivot)); else _owner->setHeight(_owner->_rawSize.height + delta * (1 - pivot)); } else { v = delta * (1 - pivot); _owner->setHeight(_owner->_rawSize.height + v); _owner->setYMin(tmp); } } break; default: break; } } void RelationItem::addRefTarget(GObject* target) { if (!target) return; if (target != _owner->_parent) target->addEventListener(UIEventType::PositionChange, AX_CALLBACK_1(RelationItem::onTargetXYChanged, this), EventTag(this)); target->addEventListener(UIEventType::SizeChange, AX_CALLBACK_1(RelationItem::onTargetSizeChanged, this), EventTag(this)); _targetData.x = target->_position.x; _targetData.y = target->_position.y; _targetData.z = target->_size.width; _targetData.w = target->_size.height; } void RelationItem::releaseRefTarget(GObject* target) { if (!target) return; target->removeEventListener(UIEventType::PositionChange, EventTag(this)); target->removeEventListener(UIEventType::SizeChange, EventTag(this)); } void RelationItem::onTargetXYChanged(EventContext* context) { GObject* target = (GObject*)context->getSender(); if (_owner->relations()->handling != nullptr || (_owner->_group != nullptr && _owner->_group->_updating != 0)) { _targetData.x = target->_position.x; _targetData.y = target->_position.y; return; } _owner->relations()->handling = target; float ox = _owner->_position.x; float oy = _owner->_position.y; float dx = target->_position.x - _targetData.x; float dy = target->_position.y - _targetData.y; for (auto& it : _defs) applyOnXYChanged(target, it, dx, dy); _targetData.x = target->_position.x; _targetData.y = target->_position.y; if (ox != _owner->_position.x || oy != _owner->_position.y) { ox = _owner->_position.x - ox; oy = _owner->_position.y - oy; _owner->updateGearFromRelations(1, ox, oy); if (_owner->_parent != nullptr) { const Vector& arr = _owner->_parent->getTransitions(); for (auto& it : arr) it->updateFromRelations(_owner->id, ox, oy); } } _owner->relations()->handling = nullptr; } void RelationItem::onTargetSizeChanged(EventContext* context) { GObject* target = (GObject*)context->getSender(); if (_owner->relations()->handling != nullptr || (_owner->_group != nullptr && _owner->_group->_updating != 0)) { _targetData.z = target->_size.width; _targetData.w = target->_size.height; return; } _owner->relations()->handling = target; float ox = _owner->_position.x; float oy = _owner->_position.y; float ow = _owner->_rawSize.width; float oh = _owner->_rawSize.height; for (auto& it : _defs) applyOnSizeChanged(target, it); _targetData.z = target->_size.width; _targetData.w = target->_size.height; if (ox != _owner->_position.x || oy != _owner->_position.y) { ox = _owner->_position.x - ox; oy = _owner->_position.y - oy; _owner->updateGearFromRelations(1, ox, oy); if (_owner->_parent != nullptr) { const Vector& arr = _owner->_parent->getTransitions(); for (auto& it : arr) it->updateFromRelations(_owner->id, ox, oy); } } if (ow != _owner->_rawSize.width || oh != _owner->_rawSize.height) { ow = _owner->_rawSize.width - ow; oh = _owner->_rawSize.height - oh; _owner->updateGearFromRelations(2, ow, oh); } _owner->relations()->handling = nullptr; } NS_FGUI_END