// // KKGLinearLayout.cpp // SteveAndMaggieWorld // // Created by Katarzyna Kalinowska-Górska on 03/12/2020. // #include "KKGLinearLayout.h" #define CONTAINER_Z_ORDER 10 #define BACKGROUND_Z_ORDER 0 KKGLinearLayout* KKGLinearLayout::create(LayoutType type, Alignment alignment, Gravity gravity){ KKGLinearLayout *ret = new (std::nothrow) KKGLinearLayout(); if (ret->init(type, alignment, gravity)) { ret->autorelease(); return ret; } CC_SAFE_DELETE(ret); return nullptr; } bool KKGLinearLayout::init(LayoutType type, Alignment alignment, Gravity gravity){ if(!cocos2d::Node::init()){ // if(!cocos2d::LayerColor::initWithColor(cocos2d::Color4B(220, 0, 00, 250))){ return false; } m_type = type; m_alignment = alignment; m_gravity = gravity; prepareInternalContainer(); return true; } void KKGLinearLayout::setCascadeOpacityEnabled(bool cascadeOpacityEnabled){ cocos2d::Node::setCascadeOpacityEnabled(cascadeOpacityEnabled); m_internalContainer->setCascadeOpacityEnabled(cascadeOpacityEnabled); } void KKGLinearLayout::setInterViewMargin(float margin, bool immediatelyRelayout){ m_interChildMargin = margin; if(immediatelyRelayout){ layoutViews(); } } float KKGLinearLayout::getInterViewMargin(){ return m_interChildMargin; } void KKGLinearLayout::addViews(std::vector views, bool immediatelyRelayout){ auto currIndex = (int)m_internalContainer->getChildrenCount(); for(auto it = views.begin(); it != views.end(); ++it){ (*it)->setTag(currIndex++); m_internalContainer->addChild(*it); } if(immediatelyRelayout){ layoutViews(); } } void KKGLinearLayout::setLayoutContentSize(const cocos2d::Size & size, bool immediatelyRelayout){ cocos2d::Node::setContentSize(size); if(immediatelyRelayout){ layoutViews(); } } const cocos2d::Size& KKGLinearLayout::getLayoutContentSize() const { return cocos2d::Node::getContentSize(); } void KKGLinearLayout::addView(cocos2d::Node * view, bool immediatelyRelayout){ view->setTag((int)m_internalContainer->getChildrenCount()); m_internalContainer->addChild(view); if(immediatelyRelayout){ layoutViews(); } } void KKGLinearLayout::setBackgroundColor(const cocos2d::Color4B& bgColor){ if(m_backgroundNode != nullptr){ m_backgroundNode->removeFromParent(); } m_backgroundNode = cocos2d::LayerColor::create(bgColor); addChild(m_backgroundNode); m_backgroundNode->setPosition(cocos2d::Vec2::ZERO); adjustBackground(getContentSize()); m_backgroundNode->setLocalZOrder(BACKGROUND_Z_ORDER); } void KKGLinearLayout::substituteViewAtIndex(int index, cocos2d::Node * newView){ CCASSERT(index >= 0 && index < m_internalContainer->getChildrenCount(), "KKGLinearLayout::substituteViewAtIndex: invalid index"); auto oldView = m_internalContainer->getChildByTag(index); newView->setPosition(oldView->getPosition()); newView->setAnchorPoint(oldView->getAnchorPoint()); newView->setContentSize(oldView->getContentSize()); newView->setTag(index); oldView->removeFromParent(); m_internalContainer->addChild(newView); } void KKGLinearLayout::layoutViews(){ if(m_internalContainer == nullptr){ //this also means there are no children to layout return; } if(m_type == HORIZONTAL){ auto childrenTotalWidth = 0; auto childrenMaxHeight = 0; auto allChildren = m_internalContainer->getChildren(); for(int i = 0; i < allChildren.size(); ++i){ // for(auto it = allChildren.begin(); it != allChildren.end(); ++it){ // auto child = *it; auto child = m_internalContainer->getChildByTag(i); if(child != nullptr){ childrenMaxHeight = MAX(child->getBoundingBox().size.height, childrenMaxHeight); childrenTotalWidth += child->getBoundingBox().size.width; childrenTotalWidth += m_interChildMargin; } } childrenTotalWidth -= m_interChildMargin; m_internalContainer->setContentSize(cocos2d::Size(childrenTotalWidth, childrenMaxHeight)); cocos2d::Point internalContainerPosition { cocos2d::Point::ZERO }; float childAnchorPointY = 0; float childPositionY = 0; switch(m_alignment){ case ASTART: m_internalContainerAnchorPoint.x = 0;// = (cocos2d::Vec2(0, 0.5)); internalContainerPosition.x = 0;// = cocos2d::Vec2(0, getContentSize().height/2); break; case AEND: m_internalContainerAnchorPoint.x = 1; internalContainerPosition.x = getContentSize().width; // m_internalContainer->setAnchorPoint(cocos2d::Vec2(1, 0.5)); // m_internalContainer->setPosition(getContentSize().width, getContentSize().height/2); break; case ACENTER: m_internalContainerAnchorPoint.x = 0.5; internalContainerPosition.x = getContentSize().width/2; // m_internalContainer->setAnchorPoint(cocos2d::Vec2(0.5, 0.5)); // m_internalContainer->setPosition(getContentSize()/2); break; } switch(m_gravity){ case GSTART: m_internalContainerAnchorPoint.y = 1; internalContainerPosition.y = getContentSize().height; childAnchorPointY = 0; childPositionY = 0; break; case GEND: m_internalContainerAnchorPoint.y = 0; internalContainerPosition.y = 0; childAnchorPointY = 1; childPositionY = childrenMaxHeight; break; case GCENTER: m_internalContainerAnchorPoint.y = 0.5; internalContainerPosition.y = getContentSize().height/2; childAnchorPointY = 0.5; childPositionY = childrenMaxHeight / 2; break; } m_internalContainer->setAnchorPoint(m_internalContainerAnchorPoint); m_internalContainer->setPosition(internalContainerPosition); float currentPoint = 0; for(int i = 0; i < allChildren.size(); ++i){ // for(auto it = allChildren.begin(); it != allChildren.end(); ++it){ // auto child = *it; auto child = m_internalContainer->getChildByTag(i); if(child != nullptr){ child->setAnchorPoint(cocos2d::Vec2(0, childAnchorPointY)); child->setPosition(cocos2d::Vec2(currentPoint, childPositionY)); currentPoint += child->getBoundingBox().size.width + m_interChildMargin; } } } else if(m_type == VERTICAL){ auto childrenTotalHeight = 0; auto childrenMaxWidth = 0; auto allChildren = m_internalContainer->getChildren(); for(int i = 0; i < allChildren.size(); ++i){ // for(auto it = allChildren.begin(); it != allChildren.end(); ++it){ // auto child = *it; auto child = m_internalContainer->getChildByTag(i); if(child != nullptr){ childrenMaxWidth = MAX(child->getBoundingBox().size.width, childrenMaxWidth); childrenTotalHeight += child->getBoundingBox().size.height; childrenTotalHeight += m_interChildMargin; } } childrenTotalHeight -= m_interChildMargin; m_internalContainer->setContentSize(cocos2d::Size(childrenMaxWidth, childrenTotalHeight)); cocos2d::Point internalContainerPosition { cocos2d::Point::ZERO }; float childAnchorPointX = 0; float childPositionX = 0; switch(m_alignment){ case ASTART: m_internalContainerAnchorPoint.y = 1; internalContainerPosition.y = getContentSize().height; break; case AEND: m_internalContainerAnchorPoint.y = 0; internalContainerPosition.y = 0; // m_internalContainer->setAnchorPoint(cocos2d::Vec2(1, 0.5)); // m_internalContainer->setPosition(getContentSize().width, getContentSize().height/2); break; case ACENTER: m_internalContainerAnchorPoint.y = 0.5; internalContainerPosition.y = getContentSize().height/2; // m_internalContainer->setAnchorPoint(cocos2d::Vec2(0.5, 0.5)); // m_internalContainer->setPosition(getContentSize()/2); break; } switch(m_gravity){ case GSTART: m_internalContainerAnchorPoint.x = 0; internalContainerPosition.x = 0; childAnchorPointX = 0; childPositionX = 0; break; case GEND: m_internalContainerAnchorPoint.x = 1; internalContainerPosition.x = getContentSize().width; childAnchorPointX = 1; childPositionX = childrenMaxWidth; break; case GCENTER: m_internalContainerAnchorPoint.x = 0.5; internalContainerPosition.x = getContentSize().width/2; childAnchorPointX = 0.5; childPositionX = childrenMaxWidth/2; break; } m_internalContainer->setAnchorPoint(m_internalContainerAnchorPoint); m_internalContainer->setPosition(internalContainerPosition); float currentPoint = childrenTotalHeight; for(int i = 0; i < allChildren.size(); ++i){ // for(auto it = allChildren.begin(); it != allChildren.end(); ++it){ // auto child = *it; auto child = m_internalContainer->getChildByTag(i); if(child != nullptr){ if(child->getRotation() == 0){ //TODO: handle rotated children child->setAnchorPoint(cocos2d::Vec2(childAnchorPointX, 1)); } else if(child->getRotation() == 90) { child->setAnchorPoint(cocos2d::Vec2(0, childAnchorPointX)); } child->setPosition(cocos2d::Vec2(childPositionX, currentPoint)); currentPoint -= child->getBoundingBox().size.height + m_interChildMargin; } } // switch(m_gravity){ // case START: // m_internalContainer->setAnchorPoint(cocos2d::Vec2(0.5, 1)); // m_internalContainer->setPosition(getContentSize().width/2, getContentSize().height); // break; // case END: // m_internalContainer->setAnchorPoint(cocos2d::Vec2(0.5, 0)); // m_internalContainer->setPosition(getContentSize().width/2, 0); // break; // case CENTER: // m_internalContainer->setAnchorPoint(cocos2d::Vec2(0.5, 0.5)); // m_internalContainer->setPosition(getContentSize()/2); // break; // } } adjustBackground(getContentSize()); } cocos2d::Vector KKGLinearLayout::getViews(){ return m_internalContainer->getChildren(); } cocos2d::Node* KKGLinearLayout::getView(int index){ return m_internalContainer->getChildByTag(index); } bool KKGLinearLayout::hasViews(){ return m_internalContainer != nullptr && m_internalContainer->getChildrenCount() > 0; } void KKGLinearLayout::removeAllViews(bool relayout){ m_internalContainer->removeAllChildren(); if(relayout){ layoutViews(); } } void KKGLinearLayout::removeLastView(bool relayout){ auto childrenCount = m_internalContainer->getChildrenCount(); assert(0 < childrenCount); auto child = m_internalContainer->getChildByTag(childrenCount - 1); if(child != nullptr){ child->removeFromParent(); if(relayout){ layoutViews(); } } } //void KKGLinearLayout::removeViewAtIndex(int index, bool relayout){ // assert(index < m_internalContainer->getChildrenCount()); // auto view = m_internalContainer->getChildByTag(index); // view->removeFromParent(); // if(relayout){ // layoutViews(); // } // // //TODO: retag children //} void KKGLinearLayout::wrapContents(){ layoutViews(); if(m_internalContainer == nullptr){ return; } auto newContentSize = m_internalContainer->getContentSize(); setContentSize(newContentSize); m_internalContainer->setPosition(newContentSize.width * m_internalContainerAnchorPoint.x, newContentSize.height*m_internalContainerAnchorPoint.y); //TODO separate method adjust inner container position adjustBackground(newContentSize); } void KKGLinearLayout::prepareInternalContainer(){ // if(m_internalContainer == nullptr){ m_internalContainer = cocos2d::Node::create();//cocos2d::LayerColor::create(cocos2d::Color4B(100, 200, 100, 250)); m_internalContainer->setIgnoreAnchorPointForPosition(false); addChild(m_internalContainer); m_internalContainer->setLocalZOrder(CONTAINER_Z_ORDER); // } } void KKGLinearLayout::adjustBackground(const cocos2d::Size& contentSize){ if(m_backgroundNode != nullptr){ m_backgroundNode->setContentSize(contentSize); // m_backgroundNode->setPosition(contentSize/2); } }