📄 layout.pas
字号:
// adgASSERT(pChildActOn);
pChildActOn.anMetric[PtRule.ActOn.nMetric] :=
ChildRelTo.anMetric[PtRule.RelTo.nMetric] + PtRule.nPixelOffset;
pChildActOn.afMetric[PtRule.ActOn.nMetric] := KNOWN;
Layout_SolveChild(pChildActOn);
PtRule.fState := APPLIED;
// return(TRUE);
Result := TRUE;
Exit;
end;
lMOVE: // Whole control should be moved
begin
// The part being moved must be a side.
// adgASSERT(ISSIDE(pRule->ActOn.nSide));
// The part that is being acted relative to must be a metric.
// adgASSERT(ISMETRIC(pRule->RelTo.nMetric));
// Find the child being acted on and move the specified side.
pChildActOn := Layout_FindChild(pChildList, PtRule.ActOn.idc);
// adgASSERT(pChildActOn);
pChildActOn.anMetric[PtRule.ActOn.nSide] :=
ChildRelTo.anMetric[PtRule.RelTo.nMetric] + PtRule.nPixelOffset;
pChildActOn.afMetric[PtRule.ActOn.nSide] := KNOWN;
Layout_SolveChild(pChildActOn);
PtRule.fState := APPLIED;
// return(TRUE);
Result := TRUE;
Exit;
end;
lVCENTER, // Vertically center a control/group
lHCENTER: // Horizontally center a control/group
begin
// We can only center a group of one or more controls relative to
// another control (a single control is a 'group' of one control).
// adgASSERT(pRule->ActOn.nPart == lpGROUP);
// adgASSERT(pRule->RelTo.nPart == lpGROUP);
// adgASSERT(pRule->RelTo.idcFirst == pRule->RelTo.idcLast);
// First id in group must be less than or equal to the last id
idcFirst := PtRule.ActOn.idcFirst;
idcLast := PtRule.ActOn.idcLast;
// adgASSERT(idcFirst <= idcLast);
// Ensure that the width/height is known for each control in the
// group before proceeding with any centering.
hWndFirst := GetTopWindow(hWndParent);
hWnd := hWndFirst;
while IsWindow(hWnd) do
begin
idc := GetDlgCtrlID(hWnd);
if adgInRange(idcFirst, idc, idcLast) then
begin
pChildActOn := Layout_FindChild(pChildList, idc);
if (PtRule.Action = lHCENTER) then
begin
if (pChildActOn.afMetric[Integer(lpWIDTH)] = UNKNOWN) then
begin
Result := FALSE;
Exit;
end; // return(FALSE);
end else
begin
if (pChildActOn.afMetric[Integer(lpHEIGHT)] = UNKNOWN) then
begin
Result := FALSE;
Exit;
end; // return(FALSE);
end;
end;
hWnd := GetWindow(hWnd, GW_HWNDNEXT);
end;
// Create a new list of rules which contains the subset of rules
// which act on controls in the centered group.
nRules := 0;
pr := 0;
while (pr.Action <> lEND) do
begin
Inc(pr);
Inc(nRules);
end;
Inc(nRules);
GetMem(prNew, nRules * Sizeof(TRule));
prn := prNew;
pr := pRules;
while (pr.Action <> lEND) do // Inc(pr)
begin
if adgINRANGE(idcFirst, pr.ActOn.idc, idcLast) then
begin
if (PtRule.Action = lHCENTER) then
begin
if (pr.ActOn.nPart = Integer(lpLEFT)) or
(pr.ActOn.nPart = Integer(lpRIGHT)) then
begin
Inc(prn);
prn^ := pr^;
end;
end else
begin
if (pr.ActOn.nPart = Integer(lpTOP)) or
(pr.ActOn.nPart = Integer(lpBOTTOM)) then
begin
Inc(prn);
prn^ := pr^;
end;
end;
end;
end;
prn.Action := lEND;
// Make a local copy of the child list and set everything to KNOWN.
nChildren := 0;
PtChild := pChildList;
while (PtChild.idc <> IDC_LASTCHILD) do
begin
Inc(PtChild);
Inc(nChildren);
end;
Inc(nChildren);
GetMem(pChildListNew, nChildren * SizeOf(TChild));
MoveMemory(pChildListNew, pChildList, nChildren * SizeOf(TChild));
PtChild := pChildListNew;
while (PtChild.idc <> IDC_LASTCHILD) do // ; pChild++)
begin
for nMetric := 0 to NUMMETRICS - 1 do PtChild.afMetric[Integer(nMetric)] := KNOWN;
Inc(PtChild);
end;
// Solve for the children being centered as a sub-problem.
if (Layout_ApplyRules(hWndParent, prNew, pChildListNew) = FALSE) then
begin
adgFAIL('Unable to apply rules to centered children');
Result := FALSE;
end;
// Compute the bounding rectangle of the group
SetRectEmpty(RcBounds);
hWndFirst := GetTopWindow(hWndParent);
hWnd := hWndFirst;
while IsWindow(hWnd) do
begin
idc := GetDlgCtrlID(hWnd);
if adgINRANGE(idcFirst, idc, idcLast) then
begin
pChildActOn := Layout_FindChild(pChildListNew, idc);
UnionRect(rcBounds, rcBounds, pChildActOn.Rc);
end;
hWnd := GetWindow(hWnd, GW_HWNDNEXT);
end;
// Find the offset required to center the group's bounding rectangle
// against the control we are relative to.
if (PtRule.Action = lHCENTER) then
begin
nCentered := ChildRelTo.anMetric[Integer(lpLEFT)] +
((ChildRelTo.anMetric[Integer(lpWIDTH)] -
(RcBounds.Right - RcBounds.Left)) div 2);
nOffset := nCentered - RcBounds.Left;
end else
begin
nCentered := ChildRelTo.anMetric[Integer(lpTOP)] +
((ChildRelTo.anMetric[Integer(lpHEIGHT)] -
(RcBounds.Bottom - RcBounds.Top)) div 2);
nOffset := nCentered - RcBounds.Top;
end;
// Add in any additional offset from the rule.
Inc(nOffset, PtRule.nPixelOffset);
// Go through the new child list, moving each control.
// adgASSERT(pRule->ActOn.idcFirst <= pRule->ActOn.idcLast);
hWnd := hWndFirst;
while IsWindow(hWnd) do // hwnd = GetNextSibling(hwnd))
begin
idc := GetDlgCtrlID(hWnd);
if adgInRange(idcFirst, idc, idcLast) then
begin
pChildActOn := Layout_FindChild(pChildListNew, idc);
if (PtRule.Action = lHCENTER) then
begin
Inc(pChildActOn.anMetric[Integer(lpLEFT)], nOffset);
Inc(pChildActOn.anMetric[Integer(lpRIGHT)], nOffset);
end else
begin
Inc(pChildActOn.anMetric[Integer(lpTOP)], nOffset);
Inc(pChildActOn.anMetric[Integer(lpBOTTOM)], nOffset);
end;
end;
hWnd := GetWindow(hWnd, GW_HWNDNEXT);
end;
// Now modify the real child list based on pChildListNew.
pSrc := pChildListNew;
pDest := pChildList;
while (pSrc.idc <> IDC_LASTCHILD) do
begin
if adgINRANGE(idcFirst, pSrc.idc, idcLast) then
begin
if (PtRule.Action = lHCENTER) then
begin
pDest.anMetric[Integer(lpLEFT)] := pSrc.anMetric[Integer(lpLEFT)];
pDest.anMetric[Integer(lpRIGHT)] := pSrc.anMetric[Integer(lpRIGHT)];
pDest.afMetric[Integer(lpLEFT)] := KNOWN;
pDest.afMetric[Integer(lpRIGHT)] := KNOWN;
end else
begin
pDest.anMetric[Integer(lpTOP)] := pSrc.anMetric[Integer(lpTOP)];
pDest.anMetric[Integer(lpBOTTOM)] := pSrc.anMetric[Integer(lpBOTTOM)];
pDest.afMetric[Integer(lpTOP)] := KNOWN;
pDest.afMetric[Integer(lpBOTTOM)] := KNOWN;
end;
end;
Inc(pSrc);
Inc(pDest);
end;
PtRule.fState := APPLIED;
Result := TRUE;
Exit;
end;
else
begin
adgFAIL('Invalid action');
Result := FALSE;
end;
end;
end;
function Layout_ComputeLayout(hWndParent: HWND; pRules: PRule): BOOL; stdcall;
var
hdwp: THandle; // HDWP;
PtChild, pChildList: PChild;
nChildren: Integer;
hWndChild: HWND;
begin
// Check assumptions.
// adgASSERT(IsWindow(hwndParent));
// adgASSERT(pRules);
Result := TRUE;
// Don't do anything to a minimized window.
if IsIconic(hWndParent) then Exit; // return(TRUE);
// Enumerate all child windows of the dialog, allocating a CHILD structure
// for each child, with all six metric flags set to KNOWN. To simplify
// coding, we also add a special CHILD structure for the parent window with
// the id lPARENT (defined in layout.h). If there are no children, or
// memory cannot be allocated for the child list, we do nothing.
pChildList := Layout_CreateChildList(hWndParent, @nChildren);
if (pChildList = nil) then begin Result := FALSE; Exit; end; // return(FALSE);
if (nChildren = 0) then begin Result := TRUE; Exit; end; // return(TRUE);
// Apply the rules from the rule list to solve for the locations of all the
// child controls.
if (Layout_ApplyRules(hWndParent, pRules, pChildList) = FALSE) then
begin
adgFAIL('Unable to apply rules');
Result := FALSE;
Exit; // return(FALSE);
end;
// Simultaneously relocate all the children using DeferWindowPos.
hdwp := BeginDeferWindowPos(0);
// adgASSERT(hdwp);
// Move each child in the CHILD list. We enumerate the child list starting
// at pChildList + 1, because the first CHILD is lPARENT.
PtChild := pChildList;
Inc(PtChild);
while (PtChild.idc <> IDC_LASTCHILD) do // ; pChild++
begin
// Check child for any still-unsolved metrics. You may want to remove or
// #ifdef out this check once your rules are known to be working.
if (Layout_CheckChild(PtChild^) = FALSE) then Result := FALSE;
// Add child to DeferWindowPos list if it is not fixed.
if (PtChild.fFixed = FALSE) then
begin
// HWND hwndChild = GetDlgItem(hwndParent, pChild->idc);
hWndChild := GetDlgItem(hWndParent, PtChild.idc);
// adgASSERT(pChild->anMetric[lpWIDTH] >= 0);
// adgASSERT(pChild->anMetric[lpHEIGHT] >= 0);
hdwp := DeferWindowPos(hdwp, hWndChild, 0,
PtChild.anMetric[Integer(lpLEFT)], PtChild.anMetric[Integer(lpTOP)],
PtChild.anMetric[Integer(lpWIDTH)], PtChild.anMetric[Integer(lpHEIGHT)],
SWP_NOZORDER);
// adgASSERT(hdwp);
// Invalidation is necessary here because some controls (edit
// controls in particular) don't repaint correctly under Windows NT
// when they are moved with DeferWindowPos.
InvalidateRect(hWndChild, nil, TRUE);
end;
Inc(PtChild);
end;
// It is this function call which actually moves all the windows.
EndDeferWindowPos(hdwp);
// Free the allocated list of CHILD structures
FreeMem(pChildList);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -