📄 layout.pas
字号:
PtChild.afMetric[Integer(lpHEIGHT)] := UNKNOWN;
Layout_SolveChild(PtChild);
Inc(PtChild); // 指向下一个TChild
// 添加各控件信息到TChild列表
hWnd := GetTopWindow(hWndParent);
while IsWindow(hWnd) do
begin
// 取控件ID和位置
PtChild.idc := GetDlgCtrlID(hWnd);
GetWindowRect(hWnd, PtChild.Rc);
MapWindowPoints(HWND_DESKTOP, hWndParent, PtChild.Rc, 2);
for J := 0 to NUMSIDES do PtChild.afMetric[J] := KNOWN;
// 计算宽度和高度
PtChild.afMetric[Integer(lpWIDTH)] := UNKNOWN;
PtChild.afMetric[Integer(lpHEIGHT)] := UNKNOWN;
Layout_SolveChild(PtChild);
// 最初都设为'固定的'
PtChild.fFixed := TRUE;
// 指向下一个TChild
Inc(PtChild);
// 取下一个控件
hWnd := GetWindow(hWnd, GW_HWNDNEXT);
end;
// 最后一个TChild是结束标识
PtChild.idc := IDC_LASTCHILD;
end;
// 转换规则长度单位
procedure Layout_ConvertDlgUnits(hWndParent: HWND; pRules: PRule; pChildList: PChild);
var
Rc: TRect;
fVertical: BOOL;
PtRule: PRule;
begin
// Rc各成员清零
ZeroMemory(@Rc, SizeOf(TRect));
// 遍历Rule列表
PtRule := pRules;
while (PtRule.Action <> lEND) do
begin
// 转换, 对话框单位 ->> 图素单位
Rc.Right := PtRule.nOffset;
Rc.Bottom := PtRule.nOffset;
adgMapDialogRect(hWndParent, Rc);
// 需要判断当前操作是水平方向还是垂直方向的, 因为两个方向的对话框单位是不相等的
case (PtRule.Action) of
lVCENTER: fVertical := TRUE;
lHCENTER: fVertical := FALSE;
// 何时填入? **
lMOVE, lSTRETCH: fVertical := Layout_MetricIsVertical(lPART(PtRule.ActOn.nMetric));
else adgFAIL('Invalid action');
end;
// 根据动作方向决定正确的转换数值
if fVertical then
PtRule.nPixelOffset := Rc.Bottom
else
PtRule.nPixelOffset := Rc.Right;
// 指向下一个 TRule ..
Inc(PtRule);
end;
end;
// 填写未知标识
procedure Layout_MarkUnknowns(hWndParent: HWND; pRules: PRule; pChildList: PChild);
var
PtRule: PRule;
pChildActOn: PChild;
hWnd: LongWord; // HWND
nOtherUnknown, nOppositeSide, idc, idcFirst, idcLast: Integer;
begin
// 根据TRule列表, 向TChild列表填写未知标识
PtRule := pRules;
while (PtRule.Action <> lEND) do
begin
case (PtRule.Action) of
lSTRETCH: // Metric should be stretched
begin
// 定位ActOn控件TChild地址
pChildActOn := Layout_FindChild(pChildList, PtRule.ActOn.idc);
// 该控件设置成需要改变的
pChildActOn.fFixed := FALSE;
// The part being acted on must be a metric.
// adgASSERT(ISMETRIC(pRule.ActOn.nMetric));
// 需要扩展的属性状态未知
pChildActOn.afMetric[PtRule.ActOn.nMetric] := UNKNOWN;
// 如果 Left/Top or Right/Bottom 是未知的, 那么 Width/Height 也是.
// 如果 Width/Height 是未知的, 那么 Right/Bottom 也是未知的.
nOtherUnknown := Integer(Layout_GetOtherUnknownMetric(lPART(PtRule.ActOn.nMetric)));
pChildActOn.afMetric[nOtherUnknown] := UNKNOWN;
end;
lMOVE: // 移动控件
begin
// 定位ActOn控件TChild地址
pChildActOn := Layout_FindChild(pChildList, PtRule.ActOn.idc);
// 该控件设置成需要改变的
pChildActOn.fFixed := FALSE;
// The part being acted upon must be a side.
// adgASSERT(ISSIDE(pRule.ActOn.nSide));
// 需要移动的边状态未知
pChildActOn.afMetric[PtRule.ActOn.nSide] := UNKNOWN;
// 相反的边也变成未知, 但 Width/Height 保持不变
// (实际上, 这是要有6个metrics的主要原因).
nOppositeSide := Integer(Layout_GetOppositeSide(lPART(PtRule.ActOn.nSide)));
pChildActOn.afMetric[nOppositeSide] := UNKNOWN;
end;
lVCENTER, // 垂直居中
lHCENTER: // 水平居中
begin
// We must be centering a group of one or more controls.
// adgASSERT(pRule.ActOn.nPart = lpGROUP);
// 控件组ID范围
idcFirst := PtRule.ActOn.idcFirst;
idcLast := PtRule.ActOn.idcLast;
// adgASSERT(idcFirst <= idcLast);
hWnd := GetTopWindow(hWndParent);
while IsWindow(hWnd) do
begin
idc := GetDlgCtrlID(hWnd);
if adgInRange(idcFirst, idc, idcLast) then
begin
// 定位到指定ID控件的TChild处
pChildActOn := Layout_FindChild(pChildList, idc);
// 根据动作类型设相应属性未知
if (PtRule.Action = lHCENTER) then
begin
pChildActOn.afMetric[Integer(lpLEFT)] := UNKNOWN;
pChildActOn.afMetric[Integer(lpRIGHT)] := UNKNOWN;
end else
begin
pChildActOn.afMetric[Integer(lpTOP)] := UNKNOWN;
pChildActOn.afMetric[Integer(lpBOTTOM)] := UNKNOWN;
end;
// Child acted upon is no longer fixed. ??
pChildActOn.fFixed := FALSE;
end;
hWnd := GetWindow(hWnd, GW_HWNDNEXT);
end;
end;
else adgFAIL('Invalid action');
end;
end;
end;
function Layout_CheckChild(const pChild: TChild): BOOL;
const
pszMetric: array[0..5] of PChar = ('left', 'top', 'right', 'bottom', 'width', 'height');
var
i: Integer;
sz: array[0..80] of Char;
L: array[0..1] of DWORD;
begin
Result := TRUE;
// Any unknown metric indicates a problem with the rules, so we 'assert'.
for i := 0 to NUMMETRICS - 1 do
begin
if (pChild.afMetric[i] = UNKNOWN) then
begin
L[0] := Integer(pszMetric[i]);
L[1] := pChild.idc;
wvsprintf(sz, 'Layout couldn'#$27't find %s of id=%d', @L[0]);
adgMB(sz);
Result := FALSE;
end;
end;
end;
function Layout_ApplyRules(hWndParent: HWND; pRules: PRule; pChildList: PChild): BOOL;
var
PtRule: PRule;
fAppliedAtLeastOneRule: BOOL;
begin
// fOK = TRUE;
Result := TRUE;
// Check assumptions.
// adgASSERT(IsWindow(hwndParent));
// adgASSERT(pRules);
// adgASSERT(pChildList);
// Based on the list of rules, mark all unknown child metrics as UNKNOWN.
Layout_MarkUnknowns(hWndParent, pRules, pChildList);
// Traverse the rule list, converting offsets from dialog units to pixels.
Layout_ConvertDlgUnits(hWndParent, pRules, pChildList);
// Mark all the rules as unapplied before attempting to apply them.
PtRule := pRules;
while (PtRule.Action <> lEND) do
begin
PtRule.fState := UNAPPLIED;
Inc(PtRule);
end;
// Loop through the rule list for as long as we are able to apply at least
// one rule (if we make a pass through the entire list, and we are unable
// to apply any rule, we are finished).
repeat
fAppliedAtLeastOneRule := FALSE;
PtRule := pRules;
while (PtRule.Action <> lEND) do
begin
if (PtRule.fState <> APPLIED) then
begin
if Layout_ApplyRule(hWndParent, pRules, pChildList, PtRule) then
fAppliedAtLeastOneRule := TRUE;
end;
Inc(PtRule);
end;
until (fAppliedAtLeastOneRule = FALSE);
// Verify that all rules have been successfully applied.
PtRule := pRules;
while (PtRule.Action <> lEND) do
begin
// adgASSERT(pRule->fState == APPLIED);
if (PtRule.fState <> APPLIED) then Result := FALSE; // **
Inc(PtRule);
end;
end;
function Layout_ApplyRule(hWndParent: HWND; pRules: PRule; pChildList: PChild; PtRule: PRule): BOOL;
var
pChildRelTo, pChildActOn: PChild;
ChildRelTo: TChild;
ptChild, pChildListNew, pSrc, pDest: PChild;
nRules, nMetric, nChildren, idcFirst, idcLast, nOffset, nCentered: Integer;
RcBounds: TRect;
hWnd, hWndFirst: LongWord; // HWND
pr, prn, prNew: PRule;
idc: Integer; // **
begin
Result := FALSE;
// Find the child and part(s) that we are going to act relative to
pChildRelTo := Layout_FindChild(pChildList, PtRule.RelTo.idc);
case lPART(PtRule.RelTo.nPart) of // **
lpLEFT, lpTOP, lpRIGHT, lpBOTTOM, lpWIDTH, lpHEIGHT:
// We can't apply a rule relative to a metric that is unknown.
if (pChildRelTo.afMetric[PtRule.RelTo.nMetric] = UNKNOWN) then Exit;
lpGROUP:
begin
// We can't apply a rule relative to a control unless we know its
// left/top and right/bottom sides (for centering).
// adgASSERT(pRule->RelTo.idcFirst == pRule->RelTo.idcLast);
// adgASSERT((pRule->Action == lHCENTER) || (pRule->Action == lVCENTER));
if (PtRule.Action = lHCENTER) then
begin
if (pChildRelTo.afMetric[Integer(lpLEFT)] = UNKNOWN) or
(pChildRelTo.afMetric[Integer(lpRIGHT)] = UNKNOWN) then
Exit;
end else
begin
if (pChildRelTo.afMetric[Integer(lpTOP)] = UNKNOWN) or
(pChildRelTo.afMetric[Integer(lpBOTTOM)] = UNKNOWN) then
Exit;
end;
end;
end;
// Make a local copy of the child we are relative to. We need to do this
// because we may need to apply a percentage to the width/height metrics
// and we don't want to modify the actual child list.
ChildRelTo := pChildRelTo^;
// Use percentage to modify the width/height of the child we are relative to
if (PtRule.RelTo.nMetric = Integer(lpWIDTH)) or
(PtRule.RelTo.nMetric = Integer(lpHEIGHT)) then
begin
ChildRelTo.anMetric[PtRule.RelTo.nMetric] := PtRule.RelTo.nPercent * ChildRelTo.anMetric[PtRule.RelTo.nMetric];
ChildRelTo.anMetric[PtRule.RelTo.nMetric] := ChildRelTo.anMetric[PtRule.RelTo.nMetric] div 100;
Layout_SolveChild(@ChildRelTo);
end;
// Apply our rule based on the action field
case (PtRule.Action) of
lSTRETCH: // Metric should be stretched
begin
// The part being acted on must be a metric. If it is a width/height
// metric, it must be 100% of the width/height.
// adgASSERT(ISMETRIC(pRule->ActOn.nMetric));
// adgASSERT(ISSIDE(pRule->ActOn.nSide) || (pRule->ActOn.nPercent == 100));
// The part being acted relative to must be a metric.
// adgASSERT(ISMETRIC(pRule->RelTo.nMetric));
// Find the child being acted on and stretch the specified metric.
pChildActOn := Layout_FindChild(pChildList, PtRule.ActOn.idc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -