2 ** $Id: LVDemo.c,v 1.3 2000/01/12 21:17:25 bernie Exp $
7 ** This program demonstrates how to use the `boopsi' ListView gadget.
9 ** The source code shows how to create a resizable window with sliders
10 ** and how to write a custom `boopsi' class on top of the gadgetclass.
16 ** This project can be compiled with SAS/C 6.58 or better and
17 ** GeekGadget's GCC 2.95.2 or better.
18 ** You get the smallest executable with SAS/C. GCC will give
19 ** you quite a lot of warnings with the tag calls. Don't worry about them.
25 ** 0.1 (23.6.96) First try
26 ** 1.0 (21.1.97) First alpha release
27 ** 1.1 (24.5.97) Lotsa bugs fixed, implemented LVA_DoubleClick
28 ** 1.2 (31.8.97) Lotsa bugs fixed, implemented LVA_Clipped
29 ** Fixed memory leak with the test list
30 ** 1.3 (5.9.97) Improved initial sliders notification
31 ** Added multiple selection (LVA_DoMultiselect)
32 ** Fixed scrolling problems in some unusual conditions
33 ** 1.4 (8.9.97) Sets GMORE_SCROLLRASTER in OM_NEW
34 ** Multiple demo windows showing the features of the class
35 ** 1.5 (14.9.97) Added LVA_ItemSpacing
36 ** Finally fixed the LVA_Clipped mode!
38 ** 1.6 (2.10.97) Added StormC support
39 ** Implemented pixel-wise vertical scrolling for clipped mode
40 ** Reworked the class istance data and some code
42 ** 1.7 (15.12.98) Added ListBoxClass
43 ** Moved ScrollButtonClass in its own file
44 ** Removed function OpenClass()
45 ** Updated to latest version of VectorGlyphIClass
51 ** - This code has never been tested on V37.
53 ** - Middle mouse button scrolling does not work because
54 ** of a bug in input.device V40.
60 ** Copyright © 1996,97,98,00 by Bernardo Innocenti <bernie@cosmos.it>.
61 ** Freely Distributable, as long as source code, documentation and
62 ** executable are kept together. Permission is granted to release
63 ** modified versions of this program as long as all existing copyright
64 ** notices are left intact.
68 #define USE_BUILTIN_MATH
69 #define INTUI_V36_NAMES_ONLY
71 #define CLIB_ALIB_PROTOS_H /* Avoid including this header file because of
72 * conflicting definitions in BoopsiStubs.h
74 #include <exec/types.h>
75 #include <exec/memory.h>
76 #include <exec/execbase.h>
80 #include <intuition/intuition.h>
81 #include <intuition/intuitionbase.h>
82 #include <intuition/screens.h>
83 #include <intuition/classes.h>
84 #include <intuition/gadgetclass.h>
85 #include <intuition/imageclass.h>
86 #include <intuition/icclass.h>
87 #include <devices/timer.h>
89 #include <proto/exec.h>
90 #include <proto/intuition.h>
91 #include <proto/dos.h>
92 #include <proto/utility.h>
93 #include <proto/graphics.h>
94 #include <proto/diskfont.h>
100 #include <gadgets/ScrollButtonClass.h>
101 #include <gadgets/ListViewClass.h>
102 //#include <gadgets/ListBoxClass.h>
103 #include <images/VectorGlyphIClass.h>
105 #include "CompilerSpecific.h"
106 #include "DebugMacros.h"
107 #include "BoopsiStubs.h"
108 #include "ListMacros.h"
111 /* Local function prototypes */
113 LONG SAVEDS main (void);
114 static struct MsgPort *OpenDemoWindows (struct List *winlist);
115 static void CloseDemoWindows (struct List *winlist);
116 static struct LVHandle *OpenLVWin (CONST_STRPTR pubscreen,
117 struct MsgPort *winport, CONST_STRPTR title, ULONG mode, BOOL useListBox,
118 ULONG left, ULONG top, ULONG width, ULONG height, ULONG moreTags, ...);
119 static void CloseLVWin (struct LVHandle *lvhandle);
120 static struct Gadget *CreateLVGadgets (struct LVHandle *lvhandle,
121 struct TagItem *moreTags);
122 static void DisposeGadgets (struct LVHandle *lvhandle);
123 static void CreateItems (struct LVHandle *lvhandle);
124 static void CreateImages (struct DrawInfo *dri);
125 static void FreeImages (void);
128 /* Width and height for the demo vector images */
129 #define IMAGES_WIDTH 56
130 #define IMAGES_HEIGHT 48
136 GAD_LV, GAD_VSLIDER, GAD_HSLIDER,
137 GAD_UPBUTTON, GAD_DOWNBUTTON, GAD_LEFTBUTTON, GAD_RIGHTBUTTON,
145 IMG_UP, IMG_DOWN, IMG_LEFT, IMG_RIGHT, IMG_COUNT
151 /* This structure describes an open ListView window */
154 struct MinNode Link; /* Link LVHandle in a list of all windows */
155 struct Window *Win; /* Pointer to our window */
156 struct Screen *Scr; /* The screen we are opening our windows on */
157 struct DrawInfo *DrawInfo; /* DrawInfo for this screen */
158 ULONG Mode; /* ListView operating mode */
159 APTR Items; /* Items attached to the ListView */
160 ULONG Total; /* Number of items or -1 if unknown */
161 struct Gadget *Gad[GAD_COUNT];/* All our gadgets */
162 APTR Model; /* Make boopsi gadgets talk to each other */
163 struct List TestList; /* Items list for LVA_#?List modes */
164 ULONG *SelectArray; /* Array for storing multiple selections */
165 BOOL UseListBox; /* If TRUE, window uses the ListBox class */
172 UBYTE versiontag[] = "$VER: ListViewDemo 1.7 (15.12.98) by Bernardo Innocenti"
173 " (compiled with " _COMPILED_WITH ")";
177 /* Workaround a bug in StormC header file <proto/utility.h> */
180 #define UTILITYBASETYPE struct Library
182 #define UTILITYBASETYPE struct UtilityBase
186 struct ExecBase *SysBase;
187 UTILITYBASETYPE *UtilityBase;
188 struct IntuitionBase *IntuitionBase;
189 struct GfxBase *GfxBase;
190 struct Library *LayersBase;
191 struct Library *DiskfontBase;
194 /* Our private `boopsi' classes */
195 Class *ListViewClass;
196 //static Class *ListBoxClass;
197 static Class *ScrollButtonClass;
200 /* `boopsi' images for all windows
202 * These variables must be NULL at startup time. We are not
203 * going to explicitly initialize them because otherwise
204 * Storm C 2.0 would generate a C++-style constructor to do it :-).
205 * LoasSeg() will clear the BSS data section for us, so these
206 * variables are guaranteed to be NULL anyway.
208 static struct Image *Img[IMG_COUNT];
209 static ULONG ImgWidth[IMG_COUNT];
210 static ULONG ImgHeight[IMG_COUNT];
211 static struct TextFont *CustomFont;
215 /* Attribute translations for object interconnections */
217 static LONG MapLVToHSlider[] =
219 LVA_PixelLeft, PGA_Top,
220 LVA_PixelWidth, PGA_Total,
221 LVA_PixelHVisible, PGA_Visible,
225 static LONG MapHSliderToLV[] =
227 PGA_Top, LVA_PixelLeft,
232 static LONG MapLVToVSlider[] =
235 LVA_Total, PGA_Total,
236 LVA_Visible, PGA_Visible,
241 static LONG MapLVToVSlider[] =
243 LVA_PixelTop, PGA_Top,
244 LVA_PixelHeight, PGA_Total,
245 LVA_PixelVVisible, PGA_Visible,
251 static LONG MapVSliderToLV[] =
258 static LONG MapVSliderToLV[] =
260 PGA_Top, LVA_PixelTop,
266 static LONG MapUpButtonToLV[] =
272 static LONG MapDownButtonToLV[] =
278 static LONG MapLeftButtonToLV[] =
284 static LONG MapRightButtonToLV[] =
286 GA_ID, LVA_MoveRight,
294 /* StormC does not see that the expression "versiontag + 6" is constant
295 * and generates an initializer for it. The following definition
296 * works around this problem.
299 #define VERSIONTAG "ListViewDemo 1.7 by Bernardo Innocenti (compiled with " _COMPILED_WITH ")"
301 #define VERSIONTAG versiontag + 6
304 static STRPTR TestStrings[] =
308 "This `boopsi' ListView class supports all the features",
309 "of the Gadtools LISTVIEW_KIND, plus more stuff:",
311 " + Easy to use (almost a drop-in replacement for LISTVIEW_KIND)",
312 " + Can be resized and supports GREL_#? flags",
313 " + Multiple selection of items",
314 " + Notifies your `boopsi' sliders",
315 " + Multiple columns (TODO)",
316 " + Redraws quickly without clearing (which is good for solid window sizing)",
317 " + Horizontal scrolling (TODO)",
318 " + Items with `boopsi' images",
319 " + Using arrays instead of exec lists",
320 " + You can use `boopsi' label images instead of plain text",
321 " + You can use your own custom rendering hook",
322 " + You can use your own item item-retriving callback hook",
323 " + List title (TODO)",
324 " + Full Keyboard control (all control, alt and shift key combinations supported)",
325 " + Asynchronous scrolling with inertia (TODO)",
326 " + OS 3.0 optimized (V39-only version also available)",
327 " + RTG friendly and optimized (no planar stuff in chunky bitmaps)",
328 " + Small code! (<10K)",
329 " + Written in C to be highly portable across compilers and CPUs",
330 " + Full commented source code included",
331 " + Source code compiles with SAS/C, StormC and GCC",
332 " + Subclasses can be easlily derived from the base listview class",
334 "Please send comments to <bernardo.innocenti@usa.net>."
337 #define TESTSTRINGS_CNT (sizeof (TestStrings) / sizeof (CONST_STRPTR))
341 LONG SAVEDS _main(void)
343 /* Main program entry point. When linking without startup code, this
344 * must be the first function in the first object module listed on the
345 * linker command line. We also need to initialize SysBase and open
346 * all needed libraries manually.
349 struct MinList winlist;
350 struct MsgPort *winport;
351 struct Library *VectorGlyphBase = NULL;
352 LONG sigwait, sigrcvd;
353 LONG retval = RETURN_FAIL; /* = RETURN_FAIL */
357 /* Initialize SysBase */
358 SysBase = *((struct ExecBase **)4UL);
360 /* Open system libraries */
362 if ((UtilityBase = (UTILITYBASETYPE *) OpenLibrary("utility.library", 37L)) &&
363 (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39L)) &&
364 (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 39L)) &&
365 (LayersBase = OpenLibrary("layers.library", 39L)))
367 if ((ListViewClass = MakeListViewClass()) &&
368 // (ListBoxClass = MakeListBoxClass()) &&
369 (ScrollButtonClass = MakeScrollButtonClass()) &&
370 (VectorGlyphBase = OpenLibrary("images/vectorglyph.image", 0)))
372 NEWLIST((struct List *)&winlist);
374 if (winport = OpenDemoWindows((struct List *)&winlist))
376 /* Pre-calculate the signal mask for Wait() */
377 sigwait = (1 << winport->mp_SigBit) |
380 /* Now for the main loop. As you can see, it is really
381 * very compact. That's the magic of boopsi! :-)
385 /* Sleep until something interesting occurs */
386 sigrcvd = Wait(sigwait);
388 /* Now handle received signals */
391 if (sigrcvd & SIGBREAKF_CTRL_C)
395 if (sigrcvd & (1 << winport->mp_SigBit))
397 struct IntuiMessage *msg;
399 while (msg = (struct IntuiMessage *) GetMsg(winport))
403 case IDCMP_CLOSEWINDOW:
410 ReplyMsg((struct Message *) msg);
413 } /* End while (!quit) */
415 retval = 0; /* RETURN_OK */
417 CloseDemoWindows((struct List *)&winlist);
423 /* These cannot fail. Passing NULL is ok. */
424 CloseLibrary((struct Library *)VectorGlyphBase);
425 FreeScrollButtonClass(ScrollButtonClass);
426 // FreeListBoxClass(ListBoxClass);
427 FreeListViewClass(ListViewClass);
430 /* Passing NULL to CloseLibrary() was illegal in pre-V37 Exec.
431 * To avoid crashing when someone attempts to run this program
432 * on an old OS, we need to test the first library base we tried
437 CloseLibrary((struct Library *)LayersBase);
438 CloseLibrary((struct Library *)GfxBase);
439 CloseLibrary((struct Library *)IntuitionBase);
440 CloseLibrary((struct Library *)UtilityBase);
448 static struct MsgPort *OpenDemoWindows(struct List *winlist)
450 struct LVHandle *lvhandle;
451 struct MsgPort *winport;
453 if (DiskfontBase = OpenLibrary("diskfont.library", 0L))
455 static struct TextAttr attr =
463 CustomFont = OpenDiskFont(&attr);
464 CloseLibrary(DiskfontBase);
467 /* Setup windows shared Message Port */
468 if (winport = CreateMsgPort())
470 /* if (lvhandle = OpenLVWin(NULL, winport,
472 LVA_StringList, TRUE, 600, 20, 320, 128,
474 ADDTAIL(winlist, (struct Node *)lvhandle);
476 /* if (lvhandle = OpenLVWin(NULL, winport,
477 "LVA_TextFont = times/24/italic, LVA_Clipped = TRUE",
478 LVA_StringList, FALSE, 320, 320, 320, 64,
479 LVA_TextFont, CustomFont,
482 ADDTAIL(winlist, (struct Node *)lvhandle);
484 /* if (lvhandle = OpenLVWin(NULL, winport,
485 "LAYOUTA_Spacing = 4",
486 LVA_StringList, FALSE, 256, 256, 320, 64,
489 ADDTAIL(winlist, (struct Node *)lvhandle);
491 /* if (lvhandle = OpenLVWin(NULL, winport,
492 "GA_ReadOnly = TRUE; LVA_Selected = 3",
493 LVA_StringList, FALSE, 192, 192, 320, 64,
497 ADDTAIL(winlist, (struct Node *)lvhandle);
499 if (lvhandle = OpenLVWin(NULL, winport,
500 "Single selection image list, LVA_Clipped = TRUE",
501 LVA_ImageList, FALSE, 128, 128, 320, 128,
502 LVA_ItemHeight, IMAGES_HEIGHT,
505 ADDTAIL(winlist, (struct Node *)lvhandle);
507 if (lvhandle = OpenLVWin(NULL, winport,
508 "LVA_DoMultiSelect = TRUE; LVA_StringArray",
509 LVA_StringArray, FALSE, 64, 64, 320, 128,
510 LVA_DoMultiSelect, TRUE,
512 ADDTAIL(winlist, (struct Node *)lvhandle);
514 /* if (lvhandle = OpenLVWin(NULL, winport,
515 "Plain, single selection string list",
516 LVA_StringList, FALSE, 0, 20, 320, 128,
518 ADDTAIL(winlist, (struct Node *)lvhandle);
520 /* Abort only if no windows could be opened */
521 if (IsListEmpty(winlist))
523 DeleteMsgPort(winport);
524 CloseFont (CustomFont);
534 static void CloseDemoWindows(struct List *winlist)
536 struct MsgPort *winport = NULL;
537 struct LVHandle *lvhandle;
539 while (lvhandle = (struct LVHandle *) REMHEAD(winlist))
541 /* Safe way to close a shared IDCMP port window */
548 winport = lvhandle->Win->UserPort;
549 msg = (struct Message *) winport->mp_MsgList.lh_Head;
551 /* Now remove any pending message from the shared IDCMP port */
552 while (succ = msg->mn_Node.ln_Succ)
554 /* Since we are closing all our windows at once,
555 * we don't need to check to which window this
556 * message was addressed.
558 REMOVE((struct Node *)msg);
560 msg = (struct Message *) succ;
563 /* Keep intuition from freeing our port... */
564 lvhandle->Win->UserPort = NULL;
566 /* ...and from sending us any more messages. */
567 ModifyIDCMP(lvhandle->Win, 0L);
571 CloseLVWin(lvhandle);
574 DeleteMsgPort(winport); /* NULL is ok */
577 CloseFont(CustomFont);
583 static struct LVHandle *OpenLVWin(CONST_STRPTR pubscreen,
584 struct MsgPort *winport, CONST_STRPTR title, ULONG mode, BOOL useListBox,
585 ULONG left, ULONG top, ULONG width, ULONG height, ULONG moreTags, ...)
587 struct LVHandle *lvhandle;
588 struct Gadget *glist;
590 if (lvhandle = AllocMem(sizeof (struct LVHandle), MEMF_ANY | MEMF_CLEAR))
592 if (lvhandle->Scr = LockPubScreen(pubscreen))
594 /* GetScreenDrawInfo() never fails */
595 lvhandle->DrawInfo = GetScreenDrawInfo(lvhandle->Scr);
597 /* Set listview operating mode and ListBox flag */
598 lvhandle->Mode = mode;
599 lvhandle->UseListBox = useListBox;
601 CreateItems (lvhandle);
603 if (glist = CreateLVGadgets(lvhandle, (struct TagItem *)&moreTags))
605 if (lvhandle->Win = OpenWindowTags(NULL,
608 WA_InnerWidth, width,
609 WA_InnerHeight, height,
610 WA_PubScreen, lvhandle->Scr,
613 /* Since we are going to redraw the whole window anyway,
614 * we can disable backfilling to avoid flashes while
615 * resizing or revealing the window.
617 WA_BackFill, useListBox ? NULL : LAYERS_NOBACKFILL,
618 WA_ScreenTitle, versiontag + 6,
619 WA_Flags, WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIZEGADGET | WFLG_SIZEBRIGHT | WFLG_SIZEBBOTTOM |
620 WFLG_CLOSEGADGET | WFLG_SIMPLE_REFRESH | WFLG_NOCAREREFRESH,
621 WA_PubScreenFallBack, TRUE,
629 lvhandle->Win->UserPort = winport;
630 ModifyIDCMP(lvhandle->Win, IDCMP_CLOSEWINDOW);
632 /* We need to keep our screen locked all the time
633 * because we want to free the associated DrawInfo
634 * *after* the window has been closed and
635 * FreeScreenDrawInfo() wants a pointer to a *valid*
641 DisposeGadgets(lvhandle);
644 FreeScreenDrawInfo(lvhandle->Scr, lvhandle->DrawInfo);
645 /* lvhandle->DrawInfo = NULL */
647 UnlockPubScreen(NULL, lvhandle->Scr);
649 FreeMem(lvhandle, sizeof(struct LVHandle));
656 static void CloseLVWin(struct LVHandle *lvhandle)
658 /* Close our window. No need to reply queued messages,
659 * Intuition is clever enough to care about this for us.
661 CloseWindow(lvhandle->Win);
662 DisposeGadgets(lvhandle);
663 UnlockPubScreen(NULL, lvhandle->Scr);
665 FreeVec(lvhandle->SelectArray); /* NULL is ok */
667 if ((lvhandle->Mode == LVA_StringList) || (lvhandle->Mode == LVA_ImageList))
671 /* Free the test list */
672 while (node = REMHEAD (&lvhandle->TestList))
674 if (lvhandle->Mode == LVA_ImageList)
675 DisposeObject ((Object *)node->ln_Name);
676 FreeMem (node, sizeof (struct Node));
680 FreeMem (lvhandle, sizeof (struct LVHandle));
685 /* Diagram of object interconnections for the ListView window
686 * ==========================================================
688 * ScrollButtonClass objects
689 * +----------+ +------------+ +------------+ +-------------+
690 * | UpButton | | DownButton | | LeftButton | | RightButton |
691 * +----------+ +------------+ +------------+ +-------------+
692 * | GA_ID = | GA_ID = | GA_ID = | GA_ID =
693 * | LVA_MoveUp | LVA_MoveDown | LVA_MoveLeft | LVA_MoveRight
696 * | | +-----------------------+ |
697 * | | | +------------------------------------+
698 * | | | | propgclass object icclass object
699 * | | | | +-----------+ +--------------+
700 * | | | | | HSlider |<-----| PIPToHSlider |
701 * | | | | +-----------+ +--------------+
702 * | | | | PGA_Top = | ^ LVA_Top = PGA_Top
703 * | | | | LVA_Left | | LVA_Visible = PGA_Visible
706 * +-----------+ *********** |
707 * | |-------->* *------------+
708 * | ListView | * Model *
709 * | |<--------* *------------+
710 * +-----------+ *********** |
713 * LVA_Top | V icclass object
714 * +-----------+ +--------------+
715 * | VSlider |<-----| PIPToVSlider |
716 * +-----------+ +--------------+
717 * propgclass object LVA_Top = PGA_Top
718 * LVA_Visible = PGA_Visible
721 static struct Gadget *CreateLVGadgets(struct LVHandle *lvhandle,
722 struct TagItem *moreTags)
724 struct Screen *scr = lvhandle->Scr;
725 ULONG SizeWidth = 18, SizeHeight = 11; /* Default size */
726 struct Image *SizeImage;
728 /* Create a size image to get its... uhm... size */
729 if (SizeImage = NewObject(NULL, SYSICLASS,
730 SYSIA_Which, SIZEIMAGE,
731 SYSIA_DrawInfo, lvhandle->DrawInfo,
734 /* Get size gadget geometry */
735 GetAttr(IA_Width, SizeImage, &SizeWidth);
736 GetAttr(IA_Height, SizeImage, &SizeHeight);
738 /* And then get rid of it... */
739 DisposeObject(SizeImage);
743 /* if (lvhandle->UseListBox)
745 lvhandle->Gad[GAD_LV] = NewObject(ListBoxClass, NULL,
747 GA_Left, scr->WBorLeft,
748 GA_Top, scr->WBorTop + scr->Font->ta_YSize + 1,
749 GA_RelWidth, - SizeWidth - scr->WBorLeft,
750 GA_RelHeight, - (scr->WBorTop + scr->Font->ta_YSize + SizeHeight + 1),
751 GA_DrawInfo, lvhandle->DrawInfo,
752 lvhandle->Mode, lvhandle->Items,
753 LVA_Total, lvhandle->Total,
754 LVA_SelectArray, lvhandle->SelectArray,
757 return lvhandle->Gad[GAD_LV];
761 /* Code to create normal ListView class and its gadgets */
764 /* No need to check this: in case of failure we would just
765 * get no images in the scroll buttons, but we can still try
766 * to open our window anyway.
768 CreateImages(lvhandle->DrawInfo);
770 if (lvhandle->Model = NewObjectA(NULL, MODELCLASS, NULL))
771 if (lvhandle->Gad[GAD_LV] = NewObject(ListViewClass, NULL,
773 GA_Left, scr->WBorLeft,
774 GA_Top, scr->WBorTop + scr->Font->ta_YSize + 1,
775 GA_RelWidth, - SizeWidth - scr->WBorLeft,
776 GA_RelHeight, - (scr->WBorTop + scr->Font->ta_YSize + SizeHeight + 1),
777 GA_DrawInfo, lvhandle->DrawInfo,
778 ICA_TARGET, lvhandle->Model,
779 lvhandle->Mode, lvhandle->Items,
780 LVA_Total, lvhandle->Total,
781 LVA_SelectArray, lvhandle->SelectArray,
783 if (lvhandle->Gad[GAD_VSLIDER] = NewObject(NULL, PROPGCLASS,
785 GA_Previous, lvhandle->Gad[GAD_LV],
786 GA_RelRight, - SizeWidth + 5,
787 GA_Top, scr->WBorTop + scr->Font->ta_YSize + 2,
788 GA_Width, SizeWidth - 8,
789 GA_RelHeight, - (scr->WBorTop + scr->Font->ta_YSize +
790 SizeHeight + ImgHeight[IMG_DOWN] + ImgHeight[IMG_UP] + 4),
791 GA_RightBorder, TRUE,
792 GA_DrawInfo, lvhandle->DrawInfo,
793 PGA_Freedom, FREEVERT,
794 PGA_Borderless, ((lvhandle->DrawInfo->dri_Flags & DRIF_NEWLOOK) &&
795 (lvhandle->DrawInfo->dri_Depth != 1)),
797 ICA_TARGET, lvhandle->Model,
798 ICA_MAP, MapVSliderToLV,
800 if (lvhandle->Gad[GAD_HSLIDER] = NewObject(NULL, PROPGCLASS,
802 GA_Previous, lvhandle->Gad[GAD_VSLIDER],
803 GA_RelBottom, - SizeHeight + ((SizeHeight > 15) ? 4 : 3),
804 GA_Left, scr->WBorLeft,
805 GA_Height, SizeHeight - ((SizeHeight > 15) ? 6 : 4),
806 GA_RelWidth, - (SizeWidth + ImgWidth[IMG_RIGHT] + ImgWidth[IMG_LEFT] + scr->WBorLeft + 2),
807 GA_BottomBorder,TRUE,
808 GA_DrawInfo, lvhandle->DrawInfo,
809 PGA_Freedom, FREEHORIZ,
810 PGA_Borderless, ((lvhandle->DrawInfo->dri_Flags & DRIF_NEWLOOK) &&
811 (lvhandle->DrawInfo->dri_Depth != 1)),
813 ICA_TARGET, lvhandle->Model,
814 ICA_MAP, MapHSliderToLV,
816 if (lvhandle->Gad[GAD_UPBUTTON] = NewObject(ScrollButtonClass, NULL,
818 GA_Previous, lvhandle->Gad[GAD_HSLIDER],
819 GA_RelBottom, - SizeHeight - ImgHeight[IMG_DOWN] - ImgHeight[IMG_UP] + 1,
820 GA_RelRight, - ImgWidth[IMG_DOWN] + 1,
821 GA_RightBorder, TRUE,
822 GA_DrawInfo, lvhandle->DrawInfo,
823 GA_Image, Img[IMG_UP],
824 ICA_TARGET, lvhandle->Gad[GAD_LV],
825 ICA_MAP, MapUpButtonToLV,
827 if (lvhandle->Gad[GAD_DOWNBUTTON] = NewObject(ScrollButtonClass, NULL,
828 GA_ID, GAD_DOWNBUTTON,
829 GA_Previous, lvhandle->Gad[GAD_UPBUTTON],
830 GA_RelBottom, - SizeHeight - ImgHeight[IMG_DOWN] + 1,
831 GA_RelRight, - ImgWidth[IMG_DOWN] + 1,
832 GA_RightBorder, TRUE,
833 GA_DrawInfo, lvhandle->DrawInfo,
834 GA_Image, Img[IMG_DOWN],
835 ICA_TARGET, lvhandle->Gad[GAD_LV],
836 ICA_MAP, MapDownButtonToLV,
838 if (lvhandle->Gad[GAD_LEFTBUTTON] = NewObject(ScrollButtonClass, NULL,
839 GA_ID, GAD_LEFTBUTTON,
840 GA_Previous, lvhandle->Gad[GAD_DOWNBUTTON],
841 GA_RelBottom, - ImgHeight[IMG_LEFT] + 1,
842 GA_RelRight, - SizeWidth - ImgWidth[IMG_RIGHT] - ImgWidth[IMG_LEFT] + 1,
843 GA_BottomBorder,TRUE,
844 GA_DrawInfo, lvhandle->DrawInfo,
845 GA_Image, Img[IMG_LEFT],
846 ICA_TARGET, lvhandle->Gad[GAD_LV],
847 ICA_MAP, MapLeftButtonToLV,
849 if (lvhandle->Gad[GAD_RIGHTBUTTON] = NewObject(ScrollButtonClass, NULL,
850 GA_ID, GAD_RIGHTBUTTON,
851 GA_Previous, lvhandle->Gad[GAD_LEFTBUTTON],
852 GA_RelBottom, - ImgHeight[IMG_RIGHT] + 1,
853 GA_RelRight, - SizeWidth - ImgWidth[IMG_RIGHT] + 1,
854 GA_BottomBorder,TRUE,
855 GA_DrawInfo, lvhandle->DrawInfo,
856 GA_Image, Img[IMG_RIGHT],
857 ICA_TARGET, lvhandle->Gad[GAD_LV],
858 ICA_MAP, MapRightButtonToLV,
863 /* Connect VSlider to Model */
865 if (icobject = NewObject(NULL, ICCLASS,
866 ICA_TARGET, lvhandle->Gad[GAD_VSLIDER],
867 ICA_MAP, MapLVToVSlider,
869 if (!DoMethod(lvhandle->Model, OM_ADDMEMBER, icobject))
870 DisposeObject (icobject);
872 /* Connect HSlider to Model */
874 if (icobject = NewObject(NULL, ICCLASS,
875 ICA_TARGET, lvhandle->Gad[GAD_HSLIDER],
876 ICA_MAP, MapLVToHSlider,
878 if (!DoMethod(lvhandle->Model, OM_ADDMEMBER, icobject))
879 DisposeObject (icobject);
881 /* Connect Model to ListView */
883 SetAttrs(lvhandle->Model,
884 ICA_TARGET, lvhandle->Gad[GAD_LV],
887 return lvhandle->Gad[GAD_LV];
889 DisposeGadgets(lvhandle);
896 static void DisposeGadgets(struct LVHandle *lvhandle)
900 for (i = 0; i < GAD_COUNT; i++)
902 DisposeObject(lvhandle->Gad[i]);
903 /* lvhandle->Gad[i] = NULL; */
906 /* Freeing the Model will also free its two targets */
907 DisposeObject(lvhandle->Model);
908 /* lvhandle->Model = NULL */
913 static void CreateItems(struct LVHandle *lvhandle)
915 if ((lvhandle->Mode == LVA_StringList) || (lvhandle->Mode == LVA_ImageList))
921 if (lvhandle->Mode == LVA_StringList)
922 cnt = TESTSTRINGS_CNT;
923 else /* LVA_ImageList */
924 cnt = VG_IMGCOUNT * 8;
927 /* Build a list of nodes to test the list */
929 NEWLIST(&lvhandle->TestList);
931 for (i = 0; i < cnt; i++)
933 if (node = AllocMem(sizeof (struct Node), MEMF_PUBLIC))
935 if (lvhandle->Mode == LVA_StringList)
936 node->ln_Name = TestStrings[i];
938 node->ln_Name = (STRPTR) NewObject(NULL, VECTORGLYPHCLASS,
939 SYSIA_Which, i % VG_IMGCOUNT,
940 SYSIA_DrawInfo, lvhandle->DrawInfo,
941 IA_Width, IMAGES_WIDTH,
942 IA_Height, IMAGES_HEIGHT,
945 /* Unselect all items */
948 ADDTAIL (&lvhandle->TestList, node);
954 lvhandle->Items = &lvhandle->TestList;
956 else if (lvhandle->Mode == LVA_StringArray)
958 lvhandle->Items = TestStrings;
959 lvhandle->Total = TESTSTRINGS_CNT;
960 lvhandle->SelectArray = AllocVec (TESTSTRINGS_CNT * sizeof (ULONG),
961 MEMF_CLEAR | MEMF_PUBLIC);
963 else /* (lvhandle->Mode == LVA_ImageArray) */
965 lvhandle->Items = NULL; /* No items */
966 lvhandle->Total = -1; /* Unknown */
972 static void CreateImages(struct DrawInfo *dri)
974 /* Create 4 arrow images for the window scroll buttons.
976 * Why bother checking for failure? The arrow images are not
977 * life critical in our program...
980 static ULONG imagetypes[IMG_COUNT] = { UPIMAGE, DOWNIMAGE, LEFTIMAGE, RIGHTIMAGE };
983 for (i = 0; i < IMG_COUNT; i++)
985 if (Img[i] = (struct Image *)NewObject (NULL, SYSICLASS,
986 SYSIA_Which, imagetypes[i],
990 /* Ask image width and height */
991 GetAttr(IA_Width, Img[i], &ImgWidth[i]);
992 GetAttr(IA_Height, Img[i], &ImgHeight[i]);
998 static void FreeImages (void)
1002 for (i = 0; i < IMG_COUNT; i++)
1003 DisposeObject((APTR)Img[i]); /* DisposeObject(NULL) is safe */