前面幾篇主要介紹了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
好漫長啊!爲什麼?