前面几篇主要介绍了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
好漫长啊!为什么?