2#include "layout/SouiLayout.h"
3#include "helper/SplitString.h"
6#pragma warning(disable : 4985)
13 POS_INIT = 0x11000000,
14 POS_WAIT = 0x12000000,
27 return width.isMatchParent();
29 return height.isMatchParent();
43 return width.isSpecifiedSize();
45 return height.isSpecifiedSize();
59 return width.isWrapContent() || (nCount == 0 && !width.isValid());
61 return height.isWrapContent() || (nCount == 0 && !height.isValid());
72 if (orientation == Vert)
81 if (2 != swscanf(strValue, L
"%f,%f", &fx, &fy))
97 if (pos1.pit == PIT_SIZE || pos2.pit == PIT_SIZE)
124 if (strPos.
Left(4) == L
"sib.")
127 if (strPos.
Mid(4, 5) == L
"left@")
129 pos.pit = PIT_SIB_LEFT;
132 else if (strPos.
Mid(4, 6) == L
"right@")
134 pos.pit = PIT_SIB_RIGHT;
137 else if (strPos.
Mid(4, 4) == L
"top@")
139 pos.pit = PIT_SIB_TOP;
142 else if (strPos.
Mid(4, 7) == L
"bottom@")
144 pos.pit = PIT_SIB_BOTTOM;
153 if (SplitString(strValue, L
':', values) != 2)
155 pos.nRefID = _wtoi(values[0]);
158 pos.nPos = GETLAYOUTSIZE(values[1]);
160 if (pos.nPos.fSize < 0)
162 pos.nPos.fSize *= -1;
172 LPCWSTR pszPos = strPos;
175 case POSFLAG_REFCENTER:
176 pos.pit = PIT_CENTER, pszPos++;
178 case POSFLAG_PERCENT:
179 pos.pit = PIT_PERCENT, pszPos++;
181 case POSFLAG_REFPREV_NEAR:
182 pos.pit = PIT_PREV_NEAR, pszPos++;
184 case POSFLAG_REFNEXT_NEAR:
185 pos.pit = PIT_NEXT_NEAR, pszPos++;
187 case POSFLAG_REFPREV_FAR:
188 pos.pit = PIT_PREV_FAR, pszPos++;
190 case POSFLAG_REFNEXT_FAR:
191 pos.pit = PIT_NEXT_FAR, pszPos++;
194 pos.pit = PIT_SIZE, pszPos++;
197 pos.pit = PIT_NORMAL;
202 if (pszPos[0] == L
'-')
211 pos.nPos = GETLAYOUTSIZE(pszPos);
220 SplitString(strValue, L
',', strLst);
221 if (strLst.GetCount() != 2 && strLst.GetCount() != 4)
223 SSLOGW() <<
"Parse pos attribute failed, strPos=" << strValue;
227 for (
size_t i = 0; i < strLst.GetCount(); i++)
229 strLst.GetAt(i).TrimBlank();
234 if (strLst.GetCount() == 4)
238 if (bRet && nCount == 4)
240 if ((posLeft.pit == PIT_NORMAL && posLeft.nPos.isZero() && (!posTop.bMinus)) && (posRight.pit == PIT_NORMAL && posRight.nPos.isZero() && posBottom.bMinus))
242 width.setMatchParent();
244 else if (posRight.pit == PIT_SIZE)
247 width.setWrapContent();
249 width = posRight.nPos;
256 if ((posTop.pit == PIT_NORMAL && posTop.nPos.isZero() && (!posTop.bMinus)) && (posBottom.pit == PIT_NORMAL && posBottom.nPos.isZero() && posBottom.bMinus))
258 height.setMatchParent();
260 else if (posBottom.pit == PIT_SIZE)
262 if (posBottom.bMinus)
263 height.setWrapContent();
265 height = posBottom.nPos;
274 if (!width.isValid())
276 if (!height.isValid())
286 if (2 != SplitString(strValue, L
',', szStr))
297 height.setMatchParent();
299 height.setWrapContent();
301 height = GETLAYOUTSIZE(strValue);
308 width.setMatchParent();
310 width.setWrapContent();
312 width = GETLAYOUTSIZE(strValue);
318 return fabs(orientation == Vert ? fOffsetY : fOffsetX) > 0.00000001f;
321int GetPosExtra(
const POS_INFO &pos,
int nScale)
323 return pos.bMinus ? pos.nPos.
toPixelSize(nScale) : 0;
330 if (orientation == Horz)
331 return GetPosExtra(posRight, nScale);
333 return GetPosExtra(posBottom, nScale);
339 fOffsetX = fOffsetY = 0.0f;
341 width.setWrapContent();
342 height.setWrapContent();
350 width.setMatchParent();
353 height.setMatchParent();
356 width.setMatchParent();
357 height.setMatchParent();
367 width.setWrapContent();
370 height.setWrapContent();
373 width.setWrapContent();
374 height.setWrapContent();
390 width = height = layoutSize;
397 return (SouiLayoutParamStruct *)
this;
403 memcpy(pRet->
GetRawData(), (SouiLayoutParamStruct *)
this,
sizeof(SouiLayoutParamStruct));
429 return nPos == POS_INIT || nPos == POS_WAIT;
439 if (nMax != SIZE_WRAP_CONTENT)
440 nRet = pos.nPos.
toPixelSize(nScale) * (pos.bMinus ? -1 : 1) + nMax / 2;
445 if (nMax != SIZE_WRAP_CONTENT)
454 if (nMax != SIZE_WRAP_CONTENT)
456 float fPercent = pos.nPos.fSize;
459 if (fPercent > 100.0f)
462 nRet = (int)((100.0f - fPercent) * nMax / 100);
464 nRet = (int)(fPercent * nMax / 100);
470 SPOSITION positionPrev = pLstChilds->Prev(position);
474 WndPos wndPos = pLstChilds->GetAt(positionPrev);
477 if (!wndPos.bWaitOffsetX)
478 nRef = (pos.pit == PIT_PREV_NEAR) ? wndPos.rc.right : wndPos.rc.left;
482 if (!wndPos.bWaitOffsetY)
483 nRef = (pos.pit == PIT_PREV_NEAR) ? wndPos.rc.bottom : wndPos.rc.top;
491 nRet = nRef + pos.nPos.
toPixelSize(nScale) * (pos.bMinus ? -1 : 1);
497 SPOSITION positionNext = pLstChilds->Next(position);
502 WndPos wndPos = pLstChilds->GetAt(positionNext);
505 if (!wndPos.bWaitOffsetX)
506 nRef = (pos.pit == PIT_NEXT_NEAR) ? wndPos.rc.left : wndPos.rc.right;
510 if (!wndPos.bWaitOffsetY)
511 nRef = (pos.pit == PIT_NEXT_NEAR) ? wndPos.rc.top : wndPos.rc.bottom;
515 nRet = nRef + pos.nPos.
toPixelSize(nScale) * (pos.bMinus ? -1 : 1);
521 WndPos wndPos = pLstChilds->GetAt(position);
522 SASSERT(pos.nRefID > 0);
525 SPOSITION posTmp = pLstChilds->GetHeadPosition();
528 WndPos wp = pLstChilds->GetNext(posTmp);
529 if (wp.pWnd->
GetID() == pos.nRefID)
537 wndPosRef.rc = CRect(0, 0, nMax, nMax);
538 wndPosRef.bWaitOffsetX = wndPosRef.bWaitOffsetY =
false;
540 CRect rcRef = wndPosRef.rc;
544 if (!wndPosRef.bWaitOffsetX)
546 LONG refPos = (pos.pit == PIT_SIB_LEFT) ? rcRef.left : rcRef.right;
550 nRet = refPos + pos.nPos.
toPixelSize(nScale) * (pos.bMinus ? -1 : 1);
555 if (!wndPosRef.bWaitOffsetY)
557 LONG refPos = (pos.pit == PIT_SIB_TOP) ? rcRef.top : rcRef.bottom;
561 nRet = refPos + pos.nPos.
toPixelSize(nScale) * (pos.bMinus ? -1 : 1);
573 SList<WndPos> lstWndPos;
575 const IWindow *pChild = pParent->GetNextLayoutIChild(NULL);
578 if (!pChild->IsFloat() && (pChild->IsVisible(FALSE) || pChild->IsDisplay()))
581 wndPos.pWnd = (
SWindow *)pChild;
582 wndPos.rc = CRect(POS_INIT, POS_INIT, POS_INIT, POS_INIT);
586 lstWndPos.AddTail(wndPos);
588 pChild = pParent->GetNextLayoutIChild(pChild);
595 int nMaxX = 0, nMaxY = 0;
596 SPOSITION pos = lstWndPos.GetHeadPosition();
599 WndPos wndPos = lstWndPos.GetNext(pos);
601 int nScale = wndPos.pWnd->
GetScale();
604 nMaxX = smax(nMaxX, (
int)(wndPos.rc.right + pParam->
GetExtraSize(Horz, nScale)));
608 nMaxY = smax(nMaxY, (
int)(wndPos.rc.bottom + pParam->
GetExtraSize(Vert, nScale)));
616 return CSize(nWidth, nHeight);
637 for (SPOSITION pos = pListChildren->GetHeadPosition(); pos; pListChildren->GetNext(pos))
639 WndPos &wndPos = pListChildren->GetAt(pos);
643 int nWid =
IsWaitingPos(wndPos.rc.right) ? nWidth : (wndPos.rc.right - wndPos.rc.left);
644 int nHei =
IsWaitingPos(wndPos.rc.bottom) ? nHeight : (wndPos.rc.bottom - wndPos.rc.top);
649 wndPos.rc.right = wndPos.rc.left + szWnd.cx;
650 if (wndPos.bWaitOffsetX)
652 wndPos.rc.OffsetRect((
int)(wndPos.rc.Width() * pLayoutParam->fOffsetX), 0);
653 wndPos.bWaitOffsetX =
false;
659 wndPos.rc.bottom = wndPos.rc.top + szWnd.cy;
660 if (wndPos.bWaitOffsetY)
662 wndPos.rc.OffsetRect(0, (
int)(wndPos.rc.Height() * pLayoutParam->fOffsetY));
663 wndPos.bWaitOffsetY =
false;
671static const POS_INFO posRefLeft = { PIT_PREV_NEAR, -1, 1 };
672static const POS_INFO posRefTop = { PIT_PREV_FAR, -1, 1 };
676 int nResolvedAll = 0;
678 int nResolvedStep1 = 0;
679 int nResolvedStep2 = 0;
690 for (SPOSITION pos = pListChildren->GetHeadPosition(); pos; pListChildren->GetNext(pos))
692 WndPos &wndPos = pListChildren->GetAt(pos);
694 int nScale = wndPos.pWnd->
GetScale();
697 const POS_INFO &posRef = pLayoutParam->nCount >= 2 ? pLayoutParam->posLeft : posRefLeft;
698 wndPos.rc.left =
PositionItem2Value(pListChildren, pos, posRef, nWidth, TRUE, nScale);
699 if (wndPos.rc.left != POS_WAIT)
704 const POS_INFO &posRef = pLayoutParam->nCount >= 2 ? pLayoutParam->posTop : posRefTop;
705 wndPos.rc.top =
PositionItem2Value(pListChildren, pos, posRef, nHeight, FALSE, nScale);
706 if (wndPos.rc.top != POS_WAIT)
713 wndPos.rc.right = nWidth;
723 else if (!pLayoutParam->
IsWrapContent(Horz) && pLayoutParam->nCount == 4)
725 wndPos.rc.right =
PositionItem2Value(pListChildren, pos, pLayoutParam->posRight, nWidth, TRUE, nScale);
726 if (wndPos.rc.right != POS_WAIT)
734 wndPos.rc.bottom = nHeight;
744 else if (!pLayoutParam->
IsWrapContent(Vert) && pLayoutParam->nCount == 4)
746 wndPos.rc.bottom =
PositionItem2Value(pListChildren, pos, pLayoutParam->posBottom, nHeight, FALSE, nScale);
747 if (wndPos.rc.bottom != POS_WAIT)
753 nResolvedStep1 += nResolved;
756 if (nResolvedStep1 > 0)
763 for (SPOSITION pos = pListChildren->GetHeadPosition(); pos; pListChildren->GetNext(pos))
765 WndPos &wndPos = pListChildren->GetAt(pos);
772 int nWid =
IsWaitingPos(wndPos.rc.right) ? nWidth : (wndPos.rc.right - wndPos.rc.left);
773 int nHei =
IsWaitingPos(wndPos.rc.bottom) ? nHeight : (wndPos.rc.bottom - wndPos.rc.top);
778 wndPos.rc.right = wndPos.rc.left + szWnd.cx;
783 wndPos.rc.bottom = wndPos.rc.top + szWnd.cy;
787 if (!
IsWaitingPos(wndPos.rc.right) && wndPos.bWaitOffsetX)
789 wndPos.rc.OffsetRect((
int)(wndPos.rc.Width() * pLayoutParam->fOffsetX), 0);
790 wndPos.bWaitOffsetX =
false;
792 if (!
IsWaitingPos(wndPos.rc.bottom) && wndPos.bWaitOffsetY)
794 wndPos.rc.OffsetRect(0, (
int)(wndPos.rc.Height() * pLayoutParam->fOffsetY));
795 wndPos.bWaitOffsetY =
false;
798 nResolvedStep2 += nResolved;
802 nResolvedAll += nResolvedStep1 + nResolvedStep2;
803 }
while (nResolvedStep2 || nResolvedStep1);
810 SList<WndPos> lstWndPos;
812 IWindow *pChild = pParent->GetNextLayoutIChild(NULL);
816 wndPos.pWnd = (
SWindow *)pChild;
817 wndPos.rc = CRect(POS_INIT, POS_INIT, POS_INIT, POS_INIT);
821 lstWndPos.AddTail(wndPos);
823 pChild = pParent->GetNextLayoutIChild(pChild);
826 if (lstWndPos.IsEmpty())
830 pParent->GetChildrenLayoutRect(&rcParent);
832 CalcPostion(&lstWndPos, rcParent.Width(), rcParent.Height());
835 SPOSITION pos = lstWndPos.GetHeadPosition();
838 WndPos wp = lstWndPos.GetNext(pos);
839 wp.rc.OffsetRect(rcParent.TopLeft());
int toPixelSize(int scale) const
将大小转换为像素值
int GetID() SCONST OVERRIDE
Retrieves the object's ID.
static LPCWSTR GetClassName()
A class representing an ASCII string.
int CompareNoCase(const wchar_t *psz) SCONST
Compares the string with another string, ignoring case.
BOOL IsEmpty() SCONST
Checks if the string is empty.
SStringW Mid(int nFirst) const
Extracts a substring from the string.
SStringW Left(int nCount) const
Extracts the leftmost part of the string.
Base class for SOUI DUI windows.
void GetDesiredSize(SIZE *psz, int nParentWid, int nParentHei) OVERRIDE
Retrieves the desired size of the window.
int GetScale() SCONST OVERRIDE
Retrieves the scale factor of the window.
virtual BOOL OnRelayout(const CRect &rcWnd)
Handles window position changes during layout updates.
ILayoutParam * GetLayoutParam() SCONST OVERRIDE
Retrieves the layout parameter object associated with the window.
void CalcPositionEx(SList< WndPos > *pListChildren, int nWidth, int nHeight) const
计算扩展位置
BOOL IsParamAcceptable(const ILayoutParam *pLayoutParam) SCONST OVERRIDE
检查布局参数是否可接受
int PositionItem2Value(SList< WndPos > *pLstChilds, SPOSITION position, const POS_INFO &pos, int nMax, BOOL bX, int nScale) const
将位置项转换为值
SIZE MeasureChildren(const IWindow *pParent, int nWidth, int nHeight) SCONST OVERRIDE
测量子窗口大小
int CalcPostion(SList< WndPos > *pListChildren, int nWidth, int nHeight) const
计算位置
ILayoutParam * CreateLayoutParam() SCONST OVERRIDE
创建布局参数对象
BOOL IsWaitingPos(int nPos) const
检查位置是否等待
void LayoutChildren(IWindow *pParent) OVERRIDE
布局子窗口
ILayoutParam * Clone() SCONST OVERRIDE
克隆布局参数
BOOL IsSpecifiedSize(ORIENTATION orientation) SCONST OVERRIDE
检查是否指定大小
BOOL ParsePosition12(const SStringW &pos1, const SStringW &pos2)
解析在pos中定义的前两个位置
void SetSpecifiedSize(ORIENTATION orientation, const SLayoutSize &layoutSize) OVERRIDE
设置指定大小
HRESULT OnAttrPos(const SStringW &strValue, BOOL bLoading)
处理位置属性
HRESULT OnAttrSize(const SStringW &strValue, BOOL bLoading)
处理大小属性
BOOL StrPos2ItemPos(const SStringW &strPos, POS_INFO &posItem)
将字符串描述的坐标转换成POSITION_ITEM
HRESULT OnAttrWidth(const SStringW &strValue, BOOL bLoading)
处理宽度属性
void Clear() OVERRIDE
清除布局参数
void * GetRawData() OVERRIDE
获取原始数据指针
SLayoutSize GetSpecifiedSize(ORIENTATION orientation) SCONST OVERRIDE
获取指定大小
int GetExtraSize(ORIENTATION orientation, int nScale) const
获取额外大小
HRESULT OnAttrHeight(const SStringW &strValue, BOOL bLoading)
处理高度属性
BOOL IsWrapContent(ORIENTATION orientation) SCONST OVERRIDE
检查是否包裹内容大小
void SetMatchParent(ORIENTATION orientation) OVERRIDE
设置匹配父容器大小
bool IsOffsetRequired(ORIENTATION orientation) const
检查是否需要偏移
BOOL ParsePosition34(const SStringW &pos3, const SStringW &pos4)
解析在pos中定义的后两个位置
HRESULT OnAttrOffset(const SStringW &strValue, BOOL bLoading)
处理偏移属性
void SetWrapContent(ORIENTATION orientation) OVERRIDE
设置包裹内容大小
BOOL IsMatchParent(ORIENTATION orientation) SCONST OVERRIDE
检查是否匹配父容器大小