1st attempt of Zunification of BHFormat.
[cake.git] / rom / hyperlayers / movesizelayer.c
blob913491110fb50e321aeaa6552cfd6df37fa42e32
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
8 #include <aros/libcall.h>
9 #include <aros/debug.h>
10 #include <proto/layers.h>
11 #include <proto/exec.h>
12 #include <proto/graphics.h>
13 #include <proto/utility.h>
14 #include <exec/memory.h>
15 #include <graphics/rastport.h>
16 #include <graphics/clip.h>
17 #include "layers_intern.h"
18 #include "basicfuncs.h"
21 /*****************************************************************************
23 NAME */
25 AROS_LH5(LONG, MoveSizeLayer,
27 /* SYNOPSIS */
28 AROS_LHA(struct Layer *, l , A0),
29 AROS_LHA(LONG , dx, D0),
30 AROS_LHA(LONG , dy, D1),
31 AROS_LHA(LONG , dw, D2),
32 AROS_LHA(LONG , dh, D3),
34 /* LOCATION */
35 struct LayersBase *, LayersBase, 30, Layers)
37 /* FUNCTION
38 Moves and resizes the layer in one step. Collects damage lists
39 for those layers that become visible and are simple layers.
40 If the layer to be moved is becoming larger the additional
41 areas are added to a damagelist if it is a non-superbitmap
42 layer. Refresh is also triggered for this layer.
44 INPUTS
45 l - pointer to layer to be moved
46 dx - delta to add to current x position
47 dy - delta to add to current y position
48 dw - delta to add to current width
49 dw - delta to add to current height
51 RESULT
52 result - TRUE everyting went alright
53 FALSE an error occurred (out of memory)
55 NOTES
57 EXAMPLE
59 BUGS
61 SEE ALSO
63 INTERNALS
65 HISTORY
66 27-11-96 digulla automatically created from
67 layers_lib.fd and clib/layers_protos.h
69 *****************************************************************************/
71 AROS_LIBFUNC_INIT
73 struct Layer * first, *_l, *lparent;
74 struct Region * newshape, * oldshape, r, rtmp, cutnewshape;
75 struct Region *clipregion, *olddamage = NULL;
76 struct Rectangle rectw, recth;
78 InitRegion(&r);
79 InitRegion(&rtmp);
80 InitRegion(&cutnewshape);
82 LockLayers(l->LayerInfo);
84 clipregion = _InternalInstallClipRegion(l, NULL, 0, 0, LayersBase);
86 /* There's a little problem with CopyClipRectsToClipRects(). It
87 may call the backfill hook for the whole DamageList region.
88 Layers should never do this. It should call backfill hook only
89 for *new* damage, a layer operation causes. But not for those
90 areas which were part of the damage already before the layer
91 operation. Otherwise those latter areas might end up being
92 backfilled multiple times -> flickering. As fixing CopyClipRects-
93 ToClipRects() seems kinda complicated, I use a little trick: Set
94 a flag which tells the layers backfillhook calling function, not do
95 that. Before executing the movesizelayer operation I backup the old
96 damage region, and after executing of movesizelayer operation is done
97 I can use it to find out what areas where added to the damageregion.
98 i'll clear that special layer flag, and call the backfill hook for the
99 new damage areas. (stegerg) */
101 if (IS_SIMPLEREFRESH(l))
103 if ((olddamage = CopyRegion(l->DamageList)))
105 _TranslateRect(&olddamage->bounds, l->bounds.MinX, l->bounds.MinY);
106 AndRegionRegion(l->VisibleRegion, olddamage);
107 AndRegionRegion(l->visibleshape, olddamage);
108 _TranslateRect(&olddamage->bounds, -l->bounds.MinX, -l->bounds.MinY);
110 IL(l)->intflags |= INTFLAG_AVOID_BACKFILL;
115 * First Create the new region of the layer:
116 * adjust its size and position.
120 /* First create newshape with 0,0 origin, because l->shaperegion is in layer coords */
122 newshape = NewRectRegion(0,
124 l->bounds.MaxX - l->bounds.MinX + dw,
125 l->bounds.MaxY - l->bounds.MinY + dh);
126 if (IL(l)->shapehook)
128 struct ShapeHookMsg msg;
130 if ((dx || dy) && (dw || dh))
132 msg.Action = SHAPEHOOKACTION_MOVESIZELAYER;
134 else if (dx || dy)
136 msg.Action = SHAPEHOOKACTION_MOVELAYER;
138 else
140 msg.Action = SHAPEHOOKACTION_SIZELAYER;
143 msg.Layer = l;
144 msg.ActualShape = l->shaperegion;
145 msg.NewBounds.MinX = l->bounds.MinX + dx;
146 msg.NewBounds.MinY = l->bounds.MinY + dy;
147 msg.NewBounds.MaxX = l->bounds.MaxX + dx + dw;
148 msg.NewBounds.MaxY = l->bounds.MaxY + dy + dh;
149 msg.OldBounds.MinX = l->bounds.MinX;
150 msg.OldBounds.MinY = l->bounds.MinY;
151 msg.OldBounds.MaxX = l->bounds.MaxX;
152 msg.OldBounds.MaxY = l->bounds.MaxY;
154 l->shaperegion = (struct Region *)CallHookPkt(IL(l)->shapehook, l, &msg);
157 if (l->shaperegion)
158 AndRegionRegion(l->shaperegion, newshape);
160 /* Now make newshape relative to old(!!) layer screen coords */
161 _TranslateRect(&newshape->bounds, l->bounds.MinX+dx, l->bounds.MinY+dy);
163 /* rectw and recth are now only needed for backfilling if layer got bigger -> see end of func */
165 if (dw > 0)
167 rectw.MinX = dx+l->bounds.MaxX+1;
168 rectw.MinY = dy+l->bounds.MinY;
169 rectw.MaxX = rectw.MinX + dw - 1;
170 rectw.MaxY = dy+l->bounds.MaxY+dh;
173 if (dh > 0)
175 recth.MinX = dx+l->bounds.MinX;
176 recth.MinY = dy+l->bounds.MaxY + 1;
177 recth.MaxX = dx+l->bounds.MaxX+dw;
178 recth.MaxY = recth.MinY + dh - 1;
181 SetRegion(newshape, &cutnewshape);
182 AndRegionRegion(l->parent->visibleshape, &cutnewshape);
184 first = GetFirstFamilyMember(l);
186 * Must make a copy of the VisibleRegion of the first visible layer here
187 * and NOT later!
189 _l = first;
190 while (1)
192 if (IS_VISIBLE(_l))
194 SetRegion(_l->VisibleRegion, &r);
195 break;
198 if (l == _l)
199 break;
201 _l = _l->back;
203 //kprintf("%s called for layer %p, first = %p!\n",__FUNCTION__,l,first);
206 * First back up parts of layers that are behind the layer
207 * family. Only need to do this if layer is moving or
208 * getting bigger in size. Only need to visit those layers
209 * that overlap with the new shape of the layer.
213 lparent = l->parent;
214 _l = l->back;
216 #if 0
217 kprintf("\t\t%s: Backing up parts of layers that are behind the layer!\n",
218 __FUNCTION__);
219 #endif
220 while (1)
222 if (IS_VISIBLE(_l) && DO_OVERLAP(&cutnewshape.bounds, &_l->shape->bounds))
223 _BackupPartsOfLayer(_l, &cutnewshape, 0, FALSE, LayersBase);
224 else
225 ClearRegionRegion(&cutnewshape, _l->VisibleRegion);
227 if (_l == lparent)
229 if (IS_VISIBLE(_l) || (NULL == lparent->parent))
230 break;
231 else
232 lparent = lparent->parent;
234 _l = _l->back;
237 SetRegion(&cutnewshape, l->visibleshape);
238 ClearRegion(&cutnewshape);
241 * Now I need to move the layer and all its familiy to the new
242 * location.
244 oldshape = l->shape;
245 l->shape = newshape;
247 _l = l;
249 while (1)
251 struct ClipRect * cr;
253 #if 0
254 kprintf("\t\t%s: BACKING up parts of THE LAYER TO BE MOVED!\n",
255 __FUNCTION__);
256 #endif
258 if (1/* IS_VISIBLE(_l) */)
260 ClearRegion(_l->VisibleRegion);
261 _BackupPartsOfLayer(_l, _l->shape, dx, TRUE, LayersBase);
264 * Effectively move the layer...
266 _TranslateRect(&_l->bounds, dx, dy);
270 * ...and also its cliprects.
272 cr = _l->ClipRect;
273 while (cr)
275 _TranslateRect(&cr->bounds, dx, dy);
276 cr = cr->Next;
279 cr = _l->_cliprects;
280 while (cr)
282 _TranslateRect(&cr->bounds, dx, dy);
283 cr = cr->Next;
286 if (l != _l)
288 _TranslateRect(&_l->shape->bounds, dx, dy);
291 * Also calculate the visible shape!
293 SetRegion(_l->shape, _l->visibleshape);
294 AndRegionRegion(_l->parent->visibleshape, _l->visibleshape);
297 if (_l == first)
298 break;
300 _l = _l->front;
303 l->bounds.MaxX += dw;
304 l->bounds.MaxY += dh;
305 l->Width += dw;
306 l->Height += dh;
310 * Now make them visible again.
312 _l = first;
314 while (1)
316 if (IS_VISIBLE(_l))
318 #if 0
319 kprintf("\t\t%s: SHOWING parts of THE LAYER TO BE MOVED (children)!\n",
320 __FUNCTION__);
321 #endif
322 ClearRegion(_l->VisibleRegion);
323 _ShowPartsOfLayer(_l, &r, LayersBase);
325 if (l == _l)
326 break;
328 ClearRegionRegion(_l->visibleshape, &r);
331 if (l == _l)
332 break;
334 _l = _l->back;
338 * Now make those parts of the layers after l up to and including
339 * its parent visible.
341 SetRegion(l->VisibleRegion, &r);
342 ClearRegionRegion(l->visibleshape, &r);
343 _l = l->back;
344 lparent = l->parent;
346 while (1)
348 #if 0
349 kprintf("\t\t%s: SHOWING parts of the layers behind the layer to be moved!\n",
350 __FUNCTION__);
351 #endif
352 if (IS_VISIBLE(_l) &&
353 ( DO_OVERLAP(&l->visibleshape->bounds, &_l->shape->bounds) ||
354 DO_OVERLAP( &oldshape->bounds, &_l->shape->bounds) ))
356 ClearRegion(_l->VisibleRegion);
357 _ShowPartsOfLayer(_l, &r, LayersBase);
359 else
360 SetRegion(&r, _l->VisibleRegion);
362 if (IS_VISIBLE(_l) || IS_ROOTLAYER(_l))
363 AndRegionRegion(_l->VisibleRegion, oldshape);
365 #if 0
366 if (IS_ROOTLAYER(_l))
367 kprintf("root reached! %p\n",_l);
368 #endif
370 if (_l == lparent)
372 if (IS_VISIBLE(_l) || (NULL == lparent->parent))
373 break;
374 else
375 lparent = lparent->parent;
378 if (IS_VISIBLE(_l))
379 ClearRegionRegion(_l->visibleshape, &r);
381 _l = _l->back;
384 ClearRegion(&rtmp);
387 * Now I need to clear the old layer at its previous place..
388 * But I may only clear those parts where no layer has become
389 * visible in the meantime.
391 if (!IS_EMPTYREGION(oldshape))
393 if (lparent && IS_ROOTLAYER(lparent))
394 _BackFillRegion(l->parent, oldshape, TRUE, LayersBase);
397 DisposeRegion(oldshape);
400 * If the size of the layer became larger clear the
401 * new area where it is visible.
403 if ((dw > 0 || dh > 0) && !IS_SUPERREFRESH(l))
405 ClearRegion(&r);
406 if (dw > 0)
407 OrRectRegion(&r, &rectw);
409 if (dh > 0)
410 OrRectRegion(&r, &recth);
412 _BackFillRegion(l, &r, TRUE, LayersBase);
415 ClearRegion(&r);
417 if (olddamage)
419 struct Region *newdamage = CopyRegion(l->DamageList);
421 IL(l)->intflags &= ~INTFLAG_AVOID_BACKFILL;
422 if (newdamage)
424 ClearRegionRegion(olddamage, newdamage);
425 _TranslateRect(&newdamage->bounds, l->bounds.MinX, l->bounds.MinY);
426 _BackFillRegion(l, newdamage, FALSE, LayersBase);
428 DisposeRegion(newdamage);
430 DisposeRegion(olddamage);
433 if (clipregion)
434 _InternalInstallClipRegion(l, clipregion, 0, 0, LayersBase);
436 UnlockLayers(l->LayerInfo);
438 return TRUE;
440 AROS_LIBFUNC_EXIT
441 } /* MoveSizeLayer */