Initial import of Scalos. To decrease size I have
[AROS-Contrib.git] / scalos / main / cleanup.c
blobeec5e2372609159d136d0c7a8e69bdd6e456c26d
1 // cleanup.c
2 // $Date$
3 // $Revision$
6 #include <exec/types.h>
7 #include <intuition/classusr.h>
8 #include <dos/datetime.h>
10 #define __USE_SYSBASE
12 #include <proto/exec.h>
13 #include <proto/intuition.h>
14 #include <proto/timer.h>
15 #include "debug.h"
16 #include <proto/scalos.h>
18 #include <clib/alib_protos.h>
20 #include <intuition/classusr.h>
21 #include <workbench/workbench.h>
22 #include <workbench/startup.h>
24 #include <defs.h>
25 #include <scalos/scalos.h>
27 #include <string.h>
28 #include <stdio.h>
30 #include "scalos_structures.h"
31 #include "Variables.h"
32 #include "functions.h"
34 //----------------------------------------------------------------------------
36 #define TILE_SIZE_X 4
37 #define TILE_SIZE_Y 4
39 //----------------------------------------------------------------------------
41 enum PlacementMode
43 PLACEMENT_TopDown,
44 PLACEMENT_LeftRight,
47 struct TilesInfo
49 ULONG tli_WindowWidth; // Width of tile array, in window coordinates
50 ULONG tli_WindowHeight; // Height of tile array, in window coordinates
51 ULONG tli_NumberOfRows; // Total number of rows in tile array
52 ULONG tli_NumberOfColumns; // Total number of columns in tile array
53 ULONG tli_BytesPerRow; // Number of octets per row in tile array
54 enum PlacementMode tli_Placement;
55 UBYTE tli_TileMemory[1]; // Array of allocated tiles, one bit per tile
58 //----------------------------------------------------------------------------
60 static BOOL INLINE TestTilesLocation(const struct TilesInfo *tli, LONG x, LONG y);
61 static void INLINE MarkTilesLocation(struct TilesInfo *tli, LONG x, LONG y);
62 static LONG INLINE LimitTo(LONG Value, LONG MinVal, LONG MaxVal);
63 static struct TilesInfo *CreateTilesInfo(const struct internalScaWindowTask *iwt,
64 enum PlacementMode Placement, const struct Rect32 *AreaBounds);
65 static void DisposeTilesInfo(struct TilesInfo *tli);
66 static BOOL IsSpaceFreeInTilesArray(const struct TilesInfo *tli, const struct Rect32 *pos);
67 static void MarkSpaceInTilesArray(struct TilesInfo *tli, const struct Rect32 *pos);
68 static void IconPositionToTilePosition(const struct internalScaWindowTask *iwt,
69 const struct TilesInfo *tli,
70 const struct Rect32 *WindowPosition, struct Rect32 *TilePosition);
71 static void AddIconToTilesInfo(const struct internalScaWindowTask *iwt,
72 struct TilesInfo *tli, const struct ScaIconNode *in);
73 static void FindFreeLocationInTilesInfoTopDown(const struct internalScaWindowTask *iwt,
74 struct TilesInfo *tli, struct ScaIconNode *in, LONG XStart, LONG YStart,
75 const struct Rect32 *LayoutAreaBounds, LONG *x, LONG *y);
76 static void FindFreeLocationInTilesInfoLeftRight(const struct internalScaWindowTask *iwt,
77 struct TilesInfo *tli, struct ScaIconNode *in, LONG XStart, LONG YStart,
78 const struct Rect32 *LayoutAreaBounds, LONG *x, LONG *y);
79 static void LayoutIconsTopDown(struct internalScaWindowTask *iwt,
80 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
81 const struct Rect32 *LayoutAreaBounds, const struct Rect32 *MaxAreaBounds);
82 static void SimpleLayoutIconsTopDown(struct internalScaWindowTask *iwt,
83 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
84 const struct Rect32 *LayoutAreaBounds);
85 static void LayoutIconsLeftRight(struct internalScaWindowTask *iwt,
86 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
87 const struct Rect32 *LayoutAreaBounds, const struct Rect32 *MaxAreaBounds);
88 static void SimpleLayoutIconsLeftRight(struct internalScaWindowTask *iwt,
89 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
90 const struct Rect32 *LayoutAreaBounds);
91 static void MoveIconToPositionXY(struct ScaIconNode *in, LONG x, LONG y);
92 static void GetIconBoundingBox(const struct ScaIconNode *in, struct Rect32 *Bounds);
93 static void DrawIconList(struct internalScaWindowTask *iwt,
94 struct ScaIconNode **RedrawIconList);
95 static void RedrawIcon(struct internalScaWindowTask *iwt, struct ScaIconNode *in);
96 static void CalculateMaximumIconAreaDimensions(const struct internalScaWindowTask *iwt, struct Rect32 *Bounds);
97 static void AddPositionedIconsToTiles(const struct internalScaWindowTask *iwt,
98 struct TilesInfo *tli);
100 //----------------------------------------------------------------------------
102 void IconWindow_UnCleanup(struct internalScaWindowTask *iwt, struct Region *UnCleanUpRegion)
104 struct ScaIconNode *in, *inNext;
106 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
108 ScalosLockIconListExclusive(iwt);
110 d1(KPrintF("%s/%s/%ld:\n", __LINE__));
112 for (in=iwt->iwt_WindowTask.wt_IconList; in; in = inNext)
114 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
116 d1(KPrintF("%s/%s/%ld: in=%08lx <%s> inFlags=%08lx\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in), in->in_Flags));
118 if (in->in_Flags & INF_FreeIconPosition)
120 BOOL MoveIcon = FALSE;
121 struct ExtGadget *gg = (struct ExtGadget *) in->in_Icon;
123 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
125 if (UnCleanUpRegion)
127 // Do not uncleanup any icon which lies outside of <UnCleanUpRegion>
128 struct Rectangle IconRect;
130 IconRect.MinX = IconRect.MaxX = gg->BoundsLeftEdge;
131 IconRect.MinY = IconRect.MaxY = gg->BoundsTopEdge;
132 IconRect.MaxX += gg->BoundsWidth;
133 IconRect.MaxY += gg->BoundsHeight;
135 if (ScaRectInRegion(UnCleanUpRegion, &IconRect))
136 MoveIcon = TRUE;
138 else
140 MoveIcon = TRUE;
143 if (MoveIcon)
145 in->in_OldLeftEdge = gg->LeftEdge;
146 in->in_OldTopEdge = gg->TopEdge;
148 in->in_Flags |= INF_IconVisible;
150 SCA_MoveIconNode(&iwt->iwt_WindowTask.wt_IconList,
151 &iwt->iwt_WindowTask.wt_LateIconList, in);
156 ScalosUnLockIconList(iwt);
158 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
162 void IconWindow_Cleanup(struct internalScaWindowTask *iwt)
164 d1(KPrintF("%s/%s/%ld: START iwt=%08lx <%s>\n", __FILE__, __FUNC__, __LINE__, iwt, iwt->iwt_WinTitle));
165 TIMESTAMP_d1();
167 ScalosLockIconListExclusive(iwt);
169 if (iwt->iwt_WindowTask.wt_LateIconList)
171 // This list collects all (re)positioned icons
172 struct ScaIconNode *RedrawIconList = NULL;
173 struct Rect32 LayoutAreaBounds;
174 struct ScaIconNode *in, *inNext;
175 struct ScaIconNode *LateIconList;
176 struct ScaIconNode *RowLayoutIconList = NULL;
177 struct Rect32 MaxAreaBounds;
179 CalculateMaximumIconAreaDimensions(iwt, &MaxAreaBounds);
181 d1(KPrintF("%s/%s/%ld: MaxAreaBounds: MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
182 __FILE__, __FUNC__, __LINE__, MaxAreaBounds.MinX, MaxAreaBounds.MinY, \
183 MaxAreaBounds.MaxX, MaxAreaBounds.MaxY));
185 LateIconList = iwt->iwt_WindowTask.wt_LateIconList;
186 iwt->iwt_WindowTask.wt_LateIconList = NULL;
188 ScalosUnLockIconList(iwt);
191 // Move all icons with ICONLAYOUT_Rows to RowLayoutIconList
192 for (in = LateIconList; in; in = inNext)
194 enum IconLayoutMode LayoutMode;
195 ULONG IconType;
197 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
199 GetAttr(IDTA_Type, in->in_Icon, &IconType);
201 if (IconType < sizeof(iwt->iwt_IconLayoutInfo.ili_IconTypeLayoutModes))
202 LayoutMode = iwt->iwt_IconLayoutInfo.ili_IconTypeLayoutModes[IconType];
203 else
204 LayoutMode = ICONLAYOUT_Columns; // default
206 if (ICONLAYOUT_Rows == LayoutMode)
208 SCA_MoveIconNode(&LateIconList,
209 &RowLayoutIconList, in);
213 TIMESTAMP_d1();
215 if (RowLayoutIconList)
217 // Layout all icons with ICONLAYOUT_Rows mode
218 LayoutAreaBounds.MinX = CurrentPrefs.pref_CleanupSpace.Left + iwt->iwt_WindowTask.wt_XOffset;
219 LayoutAreaBounds.MinY = CurrentPrefs.pref_CleanupSpace.Top + iwt->iwt_WindowTask.wt_YOffset;
220 LayoutAreaBounds.MaxX = iwt->iwt_InnerWidth + iwt->iwt_WindowTask.wt_XOffset;
221 LayoutAreaBounds.MaxY = SHRT_MAX;
223 while (MaxAreaBounds.MaxY > SHRT_MAX)
225 LayoutAreaBounds.MaxX *= 2;
226 MaxAreaBounds.MaxY /= 2;
229 LayoutIconsLeftRight(iwt, &RedrawIconList,
230 &RowLayoutIconList, &LayoutAreaBounds, &MaxAreaBounds);
231 TIMESTAMP_d1();
233 // Redraw all icons in RedrawIconList and move them to wt_IconList
234 DrawIconList(iwt, &RedrawIconList);
237 TIMESTAMP_d1();
239 if (LateIconList)
241 // Layout all remaining icons with ICONLAYOUT_Columns mode
242 LayoutAreaBounds.MinX = CurrentPrefs.pref_CleanupSpace.Left + iwt->iwt_WindowTask.wt_XOffset;
243 LayoutAreaBounds.MinY = CurrentPrefs.pref_CleanupSpace.Top + iwt->iwt_WindowTask.wt_YOffset;
244 LayoutAreaBounds.MaxX = SHRT_MAX;
245 LayoutAreaBounds.MaxY = iwt->iwt_InnerHeight + iwt->iwt_WindowTask.wt_YOffset;
247 while (MaxAreaBounds.MaxX > SHRT_MAX)
249 LayoutAreaBounds.MaxY *= 2;
250 MaxAreaBounds.MaxX /= 2;
253 LayoutIconsTopDown(iwt, &RedrawIconList,
254 &LateIconList, &LayoutAreaBounds, &MaxAreaBounds);
255 TIMESTAMP_d1();
257 // Redraw all icons in RedrawIconList and move them to wt_IconList
258 DrawIconList(iwt, &RedrawIconList);
261 else
263 ScalosUnLockIconList(iwt);
266 TIMESTAMP_d1();
268 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
271 //----------------------------------------------------------------------------
273 static BOOL INLINE TestTilesLocation(const struct TilesInfo *tli, LONG x, LONG y)
275 ULONG BitMask = 1 << (x & (CHAR_BIT - 1));
276 const UBYTE *p = tli->tli_TileMemory
277 + (y * tli->tli_BytesPerRow) + (x / CHAR_BIT);
279 d1(KPrintF("%s/%s/%ld: x=%ld y=%ld p=%08lx BitMask=%02lx\n", \
280 __FILE__, __FUNC__, __LINE__, x, y, p, BitMask));
282 return (BOOL) (*p & BitMask);
286 static void INLINE MarkTilesLocation(struct TilesInfo *tli, LONG x, LONG y)
288 ULONG BitMask = 1 << (x & (CHAR_BIT - 1));
289 UBYTE *p = tli->tli_TileMemory
290 + (y * tli->tli_BytesPerRow) + (x / CHAR_BIT);
292 d1(KPrintF("%s/%s/%ld: x=%ld y=%ld p=%08lx BitMask=%02lx\n", \
293 __FILE__, __FUNC__, __LINE__, x, y, p, BitMask));
295 *p |= BitMask;
299 static LONG INLINE LimitTo(LONG Value, LONG MinVal, LONG MaxVal)
301 if (Value < MinVal)
302 Value = MinVal;
303 if (Value > MaxVal)
304 Value = MaxVal;
306 return Value;
310 static struct TilesInfo *CreateTilesInfo(const struct internalScaWindowTask *iwt,
311 enum PlacementMode Placement, const struct Rect32 *AreaBounds)
313 struct TilesInfo *tli;
314 LONG TilesArrayWidth, TilesArrayHeight;
315 ULONG NumberOfColumns;
316 ULONG NumberOfRows;
317 size_t TilesLength;
318 ULONG BytesPerRow;
320 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
322 switch (Placement)
324 case PLACEMENT_TopDown:
325 TilesArrayHeight = iwt->iwt_InnerHeight;
326 TilesArrayWidth = 1 + AreaBounds->MaxX;
327 break;
328 case PLACEMENT_LeftRight:
329 TilesArrayWidth = iwt->iwt_InnerWidth;
330 TilesArrayHeight = 1 + AreaBounds->MaxY;
331 break;
332 default:
333 return NULL;
334 break;
337 // make sure tiles array is alway at least as large as inner window area
338 if (TilesArrayWidth < iwt->iwt_InnerWidth)
339 TilesArrayWidth = iwt->iwt_InnerWidth;
340 if (TilesArrayHeight < iwt->iwt_InnerHeight)
341 TilesArrayHeight = iwt->iwt_InnerHeight;
343 d1(KPrintF("%s/%s/%ld: TilesArrayWidth=%lu TilesArrayHeight=%lu\n", \
344 __FILE__, __FUNC__, __LINE__, TilesArrayWidth, TilesArrayHeight));
346 NumberOfColumns = TilesArrayWidth / TILE_SIZE_X;
347 NumberOfRows = TilesArrayHeight / TILE_SIZE_Y;
349 if (0 == NumberOfColumns || 0 == NumberOfRows)
350 return NULL;
352 BytesPerRow = (NumberOfColumns + CHAR_BIT - 1) / CHAR_BIT; // round up to ceiling
353 TilesLength = NumberOfRows * BytesPerRow;
355 tli = ScalosAlloc(sizeof(struct TilesInfo) + TilesLength);
356 if (NULL == tli)
357 return NULL;
359 tli->tli_NumberOfColumns = NumberOfColumns;
360 tli->tli_NumberOfRows = NumberOfRows;
361 tli->tli_WindowWidth = TilesArrayWidth;
362 tli->tli_WindowHeight = TilesArrayHeight;
363 tli->tli_BytesPerRow = BytesPerRow; // round up to ceiling
364 tli->tli_Placement = Placement;
366 d1(KPrintF("%s/%s/%ld: NumberOfColumns=%lu NumberOfRows=%lu AllocSize=%lu BytesPerRow=%lu\n", \
367 __FILE__, __FUNC__, __LINE__, NumberOfColumns, NumberOfRows, tli->tli_BytesPerRow));
369 // mark all tiles as free
370 memset(tli->tli_TileMemory, 0, TilesLength);
372 d1(KPrintF("%s/%s/%ld: END tli=%08lx\n", __FILE__, __FUNC__, __LINE__, tli));
374 return tli;
378 static void DisposeTilesInfo(struct TilesInfo *tli)
380 d1(KPrintF("%s/%s/%ld: START tli=%08lx\n", __FILE__, __FUNC__, __LINE__, tli));
381 ScalosFree(tli);
382 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
386 static BOOL IsSpaceFreeInTilesArray(const struct TilesInfo *tli, const struct Rect32 *pos)
388 LONG x;
390 d1(KPrintF("%s/%s/%ld: START tli=%08lx MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
391 __FILE__, __FUNC__, __LINE__, tli, pos->MinX, pos->MinY, pos->MaxX, pos->MaxY));
393 // areas outside of tiles array are considered occupied
394 if (!(pos->MinX >= 0 && pos->MinX < tli->tli_NumberOfColumns)
395 || !(pos->MinY >= 0 && pos->MinY < tli->tli_NumberOfRows)
396 || !(pos->MaxX >= 0 && pos->MaxX < tli->tli_NumberOfColumns)
397 || !(pos->MaxY >= 0 && pos->MaxY < tli->tli_NumberOfRows))
398 return FALSE;
400 for (x = pos->MinX; x <= pos->MaxX; x++)
402 LONG y;
404 for (y = pos->MinY; y <= pos->MaxY; y++)
406 if (TestTilesLocation(tli, x, y))
408 // This tile is occupied
409 return FALSE;
414 // All tiles required for <pos> are free
415 return TRUE;
419 static void MarkSpaceInTilesArray(struct TilesInfo *tli, const struct Rect32 *pos)
421 struct Rect32 Bounds;
422 LONG x;
424 d1(KPrintF("%s/%s/%ld: START tli=%08lx MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
425 __FILE__, __FUNC__, __LINE__, tli, pos->MinX, pos->MinY, pos->MaxX, pos->MaxY));
427 // make sure marking is limited to size of tiles array
428 Bounds.MinX = LimitTo(pos->MinX, 0, tli->tli_NumberOfColumns);
429 Bounds.MaxX = LimitTo(pos->MaxX, 0, tli->tli_NumberOfColumns);
430 Bounds.MinY = LimitTo(pos->MinY, 0, tli->tli_NumberOfRows);
431 Bounds.MaxY = LimitTo(pos->MaxY, 0, tli->tli_NumberOfRows);
433 for (x = Bounds.MinX; x <= Bounds.MaxX; x++)
435 LONG y;
437 for (y = Bounds.MinY; y <= Bounds.MaxY; y++)
439 MarkTilesLocation(tli, x, y);
444 static void IconPositionToTilePosition(const struct internalScaWindowTask *iwt,
445 const struct TilesInfo *tli,
446 const struct Rect32 *WindowPosition, struct Rect32 *TilePosition)
448 d1(KPrintF("%s/%s/%ld: START tli=%08lx MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
449 __FILE__, __FUNC__, __LINE__, tli, WindowPosition->MinX, WindowPosition->MinY, WindowPosition->MaxX, WindowPosition->MaxY));
451 TilePosition->MinX = (WindowPosition->MinX + iwt->iwt_WindowTask.wt_XOffset) / TILE_SIZE_X;
452 TilePosition->MinY = (WindowPosition->MinY + iwt->iwt_WindowTask.wt_YOffset) / TILE_SIZE_Y;
453 TilePosition->MaxX = (WindowPosition->MaxX + iwt->iwt_WindowTask.wt_XOffset + (TILE_SIZE_X - 1)) / TILE_SIZE_X;
454 TilePosition->MaxY = (WindowPosition->MaxY + iwt->iwt_WindowTask.wt_YOffset + (TILE_SIZE_Y - 1)) / TILE_SIZE_Y;;
456 TilePosition->MinX = LimitTo(TilePosition->MinX, 0, tli->tli_NumberOfColumns - 1);
457 TilePosition->MinY = LimitTo(TilePosition->MinY, 0, tli->tli_NumberOfRows - 1);
458 TilePosition->MaxX = LimitTo(TilePosition->MaxX, TilePosition->MinX, tli->tli_NumberOfColumns - 1);
459 TilePosition->MaxY = LimitTo(TilePosition->MaxY, TilePosition->MinY, tli->tli_NumberOfRows - 1);
461 d1(KPrintF("%s/%s/%ld: END tli=%08lx MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
462 __FILE__, __FUNC__, __LINE__, tli, TilePosition->MinX, TilePosition->MinY, TilePosition->MaxX, TilePosition->MaxY));
466 static void AddIconToTilesInfo(const struct internalScaWindowTask *iwt,
467 struct TilesInfo *tli, const struct ScaIconNode *in)
469 struct Rect32 IconBounds;
470 struct Rect32 TilesArrayPos;
472 d1(KPrintF("%s/%s/%ld: START tli=%08lx in=%08lx <%s>\n", \
473 __FILE__, __FUNC__, __LINE__, tli, in, GetIconName((struct ScaIconNode *) in)));
475 GetIconBoundingBox(in, &IconBounds);
477 d1(KPrintF("%s/%s/%ld: MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
478 __FILE__, __FUNC__, __LINE__, IconBounds.MinX, IconBounds.MinY, \
479 IconBounds.MaxX, IconBounds.MaxY));
481 IconPositionToTilePosition(iwt, tli, &IconBounds, &TilesArrayPos);
482 MarkSpaceInTilesArray(tli, &TilesArrayPos);
484 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
488 static void FindFreeLocationInTilesInfoTopDown(const struct internalScaWindowTask *iwt,
489 struct TilesInfo *tli, struct ScaIconNode *in, LONG XStart, LONG YStart,
490 const struct Rect32 *LayoutAreaBounds, LONG *x, LONG *y)
492 ULONG IconWidth, IconHeight;
493 struct Rect32 IconBounds;
494 BOOL SpaceIsOccupied;
496 d1(KPrintF("%s/%s/%ld: START tli=%08lx in=%08lx <%s> startx=%ld starty=%ld\n", \
497 __FILE__, __FUNC__, __LINE__, tli, in, GetIconName(in), XStart, YStart));
498 d1(KPrintF("%s/%s/%ld: tli_NumberOfColumns=%ld tli_NumberOfRows=%ld\n", \
499 __FILE__, __FUNC__, __LINE__, tli->tli_NumberOfColumns, tli->tli_NumberOfRows));
501 GetIconBoundingBox(in, &IconBounds);
503 IconWidth = 1 + IconBounds.MaxX - IconBounds.MinX;
504 IconHeight = 1 + IconBounds.MaxY - IconBounds.MinY;
506 IconBounds.MinX = XStart;
507 IconBounds.MinY = YStart;
508 IconBounds.MaxX = IconBounds.MinX + IconWidth;
509 IconBounds.MaxY = IconBounds.MinY + IconHeight;
511 d1(KPrintF("%s/%s/%ld: IconBounds MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
512 __FILE__, __FUNC__, __LINE__, IconBounds.MinX, IconBounds.MaxX,\
513 IconBounds.MinY, IconBounds.MaxY));
514 d1(KPrintF("%s/%s/%ld: LayoutAreaBounds MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
515 __FILE__, __FUNC__, __LINE__, LayoutAreaBounds->MinX, LayoutAreaBounds->MaxX,\
516 LayoutAreaBounds->MinY, LayoutAreaBounds->MaxY));
518 do {
519 struct Rect32 TilePosition;
521 SpaceIsOccupied = FALSE;
523 IconPositionToTilePosition(iwt, tli, &IconBounds, &TilePosition);
525 if (!IsSpaceFreeInTilesArray(tli, &TilePosition))
527 SpaceIsOccupied = TRUE;
529 IconBounds.MinY += TILE_SIZE_Y;
530 IconBounds.MaxY = IconBounds.MinY + IconHeight - 1;
532 if (IconBounds.MaxY + CurrentPrefs.pref_CleanupSpace.YSkip > LayoutAreaBounds->MaxY)
534 // Icon doesn't fit into column - move to the next one
537 d1(KPrintF("%s/%s/%ld: MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
538 __FILE__, __FUNC__, __LINE__, IconBounds.MinX, IconBounds.MaxX,\
539 IconBounds.MinY, IconBounds.MaxY));
540 d1(KPrintF("%s/%s/%ld: TilePosition MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
541 __FILE__, __FUNC__, __LINE__, TilePosition.MinX, TilePosition.MaxX,\
542 TilePosition.MinY, TilePosition.MaxY));
545 IconBounds.MinY = CurrentPrefs.pref_CleanupSpace.Top + TILE_SIZE_Y;
546 IconBounds.MaxY = IconBounds.MinY + IconHeight;
548 IconBounds.MinX += TILE_SIZE_X;
549 IconBounds.MaxX = IconBounds.MinX + IconWidth;
551 if (IconBounds.MinX > 32000)
552 d1(KPrintF("%s/%s/%ld: MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
553 __FILE__, __FUNC__, __LINE__, IconBounds.MinX, IconBounds.MaxX,\
554 IconBounds.MinY, IconBounds.MaxY));
557 } while (SpaceIsOccupied && (IconBounds.MaxX <= LayoutAreaBounds->MaxX));
559 d1(KPrintF("%s/%s/%ld: MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
560 __FILE__, __FUNC__, __LINE__, IconBounds.MinX, IconBounds.MaxX,\
561 IconBounds.MinY, IconBounds.MaxY));
563 *x = IconBounds.MinX;
564 *y = IconBounds.MinY;
566 d1(KPrintF("%s/%s/%ld: END x=%ld y=%ld\n", __FILE__, __FUNC__, __LINE__, *x, *y));
570 static void FindFreeLocationInTilesInfoLeftRight(const struct internalScaWindowTask *iwt,
571 struct TilesInfo *tli, struct ScaIconNode *in, LONG XStart, LONG YStart,
572 const struct Rect32 *LayoutAreaBounds, LONG *x, LONG *y)
574 ULONG IconWidth, IconHeight;
575 struct Rect32 IconBounds;
576 BOOL SpaceIsOccupied;
578 d1(KPrintF("%s/%s/%ld: START tli=%08lx in=%08lx <%s> startx=%ld starty=%ld\n", \
579 __FILE__, __FUNC__, __LINE__, tli, in, GetIconName(in), XStart, YStart));
581 GetIconBoundingBox(in, &IconBounds);
583 IconWidth = 1 + IconBounds.MaxX - IconBounds.MinX;
584 IconHeight = 1 + IconBounds.MaxY - IconBounds.MinY;
586 IconBounds.MinX = XStart;
587 IconBounds.MinY = YStart;
588 IconBounds.MaxX = IconBounds.MinX + IconWidth;
589 IconBounds.MaxY = IconBounds.MinY + IconHeight;
591 do {
592 struct Rect32 TilePosition;
594 SpaceIsOccupied = FALSE;
596 IconPositionToTilePosition(iwt, tli, &IconBounds, &TilePosition);
598 if (!IsSpaceFreeInTilesArray(tli, &TilePosition))
600 SpaceIsOccupied = TRUE;
602 IconBounds.MinX += TILE_SIZE_X;
603 IconBounds.MaxX = IconBounds.MinX + IconWidth - 1;
605 if (IconBounds.MaxX + CurrentPrefs.pref_CleanupSpace.XSkip > LayoutAreaBounds->MaxX)
607 // Icon doesn't fit into row - move to the next one
608 IconBounds.MinX = CurrentPrefs.pref_CleanupSpace.Left + TILE_SIZE_X;
609 IconBounds.MaxX = IconBounds.MinX + IconWidth;
611 IconBounds.MinY += TILE_SIZE_Y;
612 IconBounds.MaxY = IconBounds.MinY + IconHeight;
615 } while (SpaceIsOccupied && (IconBounds.MaxY <= LayoutAreaBounds->MaxY));
617 d1(KPrintF("%s/%s/%ld: MinX=%ld MaxX=%ld MinY=%ld MaxY=%ld\n", \
618 __FILE__, __FUNC__, __LINE__, IconBounds.MinX, IconBounds.MaxX,\
619 IconBounds.MinY, IconBounds.MaxY));
621 *x = IconBounds.MinX;
622 *y = IconBounds.MinY;
624 d1(KPrintF("%s/%s/%ld: END x=%ld y=%ld\n", __FILE__, __FUNC__, __LINE__, *x, *y));
628 static void LayoutIconsTopDown(struct internalScaWindowTask *iwt,
629 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
630 const struct Rect32 *LayoutAreaBounds, const struct Rect32 *MaxAreaBounds)
632 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
634 // Check which icons have not been positioned
635 if (iwt->iwt_WindowTask.wt_IconList)
637 LONG x, y;
638 struct Rect32 IconBounds;
639 struct TilesInfo *tli;
641 tli = CreateTilesInfo(iwt, PLACEMENT_TopDown, MaxAreaBounds);
642 d1(KPrintF("%s/%s/%ld: tli=%08lx\n", __FILE__, __FUNC__, __LINE__, tli));
643 if (tli)
645 struct ScaIconNode *in, *inNext;
647 // Add all placed icons to tiles array,
648 // and mark their positions as occupied
649 AddPositionedIconsToTiles(iwt, tli);
651 // Start the icon placement at (LayoutAreaBounds->MinX, LayoutAreaBounds->MinY)
652 x = LayoutAreaBounds->MinX;
653 y = LayoutAreaBounds->MinY;
655 // Find best locations for unpositioned icons
656 for (in = *UnpositionedIconList; in; in = inNext)
658 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
660 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
662 GetIconBoundingBox(in, &IconBounds);
664 FindFreeLocationInTilesInfoTopDown(iwt,
665 tli, in,
667 LayoutAreaBounds->MinY,
668 LayoutAreaBounds, &x, &y);
670 d1(KPrintF("%s/%s/%ld: in_Icon=%08lx x=%ld y=%ld\n", __FILE__, __FUNC__, __LINE__, in->in_Icon, x, y));
671 MoveIconToPositionXY(in, x, y);
673 // move icon to list of positioned icons
674 SCA_MoveIconNode(UnpositionedIconList,
675 RedrawIconList, in);
677 AddIconToTilesInfo(iwt, tli, in);
680 DisposeTilesInfo(tli);
683 else
685 // We only have unpositioned icons,
686 // so we don't need to bother whether space is free.
687 SimpleLayoutIconsTopDown(iwt, RedrawIconList,
688 UnpositionedIconList, LayoutAreaBounds);
690 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
694 // Layout icons top-down in columns
695 // Since we have no placed icons, there's no need to check
696 // if any area is occupied
697 static void SimpleLayoutIconsTopDown(struct internalScaWindowTask *iwt,
698 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
699 const struct Rect32 *LayoutAreaBounds)
701 LONG MaxWidth, ColumnWidth, IconWidth, IconHeight;
702 LONG x, y;
703 struct Rect32 IconBounds;
705 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
707 x = LayoutAreaBounds->MinX;
709 while (*UnpositionedIconList)
711 struct ScaIconNode *in, *inNext;
712 LONG XCenter;
714 y = LayoutAreaBounds->MinY;
716 MaxWidth = 0;
718 // Calculate width for column
719 for (in = *UnpositionedIconList;
720 in; in = (struct ScaIconNode *) in->in_Node.mln_Succ)
722 GetIconBoundingBox(in, &IconBounds);
724 IconWidth = 1 + IconBounds.MaxX - IconBounds.MinX;
725 IconHeight = 1 + IconBounds.MaxY - IconBounds.MinY;
727 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
728 d1(KPrintF("%s/%s/%ld: width=%ld height=%ld\n", __FILE__, __FUNC__, __LINE__, IconWidth, IconHeight));
730 // Check if there is still room in the column
731 if (y != CurrentPrefs.pref_CleanupSpace.Top && y > LayoutAreaBounds->MaxY - IconHeight)
733 break;
736 if (MaxWidth < IconWidth)
738 MaxWidth = IconWidth;
741 y += IconHeight + CurrentPrefs.pref_CleanupSpace.YSkip;
744 y = LayoutAreaBounds->MinY;
746 XCenter = x + MaxWidth / 2;
747 ColumnWidth = MaxWidth;
749 // Position icons in column
750 for (in = *UnpositionedIconList; in; in = inNext)
752 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
754 GetIconBoundingBox(in, &IconBounds);
756 IconWidth = 1 + IconBounds.MaxX - IconBounds.MinX;
757 IconHeight = 1 + IconBounds.MaxY - IconBounds.MinY;
759 d1(KPrintF("%s/%s/%ld: in=%08lx <%s> y=%ld\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in), y));
761 // Check and see if we need to move to a new column
762 if (y != CurrentPrefs.pref_CleanupSpace.Top && y > LayoutAreaBounds->MaxY - IconHeight)
764 // proceed to next column
765 x += ColumnWidth + CurrentPrefs.pref_CleanupSpace.XSkip;
766 break;
769 MoveIconToPositionXY(in,
770 XCenter - IconWidth / 2, y);
772 // move icon to list of positioned icons
773 SCA_MoveIconNode(UnpositionedIconList,
774 RedrawIconList, in);
776 y += IconHeight + CurrentPrefs.pref_CleanupSpace.YSkip;
779 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
783 // Layout icons left to right, one row at a time.
784 static void LayoutIconsLeftRight(struct internalScaWindowTask *iwt,
785 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
786 const struct Rect32 *LayoutAreaBounds, const struct Rect32 *MaxAreaBounds)
788 d1(KPrintF("%s/%s/%ld: START LayoutAreaBounds->MinY=%ld\n", __FILE__, __FUNC__, __LINE__, LayoutAreaBounds->MinY));
790 // Check which icons have not been positioned
791 if (iwt->iwt_WindowTask.wt_IconList)
793 LONG x, y;
794 struct Rect32 IconBounds;
795 struct TilesInfo *tli;
797 tli = CreateTilesInfo(iwt, PLACEMENT_TopDown, MaxAreaBounds);
798 d1(KPrintF("%s/%s/%ld: tli=%08lx\n", __FILE__, __FUNC__, __LINE__, tli));
799 if (tli)
801 struct ScaIconNode *in, *inNext;
803 // Add all placed icons to tiles array,
804 // and mark their positions as occupied
805 AddPositionedIconsToTiles(iwt, tli);
807 // Start the icon placement at (LayoutAreaBounds->MinX, LayoutAreaBounds->MinY)
808 x = LayoutAreaBounds->MinX;
809 y = LayoutAreaBounds->MinY;
811 // Find best locations for unpositioned icons
812 for (in = *UnpositionedIconList; in; in = inNext)
814 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
816 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
818 GetIconBoundingBox(in, &IconBounds);
820 FindFreeLocationInTilesInfoLeftRight(iwt,
821 tli, in,
822 LayoutAreaBounds->MinX,
824 LayoutAreaBounds, &x, &y);
826 d1(KPrintF("%s/%s/%ld: x=%ld y=%ld\n", __FILE__, __FUNC__, __LINE__, x, y));
827 MoveIconToPositionXY(in, x, y);
829 // move icon to list of positioned icons
830 SCA_MoveIconNode(UnpositionedIconList,
831 RedrawIconList, in);
833 AddIconToTilesInfo(iwt, tli, in);
836 DisposeTilesInfo(tli);
839 else
841 // We only have unpositioned icons,
842 // so we don't need to bother whether space is free.
843 SimpleLayoutIconsLeftRight(iwt, RedrawIconList,
844 UnpositionedIconList, LayoutAreaBounds);
847 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
851 // Layout icons left to right in rows
852 // Since we have no placed icons, there's no need to check
853 // if any area is occupied
854 static void SimpleLayoutIconsLeftRight(struct internalScaWindowTask *iwt,
855 struct ScaIconNode **RedrawIconList, struct ScaIconNode **UnpositionedIconList,
856 const struct Rect32 *LayoutAreaBounds)
858 LONG x, y;
859 ULONG MaxHeight, RowHeight;
861 d1(KPrintF("%s/%s/%ld: START LayoutAreaBounds->MinY=%ld\n", __FILE__, __FUNC__, __LINE__, LayoutAreaBounds->MinY));
863 y = LayoutAreaBounds->MinY;
865 while (*UnpositionedIconList)
867 struct Rect32 IconBounds;
868 struct ScaIconNode *in, *inNext;
869 LONG IconWidth, IconHeight;
870 LONG YCenter;
872 x = LayoutAreaBounds->MinX;
874 MaxHeight = 0;
876 // Calculate height for row
877 for (in = *UnpositionedIconList;
879 in = (struct ScaIconNode *) in->in_Node.mln_Succ)
881 GetIconBoundingBox(in, &IconBounds);
883 IconWidth = 1 + IconBounds.MaxX - IconBounds.MinX;
884 IconHeight = 1 + IconBounds.MaxY - IconBounds.MinY;
886 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
888 // Check if there is still room in the row
889 if (x != CurrentPrefs.pref_CleanupSpace.Left && x > LayoutAreaBounds->MaxX - IconWidth)
891 break;
894 if (MaxHeight < IconHeight)
895 MaxHeight = IconHeight;
897 x += IconWidth + CurrentPrefs.pref_CleanupSpace.XSkip;
900 x = LayoutAreaBounds->MinX;
902 YCenter = y + MaxHeight / 2;
903 RowHeight = MaxHeight;
905 // Position icons in row
906 for (in = *UnpositionedIconList; in; in = inNext)
908 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
910 GetIconBoundingBox(in, &IconBounds);
912 IconWidth = 1 + IconBounds.MaxX - IconBounds.MinX;
913 IconHeight = 1 + IconBounds.MaxY - IconBounds.MinY;
915 d1(KPrintF("%s/%s/%ld: in=%08lx <%s> y=%ld\n", __FILE__, __FUNC__, __LINE__, in, GetIconName(in), y));
917 // Check and see if we need to move to a new row
918 if (x != CurrentPrefs.pref_CleanupSpace.Left && x > LayoutAreaBounds->MaxX - IconWidth)
920 // proceed to next row
921 y += RowHeight + CurrentPrefs.pref_CleanupSpace.YSkip;
922 break;
925 MoveIconToPositionXY(in,
926 x, YCenter - IconHeight / 2);
928 // move icon to list of positioned icons
929 SCA_MoveIconNode(UnpositionedIconList,
930 RedrawIconList, in);
932 x += IconWidth + CurrentPrefs.pref_CleanupSpace.XSkip;
936 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
940 static void MoveIconToPositionXY(struct ScaIconNode *in, LONG x, LONG y)
942 struct ExtGadget *gg = (struct ExtGadget *) in->in_Icon;
943 WORD BoundsWidth;
945 d1(KPrintF("%s/%s/%ld: START in=%08lx <%s> x=%ld y=%ld\n", \
946 __FILE__, __FUNC__, __LINE__, in, GetIconName(in), x, y));
948 BoundsWidth = gg->LeftEdge - gg->BoundsLeftEdge;
950 gg->LeftEdge = gg->BoundsLeftEdge = x;
951 gg->LeftEdge += BoundsWidth;
952 gg->TopEdge = gg->BoundsTopEdge = y;
954 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
958 static void GetIconBoundingBox(const struct ScaIconNode *in, struct Rect32 *Bounds)
960 struct ExtGadget *gg = (struct ExtGadget *) in->in_Icon;
962 if (IsNoIconPosition(gg))
964 Bounds->MinX = Bounds->MaxX = 0;
965 Bounds->MinY = Bounds->MaxY = 0;
967 else
969 Bounds->MinX = Bounds->MaxX = gg->BoundsLeftEdge;
970 Bounds->MinY = Bounds->MaxY = gg->BoundsTopEdge;
973 Bounds->MaxX += gg->BoundsWidth - 1;
974 Bounds->MaxY += gg->BoundsHeight - 1;
978 static void DrawIconList(struct internalScaWindowTask *iwt,
979 struct ScaIconNode **RedrawIconList)
981 struct ScaIconNode *in, *inNext;
983 for (in = *RedrawIconList; in; in = inNext)
985 RedrawIcon(iwt, in);
987 inNext = (struct ScaIconNode *) in->in_Node.mln_Succ;
989 // Icon has been positioned and redrawn
990 // now move it to list of positioned icons
991 SCA_MoveIconNode(RedrawIconList,
992 &iwt->iwt_WindowTask.wt_IconList, in);
997 static void RedrawIcon(struct internalScaWindowTask *iwt, struct ScaIconNode *in)
999 struct ExtGadget *gg = (struct ExtGadget *) in->in_Icon;
1001 if (gg->LeftEdge != in->in_OldLeftEdge || gg->TopEdge != in->in_OldTopEdge)
1003 d1(KPrintF("%s/%s/%ld: in_Icon=%08lx LeftEdge=%ld\n", __FILE__, __FUNC__, __LINE__, in->in_Icon, gg->LeftEdge));
1005 if (!IsNoIconPosition(gg) && (in->in_Flags & INF_IconVisible))
1007 struct ScaIconNode inDummy;
1008 struct ScaIconNode *RemoveList;
1009 WORD NewLeftEdge = gg->LeftEdge;
1010 WORD NewTopEdge = gg->TopEdge;
1011 WORD NewBoundsLeftEdge = gg->BoundsLeftEdge;
1012 WORD NewBoundsTopEdge = gg->BoundsTopEdge;
1014 RemoveList = &inDummy;
1015 inDummy = *in;
1016 inDummy.in_Node.mln_Succ = NULL;
1018 gg->LeftEdge = gg->BoundsLeftEdge = in->in_OldLeftEdge;
1019 gg->TopEdge = gg->BoundsTopEdge = in->in_OldTopEdge;
1020 gg->BoundsLeftEdge += NewBoundsLeftEdge - NewLeftEdge;
1021 gg->BoundsTopEdge += NewBoundsTopEdge - NewTopEdge;
1023 RemoveIcons(iwt, &RemoveList);
1025 in->in_Flags &= ~INF_IconVisible;
1027 gg->LeftEdge = NewLeftEdge;
1028 gg->TopEdge = NewTopEdge;
1029 gg->BoundsLeftEdge = NewBoundsLeftEdge;
1030 gg->BoundsTopEdge = NewBoundsTopEdge;
1033 in->in_OldLeftEdge = gg->LeftEdge;
1034 in->in_OldTopEdge = gg->TopEdge;
1036 DoMethod(iwt->iwt_WindowTask.mt_MainObject, SCCM_IconWin_DrawIcon, in->in_Icon);
1041 static void CalculateMaximumIconAreaDimensions(const struct internalScaWindowTask *iwt, struct Rect32 *Bounds)
1043 const struct ScaIconNode *in;
1045 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
1047 // To find need size of placement tiles array,
1048 // calculate theoretical absolute maximum width and height
1049 // possibly required for the icons.
1050 // Assume that all icons are layouted either in one huge row or column,
1051 // and add up all icon's width and height.
1053 Bounds->MinX = Bounds->MaxX = 2 * CurrentPrefs.pref_CleanupSpace.Left;
1054 Bounds->MinY = Bounds->MaxY = 2 * CurrentPrefs.pref_CleanupSpace.Top;
1056 for (in = iwt->iwt_WindowTask.wt_IconList;
1057 in; in = (const struct ScaIconNode *) in->in_Node.mln_Succ)
1059 const struct ExtGadget *gg = (struct ExtGadget *) in->in_Icon;
1061 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", \
1062 __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
1064 Bounds->MaxX += CurrentPrefs.pref_CleanupSpace.XSkip + gg->BoundsWidth + 2 * CurrentPrefs.pref_CleanupSpace.Left;
1065 Bounds->MaxY += CurrentPrefs.pref_CleanupSpace.YSkip + gg->BoundsHeight + 2 * CurrentPrefs.pref_CleanupSpace.Top;
1067 for (in = iwt->iwt_WindowTask.wt_LateIconList;
1068 in; in = (const struct ScaIconNode *) in->in_Node.mln_Succ)
1070 const struct ExtGadget *gg = (struct ExtGadget *) in->in_Icon;
1072 d1(KPrintF("%s/%s/%ld: in=%08lx <%s>\n", \
1073 __FILE__, __FUNC__, __LINE__, in, GetIconName(in)));
1075 Bounds->MaxX += CurrentPrefs.pref_CleanupSpace.XSkip + gg->BoundsWidth + 2 * CurrentPrefs.pref_CleanupSpace.Left;
1076 Bounds->MaxY += CurrentPrefs.pref_CleanupSpace.YSkip + gg->BoundsHeight + 2 * CurrentPrefs.pref_CleanupSpace.Top;
1079 d1(KPrintF("%s/%s/%ld: END MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
1080 __FILE__, __FUNC__, __LINE__, Bounds->MinX, Bounds->MinY, Bounds->MaxX, Bounds->MaxY));
1082 if (iwt->iwt_WindowTask.wt_XOffset > 0)
1083 Bounds->MaxX += iwt->iwt_WindowTask.wt_XOffset;
1084 if (iwt->iwt_WindowTask.wt_YOffset > 0)
1085 Bounds->MaxY += iwt->iwt_WindowTask.wt_YOffset;
1087 d1(KPrintF("%s/%s/%ld: END MinX=%ld MinY=%ld MaxX=%ld MaxY=%ld\n", \
1088 __FILE__, __FUNC__, __LINE__, Bounds->MinX, Bounds->MinY, Bounds->MaxX, Bounds->MaxY));
1092 static void AddPositionedIconsToTiles(const struct internalScaWindowTask *iwt,
1093 struct TilesInfo *tli)
1095 const struct ScaIconNode *in;
1097 for (in = iwt->iwt_WindowTask.wt_IconList;
1098 in; in = (const struct ScaIconNode *) in->in_Node.mln_Succ)
1100 AddIconToTilesInfo(iwt, tli, in);