axmol/extensions/fairygui/GRoot.cpp

570 lines
13 KiB
C++

#include "GRoot.h"
#include "AudioEngine.h"
#include "UIConfig.h"
#include "UIPackage.h"
NS_FGUI_BEGIN
USING_NS_CC;
#if COCOS2D_VERSION < 0x00040000
using namespace cocos2d::experimental;
#endif
GRoot* GRoot::_inst = nullptr;
bool GRoot::_soundEnabled = true;
float GRoot::_soundVolumeScale = 1.0f;
int GRoot::contentScaleLevel = 0;
GRoot* GRoot::create(Scene* scene, int zOrder)
{
GRoot* pRet = new (std::nothrow) GRoot();
if (pRet && pRet->initWithScene(scene, zOrder))
{
pRet->autorelease();
return pRet;
}
else
{
delete pRet;
pRet = nullptr;
return nullptr;
}
}
GRoot::GRoot() : _windowSizeListener(nullptr),
_inputProcessor(nullptr),
_modalLayer(nullptr),
_modalWaitPane(nullptr),
_tooltipWin(nullptr),
_defaultTooltipWin(nullptr)
{
}
GRoot::~GRoot()
{
delete _inputProcessor;
CC_SAFE_RELEASE(_modalWaitPane);
CC_SAFE_RELEASE(_defaultTooltipWin);
CC_SAFE_RELEASE(_modalLayer);
CALL_LATER_CANCEL(GRoot, doShowTooltipsWin);
if (_windowSizeListener)
Director::getInstance()->getEventDispatcher()->removeEventListener(_windowSizeListener);
}
void GRoot::showWindow(Window* win)
{
addChild(win);
adjustModalLayer();
}
void GRoot::hideWindow(Window* win)
{
win->hide();
}
void GRoot::hideWindowImmediately(Window* win)
{
if (win->getParent() == this)
removeChild(win);
adjustModalLayer();
}
void GRoot::bringToFront(Window* win)
{
int cnt = numChildren();
int i;
if (_modalLayer->getParent() != nullptr && !win->isModal())
i = getChildIndex(_modalLayer) - 1;
else
i = cnt - 1;
for (; i >= 0; i--)
{
GObject* g = getChildAt(i);
if (g == win)
return;
if (dynamic_cast<Window*>(g))
break;
}
if (i >= 0)
setChildIndex(win, i);
}
void GRoot::closeAllExceptModals()
{
Vector<GObject*> map(_children);
for (const auto& child : map)
{
if (dynamic_cast<Window*>(child) && !((Window*)child)->isModal())
hideWindowImmediately((Window*)child);
}
}
void GRoot::closeAllWindows()
{
Vector<GObject*> map(_children);
for (const auto& child : map)
{
if (dynamic_cast<Window*>(child))
hideWindowImmediately((Window*)child);
}
}
Window* GRoot::getTopWindow()
{
int cnt = numChildren();
for (int i = cnt - 1; i >= 0; i--)
{
GObject* child = getChildAt(i);
if (dynamic_cast<Window*>(child))
{
return (Window*)child;
}
}
return nullptr;
}
GGraph* GRoot::getModalLayer()
{
if (_modalLayer == nullptr)
createModalLayer();
return _modalLayer;
}
void GRoot::createModalLayer()
{
_modalLayer = GGraph::create();
_modalLayer->retain();
_modalLayer->drawRect(getWidth(), getHeight(), 0, Color4F::WHITE, UIConfig::modalLayerColor);
_modalLayer->addRelation(this, RelationType::Size);
}
void GRoot::adjustModalLayer()
{
if (_modalLayer == nullptr)
createModalLayer();
int cnt = numChildren();
if (_modalWaitPane != nullptr && _modalWaitPane->getParent() != nullptr)
setChildIndex(_modalWaitPane, cnt - 1);
for (int i = cnt - 1; i >= 0; i--)
{
GObject* child = getChildAt(i);
if (dynamic_cast<Window*>(child) && ((Window*)child)->isModal())
{
if (_modalLayer->getParent() == nullptr)
addChildAt(_modalLayer, i);
else
setChildIndexBefore(_modalLayer, i);
return;
}
}
if (_modalLayer->getParent() != nullptr)
removeChild(_modalLayer);
}
bool GRoot::hasModalWindow()
{
return _modalLayer != nullptr && _modalLayer->getParent() != nullptr;
}
void GRoot::showModalWait()
{
getModalWaitingPane();
if (_modalWaitPane)
addChild(_modalWaitPane);
}
void GRoot::closeModalWait()
{
if (_modalWaitPane != nullptr && _modalWaitPane->getParent() != nullptr)
removeChild(_modalWaitPane);
}
GObject* GRoot::getModalWaitingPane()
{
if (!UIConfig::globalModalWaiting.empty())
{
if (_modalWaitPane == nullptr)
{
_modalWaitPane = UIPackage::createObjectFromURL(UIConfig::globalModalWaiting);
_modalWaitPane->setSortingOrder(INT_MAX);
_modalWaitPane->retain();
}
_modalWaitPane->setSize(getWidth(), getHeight());
_modalWaitPane->addRelation(this, RelationType::Size);
return _modalWaitPane;
}
else
return nullptr;
}
bool GRoot::isModalWaiting()
{
return (_modalWaitPane != nullptr) && _modalWaitPane->onStage();
}
cocos2d::Vec2 GRoot::getTouchPosition(int touchId)
{
return _inputProcessor->getTouchPosition(touchId);
}
GObject* GRoot::getTouchTarget()
{
return _inputProcessor->getRecentInput()->getTarget();
}
cocos2d::Vec2 GRoot::worldToRoot(const cocos2d::Vec2 &pt)
{
cocos2d::Vec2 pos = _displayObject->convertToNodeSpace(pt);
pos.y = getHeight() - pos.y;
return pos;
}
cocos2d::Vec2 GRoot::rootToWorld(const cocos2d::Vec2 &pt)
{
cocos2d::Vec2 pos = pt;
pos.y = getHeight() - pos.y;
pos = _displayObject->convertToWorldSpace(pos);
return pos;
}
void GRoot::showPopup(GObject* popup)
{
showPopup(popup, nullptr, PopupDirection::AUTO);
}
void GRoot::showPopup(GObject* popup, GObject* target, PopupDirection dir)
{
if (!_popupStack.empty())
hidePopup(popup);
_popupStack.push_back(WeakPtr(popup));
if (target != nullptr)
{
GObject* p = target;
while (p != nullptr)
{
if (p->getParent() == this)
{
if (popup->getSortingOrder() < p->getSortingOrder())
{
popup->setSortingOrder(p->getSortingOrder());
}
break;
}
p = p->getParent();
}
}
addChild(popup);
adjustModalLayer();
if (dynamic_cast<Window*>(popup) && target == nullptr && dir == PopupDirection::AUTO)
return;
Vec2 pos = getPoupPosition(popup, target, dir);
popup->setPosition(pos.x, pos.y);
}
void GRoot::togglePopup(GObject* popup)
{
togglePopup(popup, nullptr, PopupDirection::AUTO);
}
void GRoot::togglePopup(GObject* popup, GObject* target, PopupDirection dir)
{
if (std::find(_justClosedPopups.cbegin(), _justClosedPopups.cend(), popup) != _justClosedPopups.cend())
return;
showPopup(popup, target, dir);
}
void GRoot::hidePopup()
{
hidePopup(nullptr);
}
void GRoot::hidePopup(GObject* popup)
{
if (popup != nullptr)
{
auto it = std::find(_popupStack.cbegin(), _popupStack.cend(), popup);
if (it != _popupStack.cend())
{
int k = (int)(it - _popupStack.cbegin());
for (int i = (int)_popupStack.size() - 1; i >= k; i--)
{
closePopup(_popupStack.back().ptr());
_popupStack.pop_back();
}
}
}
else
{
for (const auto& it : _popupStack)
closePopup(it.ptr());
_popupStack.clear();
}
}
void GRoot::closePopup(GObject* target)
{
if (target && target->getParent() != nullptr)
{
if (dynamic_cast<Window*>(target))
((Window*)target)->hide();
else
removeChild(target);
}
}
void GRoot::checkPopups()
{
_justClosedPopups.clear();
if (!_popupStack.empty())
{
GObject* mc = _inputProcessor->getRecentInput()->getTarget();
bool handled = false;
while (mc != this && mc != nullptr)
{
auto it = std::find(_popupStack.cbegin(), _popupStack.cend(), mc);
if (it != _popupStack.cend())
{
int k = (int)(it - _popupStack.cbegin());
for (int i = (int)_popupStack.size() - 1; i > k; i--)
{
closePopup(_popupStack.back().ptr());
_popupStack.pop_back();
}
handled = true;
break;
}
mc = mc->findParent();
}
if (!handled)
{
for (int i = (int)_popupStack.size() - 1; i >= 0; i--)
{
GObject* popup = _popupStack[i].ptr();
if (popup)
{
_justClosedPopups.push_back(WeakPtr(popup));
closePopup(popup);
}
}
_popupStack.clear();
}
}
}
bool GRoot::hasAnyPopup()
{
return !_popupStack.empty();
}
cocos2d::Vec2 GRoot::getPoupPosition(GObject* popup, GObject* target, PopupDirection dir)
{
Vec2 pos;
Vec2 size;
if (target != nullptr)
{
pos = target->localToGlobal(Vec2::ZERO);
pos = this->globalToLocal(pos);
size = target->localToGlobal(target->getSize());
size = this->globalToLocal(size);
size -= pos;
}
else
{
pos = globalToLocal(_inputProcessor->getRecentInput()->getPosition());
}
float xx, yy;
xx = pos.x;
if (xx + popup->getWidth() > getWidth())
xx = xx + size.x - popup->getWidth();
yy = pos.y + size.y;
if ((dir == PopupDirection::AUTO && yy + popup->getHeight() > getHeight()) || dir == PopupDirection::UP)
{
yy = pos.y - popup->getHeight() - 1;
if (yy < 0)
{
yy = 0;
xx += size.x / 2;
}
}
return Vec2(round(xx), round(yy));
}
void GRoot::showTooltips(const std::string& msg)
{
if (_defaultTooltipWin == nullptr)
{
const std::string& resourceURL = UIConfig::tooltipsWin;
if (resourceURL.empty())
{
CCLOGWARN("FairyGUI: UIConfig.tooltipsWin not defined");
return;
}
_defaultTooltipWin = UIPackage::createObjectFromURL(resourceURL);
_defaultTooltipWin->setTouchable(false);
_defaultTooltipWin->retain();
}
_defaultTooltipWin->setText(msg);
showTooltipsWin(_defaultTooltipWin);
}
void GRoot::showTooltipsWin(GObject* tooltipWin)
{
hideTooltips();
_tooltipWin = tooltipWin;
CALL_LATER(GRoot, doShowTooltipsWin, 0.1f);
}
void GRoot::doShowTooltipsWin()
{
if (_tooltipWin == nullptr)
return;
Vec2 pt = _inputProcessor->getRecentInput()->getPosition();
float xx = pt.x + 10;
float yy = pt.y + 20;
pt = globalToLocal(Vec2(xx, yy));
xx = pt.x;
yy = pt.y;
if (xx + _tooltipWin->getWidth() > getWidth())
xx = xx - _tooltipWin->getWidth();
if (yy + _tooltipWin->getHeight() > getHeight())
{
yy = yy - _tooltipWin->getHeight() - 1;
if (yy < 0)
yy = 0;
}
_tooltipWin->setPosition(round(xx), round(yy));
addChild(_tooltipWin);
}
void GRoot::hideTooltips()
{
if (_tooltipWin != nullptr)
{
if (_tooltipWin->getParent() != nullptr)
removeChild(_tooltipWin);
_tooltipWin = nullptr;
}
}
void GRoot::playSound(const std::string& url, float volumnScale)
{
if (!_soundEnabled)
return;
PackageItem* pi = UIPackage::getItemByURL(url);
if (pi)
AudioEngine::play2d(pi->file, false, _soundVolumeScale * volumnScale);
}
void GRoot::setSoundEnabled(bool value)
{
_soundEnabled = value;
}
void GRoot::setSoundVolumeScale(float value)
{
_soundVolumeScale = value;
}
void GRoot::onTouchEvent(int eventType)
{
if (eventType == UIEventType::TouchBegin)
{
if (_tooltipWin != nullptr)
hideTooltips();
checkPopups();
}
}
void GRoot::handlePositionChanged()
{
_displayObject->setPosition(0, _size.height);
}
void GRoot::onEnter()
{
GComponent::onEnter();
_inst = this;
}
void GRoot::onExit()
{
GComponent::onExit();
if (_inst == this)
_inst = nullptr;
}
bool GRoot::initWithScene(cocos2d::Scene* scene, int zOrder)
{
if (!GComponent::init())
return false;
if (_inst == nullptr)
_inst = this;
_inputProcessor = new InputProcessor(this);
_inputProcessor->setCaptureCallback(CC_CALLBACK_1(GRoot::onTouchEvent, this));
#ifdef CC_PLATFORM_PC
_windowSizeListener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(GLViewImpl::EVENT_WINDOW_RESIZED, CC_CALLBACK_0(GRoot::onWindowSizeChanged, this));
#endif
onWindowSizeChanged();
scene->addChild(_displayObject, zOrder);
return true;
}
void GRoot::onWindowSizeChanged()
{
const cocos2d::Size& rs = Director::getInstance()->getOpenGLView()->getDesignResolutionSize();
setSize(rs.width, rs.height);
updateContentScaleLevel();
}
void GRoot::updateContentScaleLevel()
{
float ss = Director::getInstance()->getContentScaleFactor();
if (ss >= 3.5f)
contentScaleLevel = 3; //x4
else if (ss >= 2.5f)
contentScaleLevel = 2; //x3
else if (ss >= 1.5f)
contentScaleLevel = 1; //x2
else
contentScaleLevel = 0;
}
NS_FGUI_END