Improvements to comments etc.
[AROS.git] / workbench / libs / asl / listviewclass.c
blob73e52f9948c2146b237dd7f9c1bfab3697f64b40
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <proto/alib.h>
7 #include <proto/exec.h>
8 #include <proto/dos.h>
9 #include <proto/utility.h>
10 #include <proto/intuition.h>
11 #include <proto/graphics.h>
12 #include <proto/cybergraphics.h>
13 #include <proto/layers.h>
14 #include <exec/memory.h>
15 #include <intuition/screens.h>
16 #include <intuition/icclass.h>
17 #include <intuition/cghooks.h>
18 #include <intuition/imageclass.h>
19 #include <intuition/gadgetclass.h>
20 #include <graphics/gfx.h>
21 #include <cybergraphx/cybergraphics.h>
23 #include <string.h>
25 #include "asl_intern.h"
26 #include "layout.h"
28 #define SDEBUG 0
29 #define DEBUG 0
31 #include <aros/debug.h>
33 #define CLASS_ASLBASE ((struct AslBase_intern *)cl->cl_UserData)
34 #define HOOK_ASLBASE ((struct AslBase_intern *)hook->h_Data)
36 #define AslBase CLASS_ASLBASE
38 /***********************************************************************************/
40 #undef AslBase
41 #define AslBase HOOK_ASLBASE
43 /************************
44 ** ASLLVRenderHook() **
45 ************************/
46 AROS_UFH3(IPTR, ASLLVRenderHook,
47 AROS_UFHA(struct Hook *, hook, A0),
48 AROS_UFHA(struct Node *, node, A2),
49 AROS_UFHA(struct ASLLVDrawMsg *, msg, A1)
52 AROS_USERFUNC_INIT
54 IPTR retval;
56 if (msg->lvdm_MethodID == LV_DRAW)
58 struct DrawInfo *dri = msg->lvdm_DrawInfo;
59 struct RastPort *rp = msg->lvdm_RastPort;
61 WORD min_x = msg->lvdm_Bounds.MinX;
62 WORD min_y = msg->lvdm_Bounds.MinY;
63 WORD max_x = msg->lvdm_Bounds.MaxX;
64 WORD max_y = msg->lvdm_Bounds.MaxY;
66 UWORD erasepen = BACKGROUNDPEN;
67 UWORD textpen = TEXTPEN;
69 SetDrMd(rp, JAM1);
72 switch (msg->lvdm_State)
74 case ASLLVR_SELECTED:
75 erasepen = FILLPEN;
76 textpen = FILLTEXTPEN;
78 /* Fall through */
80 case ASLLVR_NORMAL:
82 WORD numfit;
83 struct TextExtent te;
85 SetAPen(rp, dri->dri_Pens[erasepen]);
86 RectFill(rp, min_x, min_y, max_x, max_y);
88 if (node) if (node->ln_Name)
90 UWORD len = strlen(node->ln_Name);
92 numfit = TextFit(rp,
93 node->ln_Name,
94 len,
95 &te,
96 NULL,
98 max_x - min_x + 1 - BORDERLVITEMSPACINGX * 2,
99 max_y - min_y + 1);
101 if (numfit < len) numfit++;
103 SetAPen(rp, dri->dri_Pens[textpen]);
105 /* Render text */
106 Move(rp, min_x + BORDERLVITEMSPACINGX,
107 min_y + BORDERLVITEMSPACINGY + rp->Font->tf_Baseline);
108 Text(rp, node->ln_Name, numfit);
111 } break;
114 retval = ASLLVCB_OK;
116 else
118 retval = ASLLVCB_UNKNOWN;
121 return retval;
123 AROS_USERFUNC_EXIT
126 /***********************************************************************************/
128 #undef AslBase
129 #define AslBase CLASS_ASLBASE
131 static struct Node *findnode(Class *cl, Object *o, WORD which)
133 struct AslListViewData *data;
134 struct Node *node = NULL;
136 data = INST_DATA(cl, o);
138 if (data->nodetable)
140 if ((which < data->total) && (which >= 0)) node = data->nodetable[which];
141 } else {
142 node = FindListNode(data->labels, which);
145 return node;
148 /***********************************************************************************/
150 static void makenodetable(Class *cl, Object *o)
152 struct AslListViewData *data;
154 data = INST_DATA(cl, o);
156 if (data->nodetable)
158 FreeVec(data->nodetable);
159 data->nodetable = NULL;
162 /* data->total must be correct here */
164 if (data->total > 0)
166 if ((data->nodetable = AllocVec(sizeof(struct Node *) * data->total, MEMF_PUBLIC)))
168 struct Node *node, **nodeptr = data->nodetable;
169 ForeachNode(data->labels, node)
171 *nodeptr++ = node;
177 /***********************************************************************************/
179 static void renderitem(Class *cl, Object *o, struct Node *node, WORD liney, struct RastPort *rp)
181 struct AslListViewData *data;
182 struct ASLLVDrawMsg msg;
184 data = INST_DATA(cl, o);
186 if (data->font) SetFont(rp, data->font);
188 msg.lvdm_MethodID = ASLLV_DRAW;
189 msg.lvdm_RastPort = rp;
190 msg.lvdm_DrawInfo = data->ld->ld_Dri;
191 msg.lvdm_Bounds.MinX = data->minx + BORDERLVSPACINGX;
192 msg.lvdm_Bounds.MaxX = data->maxx - BORDERLVSPACINGX;
193 msg.lvdm_Bounds.MinY = data->miny + BORDERLVSPACINGY + liney * data->lineheight -
194 (data->toppixel % data->lineheight);
195 msg.lvdm_Bounds.MaxY = msg.lvdm_Bounds.MinY + data->lineheight - 1;
196 msg.lvdm_State = node ? (IS_SELECTED(node) ? ASLLVR_SELECTED : ASLLVR_NORMAL) : ASLLVR_NORMAL;
198 if (data->renderrect)
200 if (!AndRectRect(data->renderrect, &msg.lvdm_Bounds, NULL)) return;
203 CallHookPkt(data->renderhook, node, &msg);
206 /***********************************************************************************/
208 static void renderallitems(Class *cl, Object *o, struct RastPort *rp)
210 struct AslListViewData *data;
211 struct Node *node;
212 LONG i, visible;
214 data = INST_DATA(cl, o);
216 node = findnode(cl, o, data->top);
218 visible = data->visiblepixels + data->lineheight - 1 + (data->toppixel % data->lineheight);
219 visible /= data->lineheight;
221 //kprintf("renderallitem: lineheight %d visible %d visiblepixels %d toppixel %d\n",
222 // data->lineheight, visible, data->visiblepixels, data->toppixel);
224 for(i = 0; i < visible; i++)
226 if (node) if (!node->ln_Succ) node = NULL;
228 renderitem(cl, o, node , i, rp);
230 if (node) node = node->ln_Succ;
234 /***********************************************************************************/
236 static void rendersingleitem(Class *cl, Object *o, struct GadgetInfo *gi, WORD which)
238 struct AslListViewData *data;
240 data = INST_DATA(cl, o);
242 if (!gi) return;
243 if (which < data->top) return;
244 if (which >= data->total) return;
246 if ((which - data->top) <
247 (data->visiblepixels + data->lineheight - 1 + (data->toppixel % data->lineheight)) / data->lineheight)
249 struct RastPort *rp;
251 if ((rp = ObtainGIRPort(gi)))
253 struct gpRender gpr;
255 data->rendersingleitem = which;
257 gpr.MethodID = GM_RENDER;
258 gpr.gpr_GInfo = gi;
259 gpr.gpr_RPort = rp;
260 gpr.gpr_Redraw = GREDRAW_UPDATE;
262 DoMethodA(o, (Msg)&gpr);
264 ReleaseGIRPort(rp);
266 } /* if ((rp = ObtainGIRPort(msg->gpi_GInfo))) */
268 } /* if ((which >= data->top) && ... */
272 /***********************************************************************************/
274 static WORD mouseitem(Class *cl, Object *o, WORD mousex, WORD mousey)
276 struct AslListViewData *data;
277 WORD result = -5;
279 data = INST_DATA(cl, o);
281 if (mousey < BORDERLVSPACINGY)
283 result = -1;
285 else if (mousey > data->maxy - data->miny - BORDERLVSPACINGY)
287 result = -2;
289 else if (mousex < BORDERLVSPACINGX)
291 result = -3;
293 else if (mousex > data->maxx - data->minx - BORDERLVSPACINGX)
295 result = -4;
297 else
299 LONG i = (mousey - BORDERLVSPACINGY + (data->toppixel % data->lineheight)) / data->lineheight;
300 LONG visible;
302 visible = data->visiblepixels + data->lineheight - 1 + (data->toppixel % data->lineheight);
303 visible /= data->lineheight;
305 if (i < visible)
307 struct Node *node;
309 i += data->top;
311 if ((node = findnode(cl, o, i)))
313 result = i;
318 //kprintf("mouseitem : %d\n", result);
320 return result;
323 /***********************************************************************************/
325 static void notifyall(Class *cl, Object *o, struct GadgetInfo *gi, STACKULONG flags)
327 struct AslListViewData *data = INST_DATA(cl, o);
328 struct TagItem tags[] =
330 {ASLLV_Top , data->top },
331 {ASLLV_TopPixel , data->toppixel },
332 {ASLLV_Total , data->total },
333 {ASLLV_TotalPixels , data->totalpixels },
334 {ASLLV_Visible , data->visible },
335 {ASLLV_VisiblePixels, data->visiblepixels },
336 {ASLLV_DeltaFactor , data->lineheight },
337 {TAG_DONE }
339 struct opUpdate opu;
341 opu.MethodID = OM_NOTIFY;
342 opu.opu_AttrList = tags;
343 opu.opu_GInfo = gi;
344 opu.opu_Flags = flags;
346 D(bug("asl listview notify all: top = %d (%d) total = %d (%d) visible = %d (%d)\n",
347 data->top, data->toppixel,
348 data->total, data->totalpixels,
349 data->visible, data->visiblepixels));
351 DoSuperMethodA(cl, o, (Msg)&opu);
355 /***********************************************************************************/
357 static void notifytop(Class *cl, Object *o, struct GadgetInfo *gi, STACKULONG flags)
359 struct AslListViewData *data = INST_DATA(cl, o);
360 struct TagItem tags[] =
362 {ASLLV_Top , data->top },
363 {ASLLV_TopPixel , data->toppixel},
364 {TAG_DONE }
366 struct opUpdate opu;
368 opu.MethodID = OM_NOTIFY;
369 opu.opu_AttrList = tags;
370 opu.opu_GInfo = gi;
371 opu.opu_Flags = flags;
373 D(bug("asl listview notify top: top = %d\n", data->top));
375 DoSuperMethodA(cl, o, (Msg)&opu);
379 /***********************************************************************************/
381 IPTR AslListView__OM_SET(Class * cl, Object * o, struct opSet * msg)
383 struct AslListViewData *data = INST_DATA(cl, o);
384 struct TagItem *tag, *tstate = msg->ops_AttrList;
385 IPTR retval, tidata;
386 BOOL redraw = FALSE, notify_all = FALSE, notify_top = FALSE;
387 LONG newtop;
389 retval = DoSuperMethod(cl, o, OM_SET, (IPTR) msg->ops_AttrList, (IPTR) msg->ops_GInfo);
391 while((tag = NextTagItem(&tstate)))
393 tidata = tag->ti_Data;
395 switch(tag->ti_Tag)
397 case ASLLV_Top:
398 tidata *= data->lineheight;
399 /* fall through */
401 case ASLLV_TopPixel:
402 newtop = tidata;
403 if (newtop + data->visiblepixels > data->totalpixels)
405 newtop = data->totalpixels - data->visiblepixels;
407 if (newtop < 0) newtop = 0;
409 if (newtop != data->toppixel)
411 data->scroll = redraw ? 0 : newtop - data->toppixel;
412 data->top = newtop / data->lineheight;
413 data->toppixel = newtop;
414 notify_top = TRUE;
415 redraw = TRUE;
417 break;
419 case ASLLV_MakeVisible:
420 newtop = (LONG)tidata * data->lineheight;
422 if (newtop < 0)
424 newtop = 0;
426 else if (newtop >= data->totalpixels)
428 newtop = data->totalpixels - 1;
429 if (newtop < 0) newtop = 0;
432 /* No need to do anything if it is already visible */
434 if (newtop < data->toppixel)
436 /* new_top already okay */
438 data->scroll = redraw ? 0 : newtop - data->toppixel;
439 data->top = newtop / data->lineheight;
440 data->toppixel = newtop;
441 notify_top = TRUE;
442 redraw = TRUE;
444 else if (newtop > data->toppixel + data->visiblepixels - data->lineheight)
446 newtop -= (data->visiblepixels - data->lineheight);
447 data->scroll = redraw ? 0 : newtop - data->toppixel;
448 data->top = newtop / data->lineheight;
449 data->toppixel = newtop;
450 notify_top = TRUE;
451 redraw = TRUE;
453 break;
455 case ASLLV_Active:
457 struct Node *node;
458 WORD n = 0;
459 WORD old_active = data->active;
461 data->active = (WORD)tidata;
463 if (data->domultiselect)
465 ForeachNode(data->labels, node)
467 if (IS_MULTISEL(node) && IS_SELECTED(node) && (n != data->active))
469 MARK_UNSELECTED(node);
470 rendersingleitem(cl, o, msg->ops_GInfo, n);
472 n++;
474 } else {
475 if ((node = findnode(cl, o, old_active)))
477 MARK_UNSELECTED(node);
478 rendersingleitem(cl, o, msg->ops_GInfo, old_active);
482 if ((node = findnode(cl, o, data->active)))
484 if (!data->domultiselect || IS_MULTISEL(node))
486 MARK_SELECTED(node);
487 rendersingleitem(cl, o, msg->ops_GInfo, data->active);
492 break;
494 case ASLLV_Labels:
495 data->labels = tidata ? (struct List *)tidata : &data->emptylist;
496 data->total = CountNodes(data->labels, 0);
497 data->totalpixels = data->total * data->lineheight;
498 data->active = -1;
500 if (!data->layouted)
502 data->visible = data->total;
503 data->visiblepixels = data->visible * data->lineheight;
506 if (data->toppixel + data->visiblepixels > data->totalpixels)
508 data->toppixel = data->totalpixels - data->visiblepixels;
510 if (data->toppixel < 0) data->toppixel = 0;
511 data->top = data->toppixel / data->lineheight;
513 if (!data->layouted)
515 data->visiblepixels = data->totalpixels;
516 data->visible = data->total;
519 makenodetable(cl, o);
521 notify_all = TRUE;
522 redraw = TRUE;
523 break;
525 case ASLLV_DoMultiSelect:
526 data->domultiselect = tidata ? TRUE : FALSE;
527 break;
529 case ASLLV_DoSaveMode:
530 data->dosavemode = tidata ? TRUE : FALSE;
531 break;
533 case ASLLV_ReadOnly:
534 data->readonly = tidata ? TRUE : FALSE;
535 break;
537 case ASLLV_Font:
538 data->font = (struct TextFont *)tidata;
539 break;
541 } /* switch(tag->ti_Tag) */
543 } /* while((tag = NextTagItem(&tsate))) */
545 if (redraw)
547 struct RastPort *rp;
548 struct gpRender gpr;
550 if ((rp = ObtainGIRPort(msg->ops_GInfo)))
552 gpr.MethodID = GM_RENDER;
553 gpr.gpr_GInfo = msg->ops_GInfo;
554 gpr.gpr_RPort = rp;
555 gpr.gpr_Redraw = GREDRAW_UPDATE;
557 DoMethodA(o, (Msg)&gpr);
559 ReleaseGIRPort(rp);
563 if (notify_all)
565 notifyall(cl, o, msg->ops_GInfo, 0);
567 else if (notify_top)
569 notifytop(cl, o, msg->ops_GInfo, 0);
572 return retval;
575 /***********************************************************************************/
577 IPTR AslListView__OM_NEW(Class * cl, Object * o, struct opSet * msg)
579 struct AslListViewData *data;
580 struct TagItem fitags[] =
582 {IA_FrameType, FRAME_BUTTON},
583 {IA_EdgesOnly, TRUE },
584 {TAG_DONE, 0UL}
587 struct Gadget *g = (struct Gadget *)DoSuperMethodA(cl, o, (Msg)msg);
588 if (g)
590 data = INST_DATA(cl, g);
592 /* We want to get a GM_LAYOUT message, no matter if gadget is GFLG_RELRIGHT/RELBOTTOM/
593 RELWIDTH/RELHEIGHT or not */
594 g->Flags |= GFLG_RELSPECIAL;
596 data->frame = NewObjectA(NULL, FRAMEICLASS, fitags);
597 data->ld = (struct LayoutData *)GetTagData(GA_UserData, 0, msg->ops_AttrList);
599 if (!data->ld || !data->frame)
601 CoerceMethod(cl, (Object *)g, OM_DISPOSE);
602 g = NULL;
604 else
606 data->itemheight = GetTagData(ASLLV_ItemHeight, data->ld->ld_Font->tf_YSize, msg->ops_AttrList);
607 data->spacing = GetTagData(ASLLV_Spacing, BORDERLVITEMSPACINGY * 2, msg->ops_AttrList);
609 data->lineheight = data->itemheight + data->spacing;
611 NEWLIST(&data->emptylist);
612 data->labels = &data->emptylist;
613 data->active = -1;
614 data->rendersingleitem = -1;
616 data->renderhook = (struct Hook *)GetTagData(ASLLV_CallBack, 0, msg->ops_AttrList);
617 data->default_renderhook.h_Entry = (APTR) AROS_ASMSYMNAME(ASLLVRenderHook);
618 data->default_renderhook.h_SubEntry = NULL;
619 data->default_renderhook.h_Data = (APTR)AslBase;
620 if (!data->renderhook) data->renderhook = &data->default_renderhook;
622 AslListView__OM_SET(cl, (Object *)g, msg);
626 return (IPTR)g;
629 /***********************************************************************************/
631 IPTR AslListView__OM_GET(Class * cl, Object * o, struct opGet *msg)
633 struct AslListViewData *data;
634 IPTR retval = 1;
636 data = INST_DATA(cl, o);
638 switch(msg->opg_AttrID)
640 case ASLLV_Active:
641 *msg->opg_Storage = data->active;
642 break;
644 case ASLLV_Top:
645 *msg->opg_Storage = data->top;
646 break;
648 case ASLLV_TopPixel:
649 *msg->opg_Storage = data->toppixel;
650 break;
652 case ASLLV_Total:
653 *msg->opg_Storage = data->total;
654 break;
656 case ASLLV_TotalPixels:
657 *msg->opg_Storage = data->totalpixels;
658 break;
660 case ASLLV_Visible:
661 *msg->opg_Storage = data->visible;
662 break;
664 case ASLLV_VisiblePixels:
665 *msg->opg_Storage = data->visiblepixels;
666 break;
668 default:
669 retval = DoSuperMethodA(cl, o, (Msg)msg);
670 break;
672 } /* switch(msg->opg_AttrID) */
674 return retval;
677 /***********************************************************************************/
679 IPTR AslListView__OM_DISPOSE(Class * cl, Object * o, Msg msg)
681 struct AslListViewData *data;
682 IPTR retval;
684 data = INST_DATA(cl, o);
685 if (data->frame) DisposeObject(data->frame);
686 if (data->nodetable) FreeVec(data->nodetable);
687 retval = DoSuperMethodA(cl, o, msg);
689 return retval;
692 /***********************************************************************************/
694 IPTR AslListView__GM_GOACTIVE(Class *cl, Object *o, struct gpInput *msg)
696 struct AslListViewData *data;
697 WORD i;
698 IPTR retval = GMR_NOREUSE;
700 data = INST_DATA(cl, o);
701 if ((data->total < 1) || (data->readonly)) return retval;
703 i = mouseitem(cl, o, msg->gpi_Mouse.X, msg->gpi_Mouse.Y);
705 if (i >= 0)
707 struct Node *node;
709 if ((node = findnode(cl, o, i)))
711 ULONG sec, micro;
713 CurrentTime(&sec, &micro);
715 if (data->domultiselect && IS_MULTISEL(node) &&
716 (msg->gpi_IEvent->ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
718 data->multiselecting = TRUE;
720 else
722 data->multiselecting = FALSE;
724 if (data->domultiselect)
726 struct Node *node;
727 WORD n = 0;
729 ForeachNode(data->labels, node)
731 if (IS_MULTISEL(node) && IS_SELECTED(node) && (n != data->active))
733 MARK_UNSELECTED(node);
734 rendersingleitem(cl, o, msg->gpi_GInfo, n);
736 n++;
741 data->doubleclicked = FALSE;
742 if (data->active == i)
744 if (DoubleClick(data->clicksec, data->clickmicro, sec, micro))
746 data->doubleclicked = TRUE;
749 else
751 if (!data->multiselecting && (data->active >= 0))
753 struct Node *oldnode = findnode(cl, o, data->active);
755 MARK_UNSELECTED(oldnode);
756 rendersingleitem(cl, o, msg->gpi_GInfo, data->active);
759 MARK_SELECTED(node);
760 rendersingleitem(cl, o, msg->gpi_GInfo, i);
762 data->active = i;
764 } /* if (data->active != i) */
766 data->clicksec = sec;
767 data->clickmicro = micro;
769 retval = GMR_MEACTIVE;
771 } /* if ((node = findnode(cl, o, i))) */
773 } /* if (i >= 0) */
775 return retval;
778 /***********************************************************************************/
780 IPTR AslListView__GM_HANDLEINPUT(Class *cl, Object *o, struct gpInput *msg)
782 struct AslListViewData *data;
783 UWORD code;
784 IPTR retval = GMR_MEACTIVE;
786 data = INST_DATA(cl, o);
788 switch(msg->gpi_IEvent->ie_Class)
790 case IECLASS_TIMER:
791 code = IECODE_NOBUTTON;
792 /* fall through */
794 case IECLASS_RAWMOUSE:
795 code = msg->gpi_IEvent->ie_Code;
797 switch(code)
799 case SELECTUP:
800 *msg->gpi_Termination = data->doubleclicked;
801 retval = GMR_VERIFY | GMR_NOREUSE;
802 break;
804 case IECODE_NOBUTTON:
806 WORD n = mouseitem(cl, o, msg->gpi_Mouse.X, msg->gpi_Mouse.Y);
808 if ((n == -1) && (data->active > 0)) n = data->active - 1;
809 if ((n == -2) && (data->active < data->total - 1)) n = data->active + 1;
811 if ((n >= 0) && (n != data->active))
813 struct Node *old = findnode(cl, o, data->active);
814 struct Node *new = findnode(cl, o, n);
816 if (data->multiselecting && new)
818 if (!IS_MULTISEL(new)) new = NULL;
821 if (new && old)
823 if (!data->multiselecting)
825 MARK_UNSELECTED(old);
826 rendersingleitem(cl, o, msg->gpi_GInfo, data->active);
829 MARK_SELECTED(new);
830 rendersingleitem(cl, o, msg->gpi_GInfo, n);
832 data->active = n;
835 if ((n * data->lineheight < data->toppixel) ||
836 (n * data->lineheight > data->toppixel + data->visiblepixels - data->lineheight))
838 struct RastPort *rp;
840 if (n * data->lineheight < data->toppixel)
842 LONG newtop = n * data->lineheight;
843 data->scroll = newtop - data->toppixel;
844 data->toppixel = newtop;
845 data->top = newtop / data->lineheight;
847 else
849 LONG newtop = n * data->lineheight - (data->visiblepixels - data->lineheight);
851 data->scroll = newtop - data->toppixel;
852 data->toppixel = newtop;
853 data->top = newtop / data->lineheight;
856 if ((rp = ObtainGIRPort(msg->gpi_GInfo)))
858 struct gpRender gpr;
860 gpr.MethodID = GM_RENDER;
861 gpr.gpr_GInfo = msg->gpi_GInfo;
862 gpr.gpr_RPort = rp;
863 gpr.gpr_Redraw = GREDRAW_UPDATE;
865 DoMethodA(o, (Msg)&gpr);
867 ReleaseGIRPort(rp);
870 notifytop(cl, o, msg->gpi_GInfo, OPUF_INTERIM);
872 } /* if ((n < data->top) || (n >= data->top + data->visible)) */
874 } /* if ((n >= 0) && (n != data->active)) */
875 break;
878 } /* switch(msg->gpi_IEvent->ie_Code) */
879 break;
881 } /* switch(msg->gpi_IEvent->ie_Class) */
883 return retval;
886 /***********************************************************************************/
888 IPTR AslListView__GM_LAYOUT(Class *cl, struct Gadget *g, struct gpLayout *msg)
890 struct AslListViewData *data;
891 IPTR retval = 0;
893 data = INST_DATA(cl, g);
895 if (msg->gpl_GInfo)
897 LONG newtop = data->toppixel;
898 LONG newvisible = data->visiblepixels;
900 getgadgetcoords(g, msg->gpl_GInfo, &data->minx, &data->miny, &data->width, &data->height);
902 data->maxx = data->minx + data->width - 1;
903 data->maxy = data->miny + data->height - 1;
905 newvisible = (data->height - BORDERLVSPACINGY * 2);
906 if (newtop + newvisible > data->totalpixels)
908 newtop = data->totalpixels - newvisible;
910 if (newtop < 0) newtop = 0;
912 if ((newtop != data->toppixel) || (newvisible != data->visiblepixels) || (!data->layouted))
914 data->toppixel = newtop;
915 data->top = newtop / data->lineheight;
916 data->visiblepixels = newvisible;
917 data->visible = newvisible / data->lineheight;
919 notifyall(cl, (Object *)g, msg->gpl_GInfo, 0);
922 data->layouted = TRUE;
924 retval = 1;
927 return retval;
930 /***********************************************************************************/
932 IPTR AslListView__GM_RENDER(Class *cl, Object *o, struct gpRender *msg)
934 struct AslListViewData *data;
935 struct Region *clip, *oldclip = NULL;
936 BOOL updating = FALSE;
937 IPTR retval = 0;
939 data = INST_DATA(cl, o);
941 if (msg->gpr_Redraw == GREDRAW_REDRAW)
943 struct TagItem im_tags[] =
945 {IA_Width , data->width },
946 {IA_Height , data->height },
947 {IA_Recessed , data->readonly },
948 {TAG_DONE }
951 SetAttrsA(data->frame, im_tags);
953 DrawImageState(msg->gpr_RPort,
954 (struct Image *)data->frame,
955 data->minx,
956 data->miny,
957 IDS_NORMAL,
958 msg->gpr_GInfo->gi_DrInfo);
959 #if AVOID_FLICKER
961 struct IBox ibox, fbox;
963 fbox.Left = data->minx;
964 fbox.Top = data->miny;
965 fbox.Width = data->maxx - data->minx + 1;
966 fbox.Height = data->maxy - data->miny + 1;
968 ibox.Left = data->minx + BORDERLVSPACINGX;
969 ibox.Top = data->miny + BORDERLVSPACINGY;
970 ibox.Width = (data->maxx - data->minx + 1) - BORDERLVSPACINGX * 2;
971 ibox.Height = (data->maxy - data->miny + 1) - BORDERLVSPACINGY * 2;
973 PaintInnerFrame(msg->gpr_RPort,
974 msg->gpr_GInfo->gi_DrInfo,
975 data->frame,
976 &fbox,
977 &ibox,
978 msg->gpr_GInfo->gi_DrInfo->dri_Pens[data->dosavemode ? TEXTPEN : BACKGROUNDPEN],
979 AslBase);
983 #endif
987 if ((clip = NewRectRegion(data->minx + BORDERLVSPACINGX,
988 data->miny + BORDERLVSPACINGY,
989 data->maxx - BORDERLVSPACINGX,
990 data->maxy - BORDERLVSPACINGY)))
992 struct Layer *lay = msg->gpr_GInfo->gi_Layer;
994 updating = (lay->Flags & LAYERUPDATING) != 0;
996 if (updating) EndUpdate(lay, FALSE);
997 oldclip = InstallClipRegion(lay, clip);
998 if (updating) BeginUpdate(lay);
1001 if (msg->gpr_Redraw == GREDRAW_REDRAW)
1003 renderallitems(cl, o, msg->gpr_RPort);
1005 } /* if (msg->gpr_Redraw == GREDRAW_REDRAW) */
1006 else if (msg->gpr_Redraw == GREDRAW_UPDATE)
1008 if (data->rendersingleitem == -1)
1010 WORD abs_scroll = (data->scroll >= 0) ? data->scroll : -data->scroll;
1012 if ((abs_scroll == 0) || (abs_scroll > data->visiblepixels / 2))
1014 renderallitems(cl, o, msg->gpr_RPort);
1016 else
1018 struct Rectangle rect;
1019 WORD scrollx1 = data->minx + BORDERLVSPACINGX;
1020 WORD scrolly1 = data->miny + BORDERLVSPACINGY;
1021 WORD scrollx2 = data->maxx - BORDERLVSPACINGX;
1022 WORD scrolly2 = data->maxy - BORDERLVSPACINGY;
1023 BOOL mustrefresh, update;
1025 ScrollRaster(msg->gpr_RPort, 0, data->scroll,
1026 scrollx1, scrolly1, scrollx2, scrolly2);
1028 mustrefresh = (msg->gpr_GInfo->gi_Layer->Flags & LAYERREFRESH) != 0;
1030 rect.MinX = scrollx1;
1031 rect.MaxX = scrollx2;
1033 if (data->scroll >= 0)
1035 rect.MinY = scrolly2 - abs_scroll;
1036 rect.MaxY = scrolly2;
1038 else
1040 rect.MinY = scrolly1;
1041 rect.MaxY = scrolly1 + abs_scroll;
1044 data->renderrect = &rect;
1045 renderallitems(cl, o, msg->gpr_RPort);
1046 data->renderrect = NULL;
1048 /* the LAYERUPDATING check should not be necessary,
1049 as then we should always have a GREDRAW_REDRAW,
1050 while here we are in GREDRAW_UPDATE. But just
1051 to be sure ... */
1053 if (mustrefresh && !(msg->gpr_GInfo->gi_Layer->Flags & LAYERUPDATING))
1055 if(!(update = BeginUpdate(msg->gpr_GInfo->gi_Layer)))
1057 EndUpdate(msg->gpr_GInfo->gi_Layer, FALSE);
1060 renderallitems(cl, o, msg->gpr_RPort);
1062 if(update) EndUpdate(msg->gpr_GInfo->gi_Layer, TRUE);
1067 else
1069 if (data->rendersingleitem >= data->top)
1071 struct Node *node = findnode(cl, o, data->rendersingleitem);
1073 renderitem(cl, o, node, data->rendersingleitem - data->top, msg->gpr_RPort);
1077 data->scroll = 0;
1078 data->rendersingleitem = -1;
1080 } /* if (msg->gpr_Redraw == GREDRAW_UPDATE) */
1082 if (clip)
1084 struct Layer *lay = msg->gpr_GInfo->gi_Layer;
1086 if (updating) EndUpdate(lay, FALSE);
1087 InstallClipRegion(lay, oldclip);
1088 if (updating) BeginUpdate(lay);
1090 DisposeRegion(clip);
1093 return retval;
1096 /***********************************************************************************/