Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

alignrec.c File Reference

#include "precomp.h"

Go to the source code of this file.

Defines

#define MONITORS_MAX   10
#define RectCenterX(prc)   ((prc)->left+((prc)->right-(prc)->left)/2)
#define RectCenterY(prc)   ((prc)->top+((prc)->bottom-(prc)->top)/2)
#define INTERSECTION_AXIS(a, b)
#define INTERSECTION_AXIS_VERTICAL   (0)
#define INTERSECTION_AXIS_HORIZONTAL   (1)
#define INTERSECTION_AXIS_UNKNOWN(code)   (code & 2)

Functions

void NEAR PASCAL CenterRectangles (LPRECT arc, UINT count)
LPRECT NEAR PASCAL RemoveOverlap (LPRECT lprc1, LPRECT lprc2, LPRECT lprcI)
void NEAR PASCAL RemoveOverlaps (LPRECT arc, UINT count)
LPRECT FAR *NEAR PASCAL AddNextContiguousRectangle (LPRECT FAR *aprc, LPRECT FAR *pprcSplit, UINT count)
void NEAR PASCAL RemoveGaps (LPRECT arc, UINT count)
BOOL AlignRects (LPRECT arc, DWORD cCount, DWORD iPrimary, DWORD dwFlags)


Define Documentation

#define INTERSECTION_AXIS a,
 ) 
 

Value:

(((((a->left == b->left) << 1) | (a->top == b->top)) ^ \ (((a->right == b->right) << 1) | (a->bottom == b->bottom))) - 1)

Definition at line 59 of file alignrec.c.

Referenced by RemoveOverlap().

#define INTERSECTION_AXIS_HORIZONTAL   (1)
 

Definition at line 64 of file alignrec.c.

Referenced by RemoveOverlap().

#define INTERSECTION_AXIS_UNKNOWN code   )     (code & 2)
 

Definition at line 65 of file alignrec.c.

Referenced by RemoveOverlap().

#define INTERSECTION_AXIS_VERTICAL   (0)
 

Definition at line 63 of file alignrec.c.

Referenced by RemoveOverlap().

#define MONITORS_MAX   10
 

Definition at line 17 of file alignrec.c.

Referenced by AlignRects(), and RemoveGaps().

#define RectCenterX prc   )     ((prc)->left+((prc)->right-(prc)->left)/2)
 

Definition at line 19 of file alignrec.c.

Referenced by CenterRectangles(), RemoveGaps(), and RemoveOverlap().

#define RectCenterY prc   )     ((prc)->top+((prc)->bottom-(prc)->top)/2)
 

Definition at line 20 of file alignrec.c.

Referenced by CenterRectangles(), RemoveGaps(), and RemoveOverlap().


Function Documentation

LPRECT FAR* NEAR PASCAL AddNextContiguousRectangle LPRECT FAR *  aprc,
LPRECT FAR *  pprcSplit,
UINT  count
 

Definition at line 295 of file alignrec.c.

References CopyRect, FAR, IntersectRect(), OffsetRect(), and UINT.

Referenced by RemoveGaps().

00297 { 00298 LPRECT FAR *pprcL; 00299 LPRECT FAR *pprcTest; 00300 LPRECT FAR *pprcAxis; 00301 LPRECT FAR *pprcDiag; 00302 UINT dAxis = (UINT)-1; 00303 UINT dDiag = (UINT)-1; 00304 POINT dpAxis; 00305 POINT dpDiag; 00306 POINT dpMove; 00307 00308 pprcL = aprc + count; 00309 00310 for (pprcTest = aprc; pprcTest < pprcSplit; pprcTest++) 00311 { 00312 LPRECT lprcTest = *pprcTest; 00313 LPRECT FAR *pprcScan; 00314 00315 for (pprcScan = pprcSplit; pprcScan < pprcL; pprcScan++) 00316 { 00317 RECT rcCheckOverlap; 00318 LPRECT lprcScan = *pprcScan; 00319 LPRECT FAR *pprcCheckOverlap; 00320 LPRECT FAR *FAR *pppBest; 00321 LPPOINT pdpBest; 00322 UINT FAR *pdBest; 00323 UINT dX, dY; 00324 UINT dTotal; 00325 00326 // 00327 // Figure out how far the rectangle may be along both axes. 00328 // Note some of these numbers could be garbage at this point but 00329 // the code below will take care of it. 00330 // 00331 if (lprcScan->right <= lprcTest->left) 00332 dpMove.x = dX = lprcTest->left - lprcScan->right; 00333 else 00334 dpMove.x = -(int)(dX = (lprcScan->left - lprcTest->right)); 00335 00336 if (lprcScan->bottom <= lprcTest->top) 00337 dpMove.y = dY = lprcTest->top - lprcScan->bottom; 00338 else 00339 dpMove.y = -(int)(dY = (lprcScan->top - lprcTest->bottom)); 00340 00341 // 00342 // Figure out whether the rectangles are vertical, horizontal or 00343 // diagonal to each other and pick the measurements we will test. 00344 // 00345 if ((lprcScan->top < lprcTest->bottom) && 00346 (lprcScan->bottom > lprcTest->top)) 00347 { 00348 // The rectangles are somewhat horizontally aligned. 00349 dpMove.y = dY = 0; 00350 pppBest = &pprcAxis; 00351 pdpBest = &dpAxis; 00352 pdBest = &dAxis; 00353 } 00354 else if ((lprcScan->left < lprcTest->right) && 00355 (lprcScan->right > lprcTest->left)) 00356 { 00357 // The rectangles are somewhat vertically aligned. 00358 dpMove.x = dX = 0; 00359 pppBest = &pprcAxis; 00360 pdpBest = &dpAxis; 00361 pdBest = &dAxis; 00362 } 00363 else 00364 { 00365 // The rectangles are somewhat diagonally aligned. 00366 pppBest = &pprcDiag; 00367 pdpBest = &dpDiag; 00368 pdBest = &dDiag; 00369 } 00370 00371 // 00372 // Make sure there aren't other rectangles in the way. We only 00373 // need to check the upper array since that is the pool of 00374 // semi-placed rectangles. Any rectangles in the lower array that 00375 // are "in the way" will be found in a different iteration of the 00376 // enclosing loop. 00377 // 00378 00379 CopyRect(&rcCheckOverlap, lprcScan); 00380 OffsetRect(&rcCheckOverlap, dpMove.x, dpMove.y); 00381 00382 for (pprcCheckOverlap = pprcScan + 1; pprcCheckOverlap < pprcL; 00383 pprcCheckOverlap++) 00384 { 00385 RECT rc; 00386 if (IntersectRect(&rc, *pprcCheckOverlap, &rcCheckOverlap)) 00387 break; 00388 } 00389 if (pprcCheckOverlap < pprcL) 00390 { 00391 // There was another rectangle in the way; don't use this one. 00392 continue; 00393 } 00394 00395 // 00396 // If it is closer than the one we already had, use it instead. 00397 // 00398 dTotal = dX + dY; 00399 if (dTotal < *pdBest) 00400 { 00401 *pdBest = dTotal; 00402 *pdpBest = dpMove; 00403 *pppBest = pprcScan; 00404 } 00405 } 00406 } 00407 00408 // 00409 // If we found anything along an axis use that otherwise use a diagonal. 00410 // 00411 if (dAxis != (UINT)-1) 00412 { 00413 pprcSplit = pprcAxis; 00414 dpMove = dpAxis; 00415 } 00416 else if (dDiag != (UINT)-1) 00417 { 00418 // BUGBUG: consider moving the rectangle to a side in this case. 00419 // (that, of course would add a lot of code to avoid collisions) 00420 pprcSplit = pprcDiag; 00421 dpMove = dpDiag; 00422 } 00423 else 00424 dpMove.x = dpMove.y = 0; 00425 00426 // 00427 // Move the monitor into place and return it as the one we chose. 00428 // 00429 if (dpMove.x || dpMove.y) 00430 OffsetRect(*pprcSplit, dpMove.x, dpMove.y); 00431 00432 return pprcSplit; 00433 }

BOOL AlignRects LPRECT  arc,
DWORD  cCount,
DWORD  iPrimary,
DWORD  dwFlags
 

Definition at line 538 of file alignrec.c.

References CopyRect, dwFlags, FALSE, MONITORS_MAX, OffsetRect(), RemoveGaps(), RemoveOverlaps(), and TRUE.

00539 { 00540 LPRECT lprc, lprcL; 00541 00542 // 00543 // Limit for loops. 00544 // 00545 00546 lprcL = arc + cCount; 00547 00548 // 00549 // We don't need to get all worked up if there is only one rectangle. 00550 // 00551 00552 if (cCount > MONITORS_MAX) 00553 { 00554 return FALSE; 00555 } 00556 00557 00558 if (cCount > 1) 00559 { 00560 if (!(dwFlags & CUDR_NOSNAPTOGRID)) 00561 { 00562 // 00563 // Align monitors on 8 pixel boundaries so GDI can use the same 00564 // brush realization on compatible devices (BIG performance win). 00565 // Note that we assume the size of a monitor will be in multiples 00566 // of 8 pixels on X and Y. We cannot do this for the work areas so 00567 // we convert them to be relative to the origins of their monitors 00568 // for the time being. 00569 // 00570 // The way we do this alignment is to just do the overlap/gap 00571 // resoluton in 8 pixel space (ie divide everything by 8 beforehand 00572 // and multiply it by 8 afterward). 00573 // 00574 // Note: WE CAN'T USE MULTDIV HERE because it introduces one-off 00575 // errors when monitors span the origin. These become eight-off 00576 // errors when we scale things back up and we end up trying to 00577 // create DCs with sizes like 632x472 etc (not too good). It also 00578 // handles rounding the wierdly in both positive and negative space 00579 // and we just want to snap things to a grid so we compensate for 00580 // truncation differently here. 00581 // 00582 for (lprc = arc; lprc < lprcL; lprc++) 00583 { 00584 RECT rc; 00585 int d; 00586 00587 00588 CopyRect(&rc, lprc); 00589 00590 d = rc.right - rc.left; 00591 00592 if (rc.left < 0) 00593 rc.left -= 4; 00594 else 00595 rc.left += 3; 00596 00597 rc.left /= 8; 00598 rc.right = rc.left + (d / 8); 00599 00600 d = rc.bottom - rc.top; 00601 00602 if (rc.top < 0) 00603 rc.top -= 4; 00604 else 00605 rc.top += 3; 00606 00607 rc.top /= 8; 00608 rc.bottom = rc.top + (d / 8); 00609 00610 CopyRect(lprc, &rc); 00611 } 00612 } 00613 00614 // 00615 // RemoveGaps is designed assuming that none of the rectangles that it 00616 // is passed will overlap. Thus we cannot safely call it if we have 00617 // skipped the call to RemoveOverlaps or it might loop forever. 00618 // 00619 if (!(dwFlags & CUDR_NORESOLVEPOSITIONS)) 00620 { 00621 RemoveOverlaps(arc, cCount); 00622 00623 if (!(dwFlags & CUDR_NOCLOSEGAPS)) 00624 { 00625 RemoveGaps(arc, cCount); 00626 } 00627 } 00628 00629 if (!(dwFlags & CUDR_NOSNAPTOGRID)) 00630 { 00631 // 00632 // Now return the monitor rectangles to pixel units this is a 00633 // simple multiply and MultDiv doesn't offer us any code size 00634 // advantage so (I guess that assumes a bit about the compiler, 00635 // but...) just do it right here. 00636 // 00637 for (lprc = arc; lprc < lprcL; lprc++) 00638 { 00639 lprc->left *= 8; 00640 lprc->top *= 8; 00641 lprc->right *= 8; 00642 lprc->bottom *= 8; 00643 } 00644 } 00645 } 00646 00647 if (!(dwFlags & CUDR_NOPRIMARY)) 00648 { 00649 // 00650 // Reset all the coordinates based on the primaries position, 00651 // so that it is always located at 0,0 00652 // 00653 00654 LONG dx = -((arc + iPrimary)->left); 00655 LONG dy = -((arc + iPrimary)->top); 00656 00657 for (lprc = arc; lprc < lprcL; lprc++) 00658 { 00659 OffsetRect(lprc, dx, dy); 00660 } 00661 } 00662 00663 return TRUE; 00664 }

void NEAR PASCAL CenterRectangles LPRECT  arc,
UINT  count
 

Definition at line 73 of file alignrec.c.

References CopyRect, OffsetRect(), RectCenterX, RectCenterY, and UnionRect().

Referenced by RemoveGaps(), and RemoveOverlaps().

00074 { 00075 LPRECT lprc, lprcL; 00076 RECT rcUnion; 00077 00078 CopyRect(&rcUnion, arc); 00079 00080 lprcL = arc + count; 00081 for (lprc = arc + 1; lprc < lprcL; lprc++) 00082 { 00083 UnionRect(&rcUnion, &rcUnion, lprc); 00084 } 00085 00086 for (lprc = arc; count; count--) 00087 { 00088 OffsetRect(lprc, -RectCenterX(&rcUnion), -RectCenterY(&rcUnion)); 00089 lprc++; 00090 } 00091 }

void NEAR PASCAL RemoveGaps LPRECT  arc,
UINT  count
 

Definition at line 442 of file alignrec.c.

References AddNextContiguousRectangle(), CenterRectangles(), FAR, MONITORS_MAX, RectCenterX, RectCenterY, and UINT.

Referenced by AlignRects().

00443 { 00444 LPRECT aprc[MONITORS_MAX]; 00445 LPRECT lprc, lprcL, lprcSwap, FAR *pprc, FAR *pprcNearest; 00446 UINT uNearest; 00447 00448 // 00449 // We will need to find the rectangle closest to the center of the group. 00450 // We don't really need to center the array here but it doesn't hurt and 00451 // saves us some code below. 00452 // 00453 CenterRectangles(arc, count); 00454 00455 // 00456 // Build an array of LPRECTs we can shuffle around with relative ease while 00457 // not disturbing the order of the passed array. Also take note of which 00458 // one is closest to the center so we start with it and pull the rest of 00459 // the rectangles inward. This can make a big difference in placement when 00460 // there are more than 2 rectangles. 00461 // 00462 uNearest = (UINT)-1; 00463 pprc = aprc; 00464 lprcL = (lprc = arc) + count; 00465 00466 while (lprc < lprcL) 00467 { 00468 int x, y; 00469 UINT u; 00470 00471 // 00472 // Fill in the array. 00473 // 00474 *pprc = lprc; 00475 00476 // 00477 // Check if this one is closer to the center of the group. 00478 // 00479 x = RectCenterX(lprc); 00480 y = RectCenterY(lprc); 00481 if (x < 0) x *= -1; 00482 if (y < 0) y *= -1; 00483 00484 u = (UINT)x + (UINT)y; 00485 if (u < uNearest) 00486 { 00487 uNearest = u; 00488 pprcNearest = pprc; 00489 } 00490 00491 pprc++; 00492 lprc++; 00493 } 00494 00495 // 00496 // Now make sure we move everything toward the centermost rectangle. 00497 // 00498 if (pprcNearest != aprc) 00499 { 00500 lprcSwap = *pprcNearest; 00501 *pprcNearest = *aprc; 00502 *aprc = lprcSwap; 00503 } 00504 00505 // 00506 // Finally, loop through the array closing any gaps. 00507 // 00508 pprc = aprc + 1; 00509 for (lprc = arc + 1; lprc < lprcL; pprc++, lprc++) 00510 { 00511 // 00512 // Find the next suitable rectangle to combine into the group and move 00513 // it into position. 00514 // 00515 pprcNearest = AddNextContiguousRectangle(aprc, pprc, count); 00516 00517 // 00518 // If the rectangle that was added is not the next in our array, swap. 00519 // 00520 if (pprcNearest != pprc) 00521 { 00522 lprcSwap = *pprcNearest; 00523 *pprcNearest = *pprc; 00524 *pprc = lprcSwap; 00525 } 00526 } 00527 }

LPRECT NEAR PASCAL RemoveOverlap LPRECT  lprc1,
LPRECT  lprc2,
LPRECT  lprcI
 

Definition at line 105 of file alignrec.c.

References BOOL, INTERSECTION_AXIS, INTERSECTION_AXIS_HORIZONTAL, INTERSECTION_AXIS_UNKNOWN, INTERSECTION_AXIS_VERTICAL, OffsetRect(), PtInRect(), RectCenterX, and RectCenterY.

Referenced by RemoveOverlaps().

00106 { 00107 LPRECT lprcMove, lprcStay; 00108 POINT ptC1, ptC2; 00109 BOOL fNegative; 00110 BOOL fC1Neg; 00111 BOOL fC2Neg; 00112 int dC1, dC2; 00113 int xOffset; 00114 int yOffset; 00115 int nAxis; 00116 00117 // 00118 // Compute the centers of both rectangles. We will need them later. 00119 // 00120 ptC1.x = RectCenterX(lprc1); 00121 ptC1.y = RectCenterY(lprc1); 00122 ptC2.x = RectCenterX(lprc2); 00123 ptC2.y = RectCenterY(lprc2); 00124 00125 // 00126 // Decide whether we should move things horizontally or vertically. All 00127 // this goop is here so it will "feel" right when the system needs to 00128 // move a monitor on you. 00129 // 00130 nAxis = INTERSECTION_AXIS(lprcI, lprc1); 00131 00132 if (INTERSECTION_AXIS_UNKNOWN(nAxis)) 00133 { 00134 // 00135 // Is this a "big" intersection between the two rectangles? 00136 // 00137 if (PtInRect(lprcI, ptC1) || PtInRect(lprcI, ptC2)) 00138 { 00139 // 00140 // This is a "big" overlap. Decide if the rectangles 00141 // are aligned more "horizontal-ish" or "vertical-ish." 00142 // 00143 xOffset = ptC1.x - ptC2.x; 00144 if (xOffset < 0) 00145 xOffset *= -1; 00146 yOffset = ptC1.y - ptC2.y; 00147 if (yOffset < 0) 00148 yOffset *= -1; 00149 00150 if (xOffset >= yOffset) 00151 nAxis = INTERSECTION_AXIS_HORIZONTAL; 00152 else 00153 nAxis = INTERSECTION_AXIS_VERTICAL; 00154 } 00155 else 00156 { 00157 // 00158 // This is a "small" overlap. Move the rectangles the 00159 // smallest distance that will fix the overlap. 00160 // 00161 if ((lprcI->right - lprcI->left) <= (lprcI->bottom - lprcI->top)) 00162 nAxis = INTERSECTION_AXIS_HORIZONTAL; 00163 else 00164 nAxis = INTERSECTION_AXIS_VERTICAL; 00165 } 00166 } 00167 00168 // 00169 // We now need to pick the rectangle to move. Move the one 00170 // that is further from the origin along the axis of motion. 00171 // 00172 if (nAxis == INTERSECTION_AXIS_HORIZONTAL) 00173 { 00174 dC1 = ptC1.x; 00175 dC2 = ptC2.x; 00176 } 00177 else 00178 { 00179 dC1 = ptC1.y; 00180 dC2 = ptC2.y; 00181 } 00182 00183 if ((fC1Neg = (dC1 < 0)) != 0) 00184 dC1 *= -1; 00185 00186 if ((fC2Neg = (dC2 < 0)) != 0) 00187 dC2 *= -1; 00188 00189 if (dC2 < dC1) 00190 { 00191 lprcMove = lprc1; 00192 lprcStay = lprc2; 00193 fNegative = fC1Neg; 00194 } 00195 else 00196 { 00197 lprcMove = lprc2; 00198 lprcStay = lprc1; 00199 fNegative = fC2Neg; 00200 } 00201 00202 // 00203 // Compute a new home for the rectangle and put it there. 00204 // 00205 if (nAxis == INTERSECTION_AXIS_HORIZONTAL) 00206 { 00207 int xPos; 00208 00209 if (fNegative) 00210 xPos = lprcStay->left - (lprcMove->right - lprcMove->left); 00211 else 00212 xPos = lprcStay->right; 00213 00214 xOffset = xPos - lprcMove->left; 00215 yOffset = 0; 00216 } 00217 else 00218 { 00219 int yPos; 00220 00221 if (fNegative) 00222 yPos = lprcStay->top - (lprcMove->bottom - lprcMove->top); 00223 else 00224 yPos = lprcStay->bottom; 00225 00226 yOffset = yPos - lprcMove->top; 00227 xOffset = 0; 00228 } 00229 00230 OffsetRect(lprcMove, xOffset, yOffset); 00231 return lprcMove; 00232 }

void NEAR PASCAL RemoveOverlaps LPRECT  arc,
UINT  count
 

Definition at line 241 of file alignrec.c.

References CenterRectangles(), IntersectRect(), and RemoveOverlap().

Referenced by AlignRects().

00242 { 00243 LPRECT lprc1, lprc2, lprcL; 00244 00245 // 00246 // Center the rectangles around a common origin. We will move them outward 00247 // when there are conflicts so centering (a) reduces running time and 00248 // hence (b) reduces the chances of totally mangling the positions. 00249 // 00250 CenterRectangles(arc, count); 00251 00252 // 00253 // Now loop through the array fixing any overlaps. 00254 // 00255 lprcL = arc + count; 00256 lprc2 = arc + 1; 00257 00258 ReScan: 00259 while (lprc2 < lprcL) 00260 { 00261 // 00262 // Scan all rectangles before this one looking for intersections. 00263 // 00264 for (lprc1 = arc; lprc1 < lprc2; lprc1++) 00265 { 00266 RECT rcI; 00267 00268 // 00269 // Move one of the rectanges if there is an intersection. 00270 // 00271 if (IntersectRect(&rcI, lprc1, lprc2)) 00272 { 00273 // 00274 // Move one of the rectangles out of the way and then restart 00275 // the scan for overlaps with that rectangle (since moving it 00276 // may have created new overlaps). 00277 // 00278 lprc2 = RemoveOverlap(lprc1, lprc2, &rcI); 00279 goto ReScan; 00280 } 00281 } 00282 00283 lprc2++; 00284 } 00285 }


Generated on Sat May 15 19:42:50 2004 for test by doxygen 1.3.7