Initial commit
[amiga/BoopsiListView.git] / ListViewHooks.c
1 /*
2 **      ListViewHooks.c
3 **
4 **      Copyright (C) 1996,97 Bernardo Innocenti
5 **
6 **      Use 4 chars wide TABs to read this file
7 **
8 **      Internal drawing and browsing hooks the listview class
9 */
10
11 #define USE_BUILTIN_MATH
12 #define INTUI_V36_NAMES_ONLY
13 #define __USE_SYSBASE
14 #define  CLIB_ALIB_PROTOS_H             /* Avoid dupe defs of boopsi funcs */
15
16 #include <exec/types.h>
17 #include <intuition/intuition.h>
18 #include <graphics/gfxbase.h>
19 #include <graphics/gfxmacros.h>
20
21 #include <proto/intuition.h>
22 #include <proto/graphics.h>
23
24 #ifdef __STORM__
25         #pragma header
26 #endif
27
28 #include "CompilerSpecific.h"
29 #include "Debug.h"
30
31 #define LV_GADTOOLS_STUFF
32 #include "ListViewClass.h"
33
34
35
36 /* Definitions for builtin List hook */
37
38 APTR HOOKCALL ListGetItem (
39         REG(a0, struct Hook                     *hook),
40         REG(a1, struct Node                     *node),
41         REG(a2, struct lvGetItem        *lvgi));
42 APTR HOOKCALL ListGetNext (
43         REG(a0, struct Hook                     *hook),
44         REG(a1, struct Node                     *node),
45         REG(a2, struct lvGetNext        *lvgn));
46 APTR HOOKCALL ListGetPrev (
47         REG(a0, struct Hook                     *hook),
48         REG(a1, struct Node                     *node),
49         REG(a2, struct lvGetPrev        *lvgp));
50 ULONG HOOKCALL ListStringDrawItem (
51         REG(a0, struct Hook                     *hook),
52         REG(a1, struct Node                     *node),
53         REG(a2, struct lvDrawItem       *lvdi));
54 ULONG HOOKCALL ListImageDrawItem (
55         REG(a0, struct Hook                     *hook),
56         REG(a1, struct Node                     *node),
57         REG(a2, struct lvDrawItem       *lvdi));
58
59
60 /* Definitions for builtin Array hook */
61
62 APTR HOOKCALL ArrayGetItem (
63         REG(a0, struct Hook                     *hook),
64         REG(a1, STRPTR                          *item),
65         REG(a2, struct lvGetItem        *lvgi));
66 ULONG HOOKCALL StringDrawItem (
67         REG(a0, struct Hook                     *hook),
68         REG(a1, STRPTR                           str),
69         REG(a2, struct lvDrawItem       *lvdi));
70 ULONG HOOKCALL ImageDrawItem (
71         REG(a0, struct Hook                     *hook),
72         REG(a1, struct Image            *img),
73         REG(a2, struct lvDrawItem       *lvdi));
74
75
76
77 APTR HOOKCALL ListGetItem (
78         REG(a0, struct Hook                     *hook),
79         REG(a1, struct Node                     *node),
80         REG(a2, struct lvGetItem        *lvg))
81 {
82         ULONG i;
83
84         ASSERT_VALIDNO0(lvg)
85
86         node = ((struct List *)(lvg->lvgi_Items))->lh_Head;
87
88         /* Warning: no sanity check is made against
89          * list being shorter than expected!
90          */
91         for (i = 0; i < lvg->lvgi_Number; i++)
92         {
93                 ASSERT_VALIDNO0(node)
94                 node = node->ln_Succ;
95         }
96
97         return (APTR)node;
98 }
99
100
101
102 APTR HOOKCALL ListGetNext (
103         REG(a0, struct Hook                     *hook),
104         REG(a1, struct Node                     *node),
105         REG(a2, struct lvGetItem        *lvg))
106 {
107         ASSERT_VALIDNO0(node)
108         ASSERT_VALIDNO0(lvg)
109
110         return (APTR)(node->ln_Succ->ln_Succ ? node->ln_Succ : NULL);
111 }
112
113
114
115 APTR HOOKCALL ListGetPrev (
116         REG(a0, struct Hook                     *hook),
117         REG(a1, struct Node                     *node),
118         REG(a2, struct lvGetItem        *lvg))
119 {
120         ASSERT_VALIDNO0(node)
121         ASSERT_VALIDNO0(lvg)
122
123         return (APTR)(node->ln_Pred->ln_Pred ? node->ln_Pred : NULL);
124 }
125
126
127
128 ULONG HOOKCALL ListStringDrawItem (
129         REG(a0, struct Hook                     *hook),
130         REG(a1, struct Node                     *node),
131         REG(a2, struct lvDrawItem       *lvdi))
132 {
133         ASSERT_VALIDNO0(node)
134         ASSERT_VALIDNO0(lvdi)
135
136         return StringDrawItem (hook, node->ln_Name, lvdi);
137 }
138
139
140
141 ULONG HOOKCALL ListImageDrawItem (
142         REG(a0, struct Hook                     *hook),
143         REG(a1, struct Node                     *node),
144         REG(a2, struct lvDrawItem       *lvdi))
145 {
146         ASSERT_VALIDNO0(node)
147         ASSERT_VALIDNO0(lvdi)
148
149         return ImageDrawItem (hook, (struct Image *)node->ln_Name, lvdi);
150 }
151
152
153
154 APTR HOOKCALL ArrayGetItem (
155         REG(a0, struct Hook                     *hook),
156         REG(a1, STRPTR                          *item),
157         REG(a2, struct lvGetItem        *lvg))
158 {
159         ASSERT_VALIDNO0(lvg)
160         ASSERT_VALIDNO0(lvg->lvgi_Items)
161
162         return (APTR)(((STRPTR *)lvg->lvgi_Items)[lvg->lvgi_Number]);
163 }
164
165
166
167 ULONG HOOKCALL StringDrawItem (
168         REG(a0, struct Hook                     *hook),
169         REG(a1, STRPTR                           str),
170         REG(a2, struct lvDrawItem       *lvdi))
171 {
172         struct RastPort *rp;
173         ULONG len;
174
175         ASSERT_VALIDNO0(lvdi)
176         rp = lvdi->lvdi_RastPort;
177         ASSERT_VALIDNO0(rp)
178         ASSERT_VALID(str)
179
180         if (!str)
181                 /* Move to the leftmost pixel of the rectangle
182                  * to have the following RectFill() clear all the line
183                  */
184                 Move (rp, lvdi->lvdi_Bounds.MinX, 0);
185         else
186         {
187                 struct TextExtent textent;
188
189                 if (lvdi->lvdi_State == LVR_NORMAL)
190                 {
191 #ifndef OS30_ONLY
192                         if (GfxBase->LibNode.lib_Version < 39)
193                         {
194                                 SetAPen (rp, lvdi->lvdi_DrawInfo->dri_Pens[TEXTPEN]);
195                                 SetBPen (rp, lvdi->lvdi_DrawInfo->dri_Pens[BACKGROUNDPEN]);
196                                 SetDrMd (rp, JAM2);
197                         }
198                         else
199 #endif /* !OS30_ONLY */
200                         SetABPenDrMd (rp, lvdi->lvdi_DrawInfo->dri_Pens[TEXTPEN],
201                                 lvdi->lvdi_DrawInfo->dri_Pens[BACKGROUNDPEN],
202                                 JAM2);
203                 }
204                 else
205                 {
206 #ifndef OS30_ONLY
207                         if (GfxBase->LibNode.lib_Version < 39)
208                         {
209                                 SetAPen (rp, lvdi->lvdi_DrawInfo->dri_Pens[FILLTEXTPEN]);
210                                 SetBPen (rp, lvdi->lvdi_DrawInfo->dri_Pens[FILLPEN]);
211                                 SetDrMd (rp, JAM2);
212                         }
213                         else
214 #endif /* !OS30_ONLY */
215                                 SetABPenDrMd (rp, lvdi->lvdi_DrawInfo->dri_Pens[FILLTEXTPEN],
216                                         lvdi->lvdi_DrawInfo->dri_Pens[FILLPEN],
217                                         JAM2);
218                 }
219
220                 Move (rp, lvdi->lvdi_Bounds.MinX, lvdi->lvdi_Bounds.MinY + rp->Font->tf_Baseline);
221
222                 len = strlen (str);
223
224                 if (!(lvdi->lvdi_Flags & LVF_CLIPPED))
225                 {
226                         /* Calculate how much text will fit in the listview width */
227                         len = TextFit (rp, str, len, &textent, NULL, 1,
228                                 lvdi->lvdi_Bounds.MaxX - lvdi->lvdi_Bounds.MinX + 1,
229                                 lvdi->lvdi_Bounds.MaxY - lvdi->lvdi_Bounds.MinY + 1);
230                 }
231
232                 Text (rp, str, len);
233
234                 /* Text() will move the pen X position to
235                  * lvdi->lvdi_Bounds.MinX + textent.te_Width.
236                  */
237         }
238
239         /* Now clear the rest of the row. rp->cp_x is updated by Text() to the
240          * next character to print.
241          */
242         SetAPen (rp, lvdi->lvdi_DrawInfo->dri_Pens[(lvdi->lvdi_State == LVR_NORMAL) ?
243                 BACKGROUNDPEN : FILLPEN]);
244         RectFill (rp, rp->cp_x,
245                 lvdi->lvdi_Bounds.MinY,
246                 lvdi->lvdi_Bounds.MaxX,
247                 lvdi->lvdi_Bounds.MaxY);
248
249
250         return LVCB_OK;
251 }
252
253
254
255 ULONG HOOKCALL ImageDrawItem (
256         REG(a0, struct Hook                     *hook),
257         REG(a1, struct Image            *img),
258         REG(a2, struct lvDrawItem       *lvdi))
259 {
260         struct RastPort *rp;
261         UWORD left;
262
263         ASSERT_VALID(img)
264         ASSERT_VALIDNO0(lvdi)
265         rp = lvdi->lvdi_RastPort;
266         ASSERT_VALIDNO0(rp)
267
268         if (!img)
269                 /* Move to the leftmost pixel of the item rectangle
270                  * to have the following RectFill() clear all the line
271                  */
272                 left = lvdi->lvdi_Bounds.MinX;
273         else
274         {
275                 DrawImageState (rp, img,
276                         lvdi->lvdi_Bounds.MinX, lvdi->lvdi_Bounds.MinY,
277                         lvdi->lvdi_State, lvdi->lvdi_DrawInfo);
278
279                 left = lvdi->lvdi_Bounds.MinX + img->Width;
280         }
281
282         /* Now clear the rest of the row. rp->cp_x is updated by Text() to the
283          * next character to print.
284          */
285         SetAPen (rp, lvdi->lvdi_DrawInfo->dri_Pens[(lvdi->lvdi_State == LVR_NORMAL) ?
286                 BACKGROUNDPEN : FILLPEN]);
287         RectFill (rp, left,
288                 lvdi->lvdi_Bounds.MinY,
289                 lvdi->lvdi_Bounds.MaxX,
290                 lvdi->lvdi_Bounds.MaxY);
291
292         return LVCB_OK;
293 }