MyGui笔记(3)控件对齐方式和所在层

前篇:《MyGui笔记(2)控件类型和皮肤》
本篇:创建控件的方法要传入控件对齐方式,创建根控件还需传入将被创建到哪一层的名称。
环境:MyGui3.2.0(OpenGL平台)

控件对齐方式        

        控件的对齐方式,定义在Align里面,所定义的方式如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum Enum
{
    HCenter = MYGUI_FLAG_NONE,  /**< 水平居中 */
    VCenter = MYGUI_FLAG_NONE,  /**< 垂直居中 */
    Center = HCenter | VCenter,  /**< 中心居中 */

    Left = MYGUI_FLAG( 1),  /**< 居左 (并且垂直居中) */
    Right = MYGUI_FLAG( 2),  /**< 居右 (并且垂直居中) */
    HStretch = Left | Right,  /**< 按与父窗口的比例进行水平拉伸 (并且垂直居中) */

    Top = MYGUI_FLAG( 3),  /**< 居上 (并且水平居中) */
    Bottom = MYGUI_FLAG( 4),  /**< 居下 (并且水平居中) */
    VStretch = Top | Bottom,  /**< 按与父窗口的比例进行垂直拉伸 (并且水平居中) */

    Stretch = HStretch | VStretch,  /**< 按与父窗口的比例进行拉伸 */
    Default = Left | Top  /**< 默认值 (居左和居上) */
};

并不仅这些方式,还可以自己进行组合,如: 

1
2
Left | VStretch       /**< 居左和按与父窗口的比例进行垂直拉伸 */    
HStretch | Bottom     /**< 按与父窗口的比例进行水平拉伸和居下 */

每当父窗口进行位置或者大小改变,都会对其子控件进行重新计算位置和大小,代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//_oldsize 父控件旧的大小
//_newSize 父控件新的大小
void Widget::_setAlign( const IntSize& _oldsize,  const IntSize& _newSize)
{
     const IntSize& size = _newSize; //getParentSize();

     bool need_move =  false;
     bool need_size =  false;
    IntCoord coord = mCoord;

     // 对齐方式
     if (mAlign.isHStretch())
    {
         // 拉伸
        coord.width = mCoord.width + (size.width - _oldsize.width);
        need_size =  true;
    }
     else  if (mAlign.isRight())
    {
         // 向右移动
        coord.left = mCoord.left + (size.width - _oldsize.width);
        need_move =  true;
    }
     else  if (mAlign.isHCenter())
    {
         // 没有拉伸的水平对齐
        coord.left = (size.width - mCoord.width) /  2;
        need_move =  true;
    }

     if (mAlign.isVStretch())
    {
         // 拉伸
        coord.height = mCoord.height + (size.height - _oldsize.height);
        need_size =  true;
    }
     else  if (mAlign.isBottom())
    {
         // 向下移动
        coord.top = mCoord.top + (size.height - _oldsize.height);
        need_move =  true;
    }
     else  if (mAlign.isVCenter())
    {
         // 没有拉伸的垂直居中
        coord.top = (size.height - mCoord.height) /  2;
        need_move =  true;
    }

     if (need_move)
    {
         if (need_size)
            setCoord(coord);
         else
            setPosition(coord.point());
    }
     else  if (need_size)
    {
        setSize(coord.size());
    }
     else
    {
        _updateView();  // 无需移动和改变大小
    }
}

 控件所在层

        每个根控件创建的时候,需要指定其所在层,所有的层定义在MyGUI_Layers.xml文件,这个文件内容为: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version= "1.0"  encoding= "UTF-8" ?>
<MyGUI type= "Layer"  version= "1.2" >
     <Layer type= "SharedLayer"  name= "Wallpaper" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "SharedLayer"  name= "Back" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "OverlappedLayer"  name= "Overlapped" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "SharedLayer"  name= "Middle" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "OverlappedLayer"  name= "Modal" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "SharedLayer"  name= "Main" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "OverlappedLayer"  name= "Popup" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "SharedLayer"  name= "FadeMiddle" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "OverlappedLayer"  name= "Info" >
         <Property key= "Pick"  value= "true" />
     </Layer>
     <Layer type= "SharedLayer"  name= "ToolTip" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "SharedLayer"  name= "DragAndDrop" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "SharedLayer"  name= "FadeBusy" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "SharedLayer"  name= "Pointer" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "SharedLayer"  name= "Fade" >
         <Property key= "Pick"  value= "false" />
     </Layer>
     <Layer type= "SharedLayer"  name= "Statistic" >
         <Property key= "Pick"  value= "false" />
     </Layer>
</MyGUI>

可以看到层类型分为两种:SharedLayerOverlappedLayer

  • SharedLayer :SharedLayer为简单无重叠的层,重叠的控件可能会出现绘制顺序不正确,整个SharedLayer在一个批次中进行渲染。

  • OverlappedLayer :当在一个层(例如:窗口)中含有重叠的控件,那么应该使用OverlappedLayer 。每个根控件进行批次渲染,所以如果层上的控件没有打算进行彼此重叠的话,那么使用SharedLayer。

层的名称标识符,用在皮肤、布局和代码里。Pick属性设置控件是否能够响应鼠标消息,如果设置为false,鼠标指针会忽略这个层上的所有控件,直接穿透到下一层。创建根控件调用代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
Widget* Gui::baseCreateWidget(WidgetStyle _style,  const std::string& _type,  const std::string& _skin,  const IntCoord& _coord, Align _align,  const std::string& _layer,  const std::string& _name)
{
    Widget* widget = WidgetManager::getInstance().createWidget(_style, _type, _skin, _coord,  /*_align, */nullptr, nullptr, _name);
    mWidgetChild.push_back(widget);

    widget->setAlign(_align);

     // 附加控件到层上
     if (!_layer.empty())
        LayerManager::getInstance().attachToLayerNode(_layer, widget);
     return widget;
}

层管理器LayerManager负责将控件添加到相应的层上,attachToLayerNode代码为: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void LayerManager::attachToLayerNode( const std::string& _name, Widget* _item)
{
    MYGUI_ASSERT(nullptr != _item,  "pointer must be valid");
    MYGUI_ASSERT(_item->isRootWidget(),  "attached widget must be root");

     // 从原先的层分离
    _item->detachFromLayer();

     // 附加到新的层上
     for (VectorLayer::iterator iter = mLayerNodes.begin(); iter != mLayerNodes.end(); ++iter)
    {
         if (_name == (*iter)->getName())
        {
            ILayerNode* node = (*iter)->createChildItemNode();
            node->attachLayerItem(_item);

             return;
        }
    }
    MYGUI_LOG(Error,  "Layer '" << _name <<  "' is not found");
     //MYGUI_EXCEPT("Layer '" << _name << "' is not found");
}

可以看到限制了控件必须为根控件,如果控件原先有附加到其他层上,则必须先分离。接着遍历mLayerNodes,它存储着MyGUI_Layers.xml里面所有的层信息,找到对应的层名称,根据相应的层类型来创建一个子节点,将控件添加到这个子节点上。代码如下: 

1
2
3
4
5
6
7
void LayerNode::attachLayerItem(ILayerItem* _item)
{
    mLayerItems.push_back(_item);
    _item->attachItemToNode(mLayer,  this);

    mOutOfDate =  true;
}

可以看到这个控件加入到mLayerItems列表里面,mLayerItems存放着所有的控件指针,对于重叠层来说,这里面只存放一个。接着控件调用attachItemToNode方法,这个方法代码如下: 

1
2
3
4
5
6
7
void LayerItem::attachItemToNode(ILayer* _layer, ILayerNode* _node)
{
    mLayer = _layer;
    mLayerNode = _node;

    attachToLayerItemNode(_node,  true);
}

继续调用方法attachToLayerItemNode,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void LayerItem::attachToLayerItemNode(ILayerNode* _item,  bool _deep)
{
    MYGUI_DEBUG_ASSERT(nullptr != _item,  "attached item must be valid");

    mLayerNode = _item;

     for (VectorSubWidget::iterator skin = mDrawItems.begin(); skin != mDrawItems.end(); ++skin)
    {
        (*skin)->createDrawItem(mTexture, _item);
    }

     for (VectorLayerItem::iterator item = mLayerItems.begin(); item != mLayerItems.end(); ++item)
    {
        (*item)->attachToLayerItemNode(_item, _deep);
    }

     for (VectorLayerItem::iterator item = mLayerNodes.begin(); item != mLayerNodes.end(); ++item)
    {
         if (_deep)
        {
            ILayerNode* child_node = _item->createChildItemNode();
            (*item)->attachToLayerItemNode(child_node, _deep);
        }
    }
}
下一篇继续......

更多资料:
1.MyGUI layers  http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MyGUI+layers

 

你可能感兴趣的:(MyGui笔记(3)控件对齐方式和所在层)