前面几篇主要介绍了MyGUI类的静态关系,还有一些粗糙的分析。
先看下关于Widget关于Inputmanager
注入鼠标移动事件时一些列流程。
bool InputManager::injectMouseMove(int _absx, int _absy, int _absz)
{
// запоминаем позицию
mMousePosition.set(_absx, _absy);
// вычисляем прирост по колеса
int relz = _absz - mOldAbsZ;
mOldAbsZ = _absz;
// проверка на скролл
if (relz != 0)
{
bool isFocus = isFocusMouse();
if (mWidgetMouseFocus != nullptr) mWidgetMouseFocus->onMouseWheel(relz);
return isFocus;
}
if (mIsWidgetMouseCapture)
{
if (mWidgetMouseFocus != nullptr)
{
if (mLayerMouseFocus != nullptr)
{
IntPoint point = mLayerMouseFocus->getPosition(_absx, _absy);
mWidgetMouseFocus->onMouseDrag(point.left, point.top);
}
}
else
mIsWidgetMouseCapture = false;
return true;
}
Widget* old_mouse_focus = mWidgetMouseFocus;
// ищем активное окно
Widget* item = LayerManager::getInstance().getWidgetFromPoint(_absx, _absy);
// ничего не изменилось
if (mWidgetMouseFocus == item)
{
bool isFocus = isFocusMouse();
if (mWidgetMouseFocus != nullptr)
{
if (mLayerMouseFocus != nullptr)
{
IntPoint point = mLayerMouseFocus->getPosition(_absx, _absy); 获取鼠标focus点-〉ILayer-〉ILayerItem-〉ILayerItem-〉Widget
mWidgetMouseFocus->onMouseMove(_absx, _absy);
}
}
return isFocus;
}
if (item)
{
// поднимаемся до рута
Widget* root = item;
while (root->getParent()) root = root->getParent();
// проверяем на модальность
if (!mVectorModalRootWidget.empty())
{
if (root != mVectorModalRootWidget.back())
{
item = nullptr;
}
}
if (item != nullptr)
{
mLayerMouseFocus = root->getLayer();
}
}
// в методе может пропасть наш виджет
WidgetManager::getInstance().addWidgetToUnlink(item);
//-------------------------------------------------------------------------------------//
// новый вид рутового фокуса мыши
Widget* save_widget = nullptr;
// спускаемся по новому виджету и устанавливаем рутовый фокус
Widget* root_focus = item;
while (root_focus != nullptr)
{
if (root_focus->mRootMouseActive)
{
save_widget = root_focus;
break;
}
root_focus->mRootMouseActive = true;
// в методе может пропасть наш виджет
WidgetManager::getInstance().addWidgetToUnlink(root_focus);
root_focus->onMouseChangeRootFocus(true);
WidgetManager::getInstance().removeWidgetFromUnlink(root_focus);
if (root_focus)
root_focus = root_focus->getParent();
}
// спускаемся по старому виджету и сбрасываем фокус
root_focus = mWidgetMouseFocus;
while (root_focus != nullptr)
{
if (root_focus == save_widget)
{
break;
}
root_focus->mRootMouseActive = false;
// в методе может пропасть наш виджет
WidgetManager::getInstance().addWidgetToUnlink(root_focus);
root_focus->onMouseChangeRootFocus(false);
WidgetManager::getInstance().removeWidgetFromUnlink(root_focus);
if (root_focus)
root_focus = root_focus->getParent();
}
//-------------------------------------------------------------------------------------//
// смена фокуса, проверяем на доступность виджета
if ((mWidgetMouseFocus != nullptr) && (mWidgetMouseFocus->isEnabled()))
{
mWidgetMouseFocus->onMouseLostFocus(item);
}
WidgetManager::getInstance().removeWidgetFromUnlink(item);
if ((item != nullptr) && (item->isEnabled()))
{
item->onMouseMove(_absx, _absy);
item->onMouseSetFocus(mWidgetMouseFocus);
}
// запоминаем текущее окно
mWidgetMouseFocus = item;
if (old_mouse_focus != mWidgetMouseFocus)
eventChangeMouseFocus(mWidgetMouseFocus);
return isFocusMouse();
}
分析点一:LayerManager
层的概念在这里运用:
第一步找出大的层位置:
LayerManager
Widget* LayerManager::getWidgetFromPoint(int _left, int _top)
{
VectorLayer::reverse_iterator iter = mLayerNodes.rbegin();
while (iter != mLayerNodes.rend())
{
ILayerItem * item = (*iter)->getLayerItemByPoint(_left, _top);
if (item != nullptr) return static_cast<Widget*>(item);
++iter;
}
return nullptr;
}
分析点二:ILayerItem
找到对应的ILayerItem
Widget* LayerManager::getWidgetFromPoint(int _left, int _top)
{
VectorLayer::reverse_iterator iter = mLayerNodes.rbegin();
while (iter != mLayerNodes.rend())
{
ILayerItem * item = (*iter)->getLayerItemByPoint(_left, _top);
if (item != nullptr) return static_cast<Widget*>(item);
++iter;
}
return nullptr;
}
分析点三:LayerNode
Widget的子节点放入LayerNode中进行子节点的查询操作
这一招MyGUI用的已经很纯熟,因为每次的WidgetFocus只可能是不可分割的一部分,原子级的。
所以MyGUI 遍历子节点查询自己的焦点所在。
注意:第一个for的作用和第二个for的作用是不同的。
第一个for的作用就是用作遍历子节点,而第二个是查找子节点的Item
ILayerItem* LayerNode::getLayerItemByPoint(int _left, int _top)
{
// сначала пикаем детей
for (VectorILayerNode::iterator iter = mChildItems.begin(); iter!=mChildItems.end(); ++iter)
{
ILayerItem * item = (*iter)->getLayerItemByPoint(_left, _top);
if (nullptr != item) return item;
}
for (VectorLayerItem::iterator iter=mLayerItems.begin(); iter!=mLayerItems.end(); ++iter)
{
ILayerItem * item = (*iter)->getLayerItemByPoint(_left, _top);
if (nullptr != item) return item;
}
return nullptr;
}
分析点四:
最终实现 IlayerItem 的 getLayerItemByPoint 接口
LayerItem 是一个虚类,因为其没有实现 IlayerItem 接口
是Widget实现的。
而Widget 的方法与LayerNode 中找焦点的办法一样
同样的两个for,同样的回调本身
这应该算是递归吧,;)(本人基础的问题!)
ILayerItem * Widget::getLayerItemByPoint(int _left, int _top)
{
// проверяем попадание
if (!mSubSkinsVisible
|| !mEnabled
|| !mVisible
|| (!mNeedMouseFocus && !mInheritsPick)
|| !_checkPoint(_left, _top)
// если есть маска, проверяем еще и по маске
|| ((!mMaskPickInfo->empty()) && (!mMaskPickInfo->pick(IntPoint(_left - mCoord.left, _top - mCoord.top), mCoord))))
return nullptr;
// спрашиваем у детишек
for (VectorWidgetPtr::reverse_iterator widget= mWidgetChild.rbegin(); widget != mWidgetChild.rend(); ++widget)
{
// общаемся только с послушными детьми
if ((*widget)->mWidgetStyle == WidgetStyle::Popup) continue;
ILayerItem * item = (*widget)->getLayerItemByPoint(_left - mCoord.left, _top - mCoord.top);
if (item != nullptr) return item;
}
// спрашиваем у детишек скна
for (VectorWidgetPtr::reverse_iterator widget= mWidgetChildSkin.rbegin(); widget != mWidgetChildSkin.rend(); ++widget)
{
ILayerItem * item = (*widget)->getLayerItemByPoint(_left - mCoord.left, _top - mCoord.top);
if (item != nullptr) return item;
}
// непослушные дети
return mInheritsPick ? nullptr : this;
}
经过四层传回move所聚焦的Widget
好漫长啊!为什么?