home *** CD-ROM | disk | FTP | other *** search
- /*
- * WICONIFY A utility that allows you to iconify any Intuition window
- * on any screen, and to open WB windows on any screen.
- *
- * wLayout.c Handles placement and rearranging of icons.
- *
- * Copyright 1990 by Davide P. Cervone, all rights reserved.
- * You may use this code, provided this copyright notice is kept intact.
- */
-
- #include "wHandler.h"
-
- static UWORD Xmax; /* maximum number of columns */
- static UWORD Ymax; /* maximum number of rows */
-
- #define XOFFSET 80 /* distance between icons */
- #define YOFFSET 34 /* distance between icons */
- #define XSTART 20 /* Starting X position */
- #define YSTART 28 /* Starting Y position (from bottom) */
- #define YDIFF 10 /* vertical offset for odd rows */
- #define XMAX 32 /* maximum icons in x direction */
- #define YMAX 32 /* maximum icons in y direction */
-
- #define GADGICON ((WICONREF *)theGadget->UserData)
-
-
- /*
- * GetPosition()
- *
- * Get the icon of the gadget (UserData points to the icon)
- * Get the X position of the gadget normalized for varrying widths of icons
- * Find the nearest X column position by dividing by the column width
- * Get the Y position of the gadget normalized by height,with 0 at the bottom
- * Offset the Y position for odd rows
- * Get two different Y row positions (it may cover two positions vertically
- * if it is not exactly placed on the grid)
- */
-
- static void GetPosition(theGadget,X,Y1,Y2)
- struct Gadget *theGadget;
- WORD *X,*Y1,*Y2;
- {
- WICONREF *theIcon = (WICONREF *)theGadget->UserData;
-
- *X = theGadget->LeftEdge + (theGadget->Width - ICONWIDTH) / 2;
- *X = (*X - XSTART + (XOFFSET/2)) / XOFFSET;
- *Y2 = theIcon->Screen->BackDrop->Height - theGadget->TopEdge;
- *Y2 = *Y2 - (theGadget->Height - ICONHEIGHT) - YSTART;
- if ((*X & 1) == 0) *Y2 -= YDIFF;
- *Y1 = (*Y2 + (YOFFSET /4)) / YOFFSET;
- *Y2 = (*Y2 + (YOFFSET*3/4)) / YOFFSET;
- }
-
-
- /*
- * GetPositionArray()
- *
- * Calculate the maximum number of rows and columns, clip to the array size
- * Clear the position array
- * While there are gadgets to work with
- * Get the gadget's position
- * Add it into the array
- * Add its second position into the array unless we are only conncered
- * with where the gadgets "should" be (ie, snapped to the grid)
- * Increment the gadget count if the gadget can be moved
- * Go on to the next gadget
- * Return the number of gadgets counted
- */
-
- static UWORD GetPositionArray(PosArray,theScreen,Snapped)
- ULONG PosArray[];
- WSCREEN *theScreen;
- int Snapped;
- {
- struct Gadget *theGadget = theScreen->BackDrop->FirstGadget;
- WORD X,Y1,Y2;
- UWORD count = 0;
-
- Xmax = (theScreen->BackDrop->Width / XOFFSET);
- Ymax = (theScreen->BackDrop->Height - YSTART) / YOFFSET;
- if (Xmax > XMAX) Xmax = XMAX;
- if (Ymax > YMAX) Ymax = YMAX;
-
- for (Y1 = 0; Y1 < YMAX; Y1++) PosArray[Y1] = 0;
-
- while(theGadget)
- {
- GetPosition(theGadget,&X,&Y1,&Y2);
- PosArray[Y1] |= (1 << X);
- if (Snapped == FALSE) PosArray[Y2] |= (1 << X);
- if ((GADGICON->Icon.Flags & (WI_NOORGANIZE | WI_LOCKED)) == 0) count++;
- theGadget = theGadget->NextGadget;
- }
- return(count);
- }
-
-
- /*
- * ValidPosition()
- *
- * Check the row and column position to make sure it is on screen
- * If not, move it one the screen area
- */
-
- static void ValidPosition(X,Y)
- WORD *X,*Y;
- {
- if (*X < 0) *X = 0;
- if (*Y < 0) *Y = 0;
- if (*X >= Xmax) *X = Xmax - 1;
- if (*Y > Ymax) *Y = Ymax;
- }
-
- /*
- * Offsets for which positions to check when looking for the nearest
- * grid location (used when two icons overlap). There are separate
- * choices for even and odd rows
- */
-
- #define DCOUNT 8
- static WORD dx[2][DCOUNT] =
- {
- { 0, -1, 1, -1, 1, -1, 1, 0},
- { 0, -1, 1, -1, 1, 0, -1, 1}
- };
-
- static WORD dy[2][DCOUNT] =
- {
- {-1, 0, 0, -1, -1, 1, 1, 1},
- {-1, -1, -1, 0, 0, 1, 1, 1}
- };
-
-
- /*
- * FindClosePosition()
- *
- * Check that the icon position is legal
- * If the gadget overlaps another one already in the array
- * Use the correct table for even or odd columns
- * While there are more positions to try
- * Get the new position for the given position
- * Make sure the position is within the screen
- * If the location is free
- * Save the new position and indicate that we're done
- * Indicate that the position is OK
- * Return a statment about whether there was a closeby place free
- */
-
- static int FindClosePosition(PosArray,X,Y,Y2)
- ULONG PosArray[];
- WORD *X,*Y,*Y2;
- {
- int Found = FALSE;
- short i,j;
- WORD Xt,Yt;
-
- ValidPosition(X,Y);
- if ((PosArray[*Y] | PosArray[*Y2]) & (1 << *X))
- {
- j = *X & 1;
- for (i=0; i<DCOUNT && Found == FALSE; i++)
- {
- Xt = *X + dx[j][i];
- Yt = *Y + dy[j][i];
- ValidPosition(&Xt,&Yt);
- if ((PosArray[Yt] & (1 << Xt)) == 0)
- {
- Found = TRUE;
- *X = Xt; *Y = Yt;
- }
- }
- } else Found = TRUE;
- return(Found);
- }
-
-
- /*
- * GetNewPosition()
- *
- * Create a mask with 1's in all the valid column positions
- * Look for the first row with an empty slot
- * If we are past the end of the array,
- * Set the position to the origin (bail out)
- * Otherwise
- * Look through the row from left to right for the first location
- * Verify that what we found really IS an OK position
- */
-
- static void GetNewPosition(PosArray,X,Y)
- ULONG PosArray[];
- WORD *X,*Y;
- {
- ULONG Xmask = (1 << Xmax) - 1;
-
- for (*Y = 0; *Y < Ymax && (PosArray[*Y] & Xmask) == Xmask; (*Y)++);
- if (*Y >= Ymax)
- *Y = *X = 0;
- else
- for (*X = 0, Xmask = 1; PosArray[*Y] & Xmask; (*X)++, Xmask <<= 1);
- ValidPosition(X,Y);
- }
-
-
- /*
- * SetPosition()
- *
- * If the icon is not locked in place
- * Get the current X and Y (in pixels) for the icon's new position
- * (centered the icon horizontally)
- * If the gadget's current location is different
- * Set the gadgets's new position
- * If the icon is supposed to get movement reports, report the change
- */
-
- static void SetPosition(theGadget,X,Y)
- struct Gadget *theGadget;
- WORD X,Y;
- {
- WICONREF *theIcon = (WICONREF *)theGadget->UserData;
-
- if ((theIcon->Icon.Flags & WI_LOCKED) == FALSE)
- {
- Y = theIcon->Screen->BackDrop->Height - YSTART - (Y * YOFFSET);
- if ((X & 1) == 0) Y -= YDIFF;
- X = (X * XOFFSET) + XSTART - (theGadget->Width - ICONWIDTH) / 2;
- Y -= theGadget->Height - ICONHEIGHT;
- if (theGadget->LeftEdge != X || theGadget->TopEdge != Y)
- {
- theGadget->LeftEdge = X; theIcon->Icon.x = X;
- theGadget->TopEdge = Y; theIcon->Icon.y = Y;
- if (theIcon->Icon.Report & WI_REPORTMOVED)
- ReportEvent(WI_REPORTMOVED,theIcon);
- }
- }
- }
-
-
- /*
- * InitPosition()
- *
- * Get the position of the gadget and save it
- * Get the position array for the screen (do not snap icons to the grid)
- * If the gadget already has a position
- * If we can't find a closeby position get the first available one
- * If the position changed, set the new position
- * Otherwise
- * Get the first available position
- * Set the gadget's position
- */
-
- void InitPosition(theGadget)
- struct Gadget *theGadget;
- {
- WICONREF *theIcon = (WICONREF *)theGadget->UserData;
- ULONG PosArray[YMAX];
- WORD X,Y,Y2;
- WORD OldX,OldY;
-
- GetPosition(theGadget,&X,&Y,&Y2); OldX = X; OldY = Y;
- GetPositionArray(PosArray,theIcon->Screen,FALSE);
- if (theGadget->LeftEdge || theGadget->TopEdge)
- {
- if (!FindClosePosition(PosArray,&X,&Y,&Y2))
- GetNewPosition(PosArray,&X,&Y);
- if (X != OldX || Y != OldY) SetPosition(theGadget,X,Y);
- } else {
- GetNewPosition(PosArray,&X,&Y);
- SetPosition(theGadget,X,Y);
- }
- }
-
-
- /*
- * CleanUpIcons()
- *
- * Get the positions of all icons on the screen (no snapping)
- * Clear the temporary array
- * Start with the first gadget on the screen
- * If there are selected gadgets
- * Add all the unselected gadgets to the temporary array
- * Start with the first selected gadget
- * While there are more gadgets to handle
- * Get the gadget's position and validate it
- * If the icon can be moved
- * If the icon's position is already in use
- * Find the closest place, or the next available one
- * Set the gadget's position
- * Add the gadget to the arrays
- * If gadgets are selected, go on to the next selected one
- * Otherwise go on to the next one
- */
-
- void CleanUpIcons(theScreen)
- WSCREEN *theScreen;
- {
- ULONG PosArray[YMAX];
- ULONG TmpArray[YMAX];
- WORD X,Y,Y2;
- short Selected;
- struct wGadget *theGadget;
-
- Forbid();
-
- GetPositionArray(PosArray,theScreen,FALSE);
- for (Y = 0; Y < YMAX; Y++) TmpArray[Y] = 0;
- theGadget = (struct wGadget *)theScreen->BackDrop->FirstGadget;
- Selected = (theScreen->Selected != NULL);
- if (Selected)
- {
- while (theGadget)
- {
- if ((theGadget->Gadget.Flags & SELECTED) == FALSE)
- {
- GetPosition(theGadget,&X,&Y,&Y2);
- TmpArray[Y] |= (1 << X);
- TmpArray[Y2] |= (1 << X);
- }
- theGadget = (struct wGadget *)theGadget->Gadget.NextGadget;
- }
- theGadget = theScreen->Selected;
- }
-
- while (theGadget)
- {
- GetPosition(theGadget,&X,&Y,&Y2);
- ValidPosition(&X,&Y);
- if ((GADGETICON->Icon.Flags & (WI_NOORGANIZE| WI_LOCKED)) == FALSE)
- {
- if ((TmpArray[Y] | TmpArray[Y2]) & (1 << X))
- if (!FindClosePosition(PosArray,&X,&Y,&Y2))
- GetNewPosition(PosArray,&X,&Y);
- SetPosition(theGadget,X,Y);
- }
- TmpArray[Y] |= (1 << X);
- PosArray[Y] |= (1 << X);
- if (Selected)
- theGadget = theGadget->NextSelect;
- else
- theGadget = (struct wGadget *)theGadget->Gadget.NextGadget;
- }
- Permit();
- }
-
-
- /*
- * OrganizeIcons()
- *
- * Start with the first gadget on the screen
- * Count the gadgets and get the position array
- * Find the highest row and the right-most column in that row needed
- * in order to store that many icons
- * Clear the temporary array
- * While there are gadgets to check
- * Get the gadget's position and validate it
- * If the gadget can be moved
- * If the icon's position is in use, or if it is outside the final
- * block of organized icons, get a new position for the gadget
- * Set the gadgets position
- * Save the icon's position in both arrays
- * Move on to the next gadget
- */
-
- void OrganizeIcons(theScreen)
- WSCREEN *theScreen;
- {
- ULONG PosArray[YMAX];
- ULONG TmpArray[YMAX];
- WORD X,Y,Y2;
- WORD RightX, TopY;
- UWORD count;
- struct Gadget *theGadget;
-
- Forbid();
- theGadget = theScreen->BackDrop->FirstGadget;
- count = GetPositionArray(PosArray,theScreen,TRUE);
- TopY = count / Xmax;
- RightX = count - TopY * Xmax;
- for (Y = 0; Y < YMAX; Y++) TmpArray[Y] = 0;
-
- while (theGadget)
- {
- GetPosition(theGadget,&X,&Y,&Y2);
- ValidPosition(&X,&Y);
- if ((GADGICON->Icon.Flags & (WI_NOORGANIZE| WI_LOCKED)) == FALSE)
- {
- if ((TmpArray[Y] & (1 << X)) || Y > TopY || (Y == TopY && X >= RightX))
- GetNewPosition(PosArray,&X,&Y);
- SetPosition(theGadget,X,Y);
- }
- PosArray[Y] |= (1 << X);
- TmpArray[Y] |= (1 << X);
- theGadget = theGadget->NextGadget;
- }
- Permit();
- }
-