Fixed building of catalogs.
[AROS.git] / workbench / classes / gadgets / aroslistview / helpfuncs.c
blob1043068228004955732fc5fc1ca870be84abac8a
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
9 #include <proto/alib.h>
10 #include <proto/dos.h>
11 #include <proto/graphics.h>
12 #include <proto/intuition.h>
13 #include <proto/utility.h>
15 #include <dos/dos.h>
16 #include <dos/rdargs.h>
17 #include <string.h>
18 #include <intuition/intuition.h>
19 #include <intuition/gadgetclass.h>
20 #include <gadgets/aroslist.h>
22 #include "aroslistview_intern.h"
24 //#define TURN_OFF_DEBUG
26 #ifndef TURN_OFF_DEBUG
27 #define DEBUG 1
28 #endif
30 #include <aros/debug.h>
32 STATIC VOID HandleSpecialMinWidth( struct ColumnAttrs *colattrs,
33 struct LVData *data
36 #define ForeachViewedCol(iterator, numcols) \
37 for (iterator = 0; iterator < numcols; iterator ++)
40 /**************************
41 ** ParseFormatString() **
42 **************************/
43 BOOL ParseFormatString( STRPTR formatstr,
44 struct LVData *data
47 #undef NUMPARAMS
48 #define NUMPARAMS 5
49 UBYTE templ[] = "COL=C/N,BAR=B/S,PREPARSE=P/K,DELTA=D/N,MINWIDTH=MIW/N";
51 struct RDArgs *rdarg;
52 BOOL success = FALSE;
53 struct ColumnAttrs *colattrs;
55 /* Give ReadArgs() som stack space to chew on so that time is not
56 * wasted on memory allocations
58 #undef WORKBUFSIZE
59 #define WORKBUFSIZE 500
60 UBYTE workbuf[WORKBUFSIZE];
62 colattrs = data->lvd_ColAttrs;
64 rdarg = (struct RDArgs *)AllocDosObject(DOS_RDARGS, NULL);
65 if (rdarg)
67 UWORD curcol = 0;
68 BOOL morecolumns = TRUE;
71 /* Reset the as-big-as-biggest-text property */
72 data->lvd_Flags &= ~LVFLG_SPECIALCOLWIDTH;
76 UWORD len = 0;
78 STRPTR str = formatstr;
79 IPTR argsarray[NUMPARAMS];
80 memset(argsarray, 0, UB(&argsarray[NUMPARAMS]) - UB(&argsarray[0]));
82 /* An example of format string is ",PREPARSE=c9, ," */
83 while (*str && *str != ',')
85 len ++;
86 str ++;
88 if (!*str)
89 morecolumns = FALSE;
91 /* Skip comma */
92 str ++;
94 rdarg->RDA_Source.CS_Buffer = formatstr;
95 rdarg->RDA_Source.CS_Length = len;
96 rdarg->RDA_Source.CS_CurChr = 0;
97 rdarg->RDA_Buffer = workbuf;
98 rdarg->RDA_BufSiz = WORKBUFSIZE;
100 if (!ReadArgs(templ, argsarray, rdarg))
102 FreeArgs(rdarg);
103 success = FALSE;
104 break;
106 else
109 /* Insert parsed info into colattr array */
110 /* A COL argument specified ? */
111 colattrs[curcol].ca_DHIndex = (UBYTE)((argsarray[0]) ? *((ULONG *)argsarray[0]) : curcol);
112 if (argsarray[1]) /* BAR */
113 colattrs[curcol].ca_Flags |= CAFLG_BAR;
114 if (argsarray[2]) /* PREPARSE */
116 /* Parse the preparse string */
117 str = (STRPTR)argsarray[2];
119 while (*str)
121 if (*str == 'c') /* Centre align text */
123 colattrs[curcol].ca_Flags &= ~CA_ALIGN_MASK;
124 colattrs[curcol].ca_Flags |= CA_ALIGN_CENTRE;
126 else if (*str == 'l') /* Left align text */
128 colattrs[curcol].ca_Flags &= ~CA_ALIGN_MASK;
129 colattrs[curcol].ca_Flags |= CA_ALIGN_LEFT;
131 else if (*str == 'r') /* Right align text */
133 colattrs[curcol].ca_Flags &= ~CA_ALIGN_MASK;
134 colattrs[curcol].ca_Flags |= CA_ALIGN_RIGHT;
136 else if (*str >= '0' && *str <= 9) /* Text background pen */
138 colattrs[curcol].ca_Pen = *str - '0';;
140 str ++;
145 if (argsarray[3]) /* DELTA */
146 colattrs[curcol].ca_Delta = (UWORD)((ULONG *)argsarray)[3];
148 if (argsarray[4]) /* MINWIDTH */
150 colattrs[curcol].ca_MinWidth = (UWORD)((ULONG *)argsarray)[4];
151 if (colattrs[curcol].ca_MinWidth == -1)
153 data->lvd_Flags |= LVFLG_SPECIALCOLWIDTH;
154 colattrs[curcol].ca_Flags |= CAFLG_SPECIALCOLWIDTH;
158 curcol ++;
159 formatstr += len + 1;
162 while (morecolumns);
164 data->lvd_ViewedColumns = curcol;
166 FreeDosObject(DOS_RDARGS, rdarg);
169 return (success);
172 /********************
173 ** GetGadgetIBox **
174 ********************/
176 /* Figure out the size of the gadget rectangle, taking relative
177 * positioning into account.
179 VOID GetGadgetIBox(Object *o, struct GadgetInfo *gi, struct IBox *ibox)
181 ibox->Left = EG(o)->LeftEdge;
182 ibox->Top = EG(o)->TopEdge;
183 ibox->Width = EG(o)->Width;
184 ibox->Height = EG(o)->Height;
186 if (gi)
188 if (EG(o)->Flags & GFLG_RELRIGHT)
189 ibox->Left += gi->gi_Domain.Width - 1;
191 if (EG(o)->Flags & GFLG_RELBOTTOM)
192 ibox->Top += gi->gi_Domain.Height - 1;
194 if (EG(o)->Flags & GFLG_RELWIDTH)
195 ibox->Width += gi->gi_Domain.Width;
197 if (EG(o)->Flags & GFLG_RELHEIGHT)
198 ibox->Height += gi->gi_Domain.Height;
202 /**********************
203 ** RenderEntries() **
204 **********************/
205 VOID RenderEntries( Class *cl,
206 Object *o,
207 struct gpRender *msg,
208 LONG startpos,
209 UWORD num,
210 BOOL erase
213 struct AROSP_List_GetEntry getentry_msg, *p_getentry_msg = &getentry_msg;
214 APTR item;
215 struct IBox container;
216 struct TextFont *oldfont;
217 WORD top;
218 LONG activepos;
219 LONG pos;
221 struct LVData *data = INST_DATA(cl, o);
222 UWORD *pens = msg->gpr_GInfo->gi_DrInfo->dri_Pens;
224 GetGadgetIBox(o, msg->gpr_GInfo, &container);
226 top = container.Top + LV_BORDERWIDTH_Y
227 + (startpos - data->lvd_First) * data->lvd_EntryHeight;
229 SetAPen(msg->gpr_RPort, pens[data->lvd_FrontPen]);
230 SetDrMd(msg->gpr_RPort, JAM1);
232 oldfont = msg->gpr_RPort->Font;
233 SetFont(msg->gpr_RPort, data->lvd_Font);
235 if (!(data->lvd_Flags & (LVFLG_READONLY|LVFLG_MULTISELECT)))
236 GetAttr(AROSA_List_Active, data->lvd_List, (IPTR *)&activepos);
238 getentry_msg.MethodID = AROSM_List_GetEntry;
239 getentry_msg.ItemPtr = &item;
241 /* Start rendering the listview entries */
242 for (pos = startpos; num --; pos ++)
245 register UWORD col;
246 struct TextExtent te;
247 struct ColumnAttrs *colattrs = data->lvd_ColAttrs;
249 BOOL erase_this_entry = erase;
250 UWORD erasepen = data->lvd_BackPen;
252 if (!(data->lvd_Flags & LVFLG_READONLY))
254 if (data->lvd_Flags & LVFLG_MULTISELECT)
256 LONG state;
257 DoMethod(data->lvd_List,
258 AROSM_List_Select,
259 pos,
260 AROSV_List_Select_Ask,
261 &state);
262 if (state)
264 erase_this_entry = TRUE;
265 erasepen = FILLPEN;
268 else
270 if (pos == activepos)
272 erase_this_entry = TRUE;
273 erasepen = FILLPEN;
278 if (erase_this_entry)
280 /* Erase the old text line */
281 SetAPen(msg->gpr_RPort, pens[erasepen]);
283 RectFill(msg->gpr_RPort,
284 container.Left + LV_BORDERWIDTH_X,
285 top,
286 container.Left + container.Width - LV_BORDERWIDTH_X - 1,
287 top + data->lvd_EntryHeight - 1);
289 SetAPen(msg->gpr_RPort, pens[data->lvd_FrontPen]);
294 getentry_msg.Position = pos;
295 DoMethodA(data->lvd_List, (Msg)p_getentry_msg);
296 if (!item)
297 break;
299 CallHookPkt( data->lvd_DisplayHook,
300 data->lvd_DHArray,
301 item);
303 ForeachViewedCol(col, data->lvd_ViewedColumns)
305 UWORD idx, len;
306 WORD left;
308 /* Get the index into DisplayHookArray for getting text for this column */
309 idx = colattrs[col].ca_DHIndex;
310 D(bug("Render: idx=%d, col=%d\n", idx, col));
311 /* How many characters of the string
312 * returned by DispHook are we able to view ?
314 len = TextFit(msg->gpr_RPort,
315 data->lvd_DHArray[idx],
316 strlen(data->lvd_DHArray[idx]),
317 &te,
318 NULL,
320 colattrs[col].ca_Width,
321 10000); /* We allready know that the height fit */
322 D(bug("Textfit len: %d\n", len));
323 /* Where do we place the len characters ? */
324 switch (colattrs[col].ca_Flags & CA_ALIGN_MASK)
326 case CA_ALIGN_LEFT:
327 left = colattrs[col].ca_Left;
328 break;
330 case CA_ALIGN_RIGHT:
331 left = colattrs[col].ca_Right - te.te_Width;
332 break;
334 default:
335 left = colattrs[col].ca_Left + ((colattrs[col].ca_Width - te.te_Width) >> 1);
336 break;
339 D(bug("Render: left=%d,idx=%d,text=%s\n", left, idx, data->lvd_DHArray[idx]));
341 Move(msg->gpr_RPort, left, top + data->lvd_Font->tf_Baseline);
342 Text(msg->gpr_RPort, data->lvd_DHArray[idx], len);
344 } /* ForeachViewedCol */
346 top += data->lvd_EntryHeight;
348 } /* for (entries to view) */
349 SetFont(msg->gpr_RPort, oldfont);
351 return;
355 /******************************
356 ** HandleSpecialMinWidth() **
357 ******************************/
359 STATIC VOID HandleSpecialMinWidth( struct ColumnAttrs *colattrs,
360 struct LVData *data
363 register UWORD i;
364 register LONG pos;
365 APTR item;
366 struct RastPort rp;
368 InitRastPort(&rp);
370 SetFont(&rp, data->lvd_Font);
373 /* Initialize the minwidths to 0 */
374 ForeachViewedCol(i, data->lvd_ViewedColumns)
375 if (colattrs[i].ca_Flags & CAFLG_SPECIALCOLWIDTH)
376 colattrs[i].ca_MinWidth = 0;
378 for (pos = 0; ; pos ++)
380 DoMethod(data->lvd_List, AROSM_List_GetEntry, pos, &item);
381 if (!item)
382 break;
384 /* Get the texts for a row in the list */
385 CallHookPkt(data->lvd_DisplayHook,
386 data->lvd_DHArray,
387 item);
389 ForeachViewedCol(i, data->lvd_ViewedColumns)
391 UWORD idx = colattrs[i].ca_DHIndex;
393 if (colattrs[i].ca_Flags & CAFLG_SPECIALCOLWIDTH)
395 UWORD length;
397 length = TextLength(&rp,
398 data->lvd_DHArray[idx],
399 strlen(data->lvd_DHArray[idx]));
401 if (length > colattrs[i].ca_MinWidth)
402 colattrs[i].ca_MinWidth = length;
404 } /* if (column should be viewed and width is as long as biggest textlength) */
406 } /* ForeachViewedCol() */
408 } /* for (iterate through list of items) */
410 return;
413 /************************
414 ** ComputeColumnWidts **
415 ************************/
417 VOID ComputeColumnWidths(UWORD listwidth,
418 struct LVData *data
422 /* First handle columns that want their minwidth to be the
423 * size of the largest entry in that column
426 struct ColumnAttrs *colattrs = data->lvd_ColAttrs;
427 UWORD sum_minwidths = 0;
428 UWORD remainder;
429 WORD on_each_col, pixels2divide;
430 register UWORD i;
432 /* Find number of pixels to divide between columns */
433 listwidth -= LV_BORDERWIDTH_X * 2
434 + data->lvd_HorSpacing * (data->lvd_ViewedColumns + 1);
436 if (data->lvd_Flags & LVFLG_SPECIALCOLWIDTH)
437 HandleSpecialMinWidth(colattrs, data);
439 /* Compute the sum of the minwidths and the number of columns to be */
440 ForeachViewedCol(i, data->lvd_ViewedColumns)
442 sum_minwidths += colattrs[i].ca_MinWidth;
446 /* Now we have three cases, 1) sum_minwidths > listwidth or
447 * 2) sum_minwidths < listwidth or 3) sum_minwidths == listwidth.
449 * 1): Divide listwidth - sum_minwidths pixels among the columns
451 * 2): Take sum_minwidths - listwidth pixels away from the columns
453 * 3): Just use each column's minwidth as width for the column
456 pixels2divide = listwidth - sum_minwidths;
458 /* Divide pixels equally among the columns */
460 on_each_col = pixels2divide / data->lvd_ViewedColumns;
461 remainder = pixels2divide % data->lvd_ViewedColumns;
463 if (pixels2divide > 0)
465 ForeachViewedCol(i, data->lvd_ViewedColumns)
467 colattrs[i].ca_Width = colattrs[i].ca_MinWidth;
468 colattrs[i].ca_Width += on_each_col;
470 if (remainder)
472 colattrs[i].ca_Width ++;
473 remainder --;
477 else if (pixels2divide < 0)
479 ForeachViewedCol(i, data->lvd_ViewedColumns)
481 colattrs[i].ca_Width = colattrs[i].ca_MinWidth;
482 colattrs[i].ca_Width += on_each_col;
484 if (remainder)
486 colattrs[i].ca_Width --;
487 remainder --;
491 else /* pixels2divide == 0 */
493 ForeachViewedCol(i, data->lvd_ViewedColumns)
495 colattrs[i].ca_Width = colattrs[i].ca_MinWidth;
499 return;
502 /**************************
503 ** ComputeColLeftRight **
504 **************************/
506 VOID ComputeColLeftRight(UWORD gadleft, struct LVData *data)
508 struct ColumnAttrs *colattrs;
509 register UWORD i;
510 register UWORD left;
512 left = gadleft + LV_BORDERWIDTH_X;
513 colattrs = data->lvd_ColAttrs;
515 ForeachViewedCol(i, data->lvd_ViewedColumns)
517 left += data->lvd_HorSpacing;
519 colattrs[i].ca_Left = left;
520 colattrs[i].ca_Right = (left += colattrs[i].ca_Width);
522 return;
526 /*********************
527 ** DrawListBorder **
528 *********************/
530 VOID DrawListBorder( struct RastPort *rp,
531 UWORD *pens,
532 struct IBox *bbox,
533 BOOL recessed
536 SetAPen (rp, pens[(recessed) ? SHINEPEN : SHADOWPEN]);
538 /* right */
539 RectFill (rp
540 , bbox->Left + bbox->Width - LV_BORDERWIDTH_X
541 , bbox->Top
542 , bbox->Left + bbox->Width - 1
543 , bbox->Top + bbox->Height - 1
546 /* bottom */
547 RectFill (rp
548 , bbox->Left
549 , bbox->Top + bbox->Height - LV_BORDERWIDTH_Y
550 , bbox->Left + bbox->Width - LV_BORDERWIDTH_X
551 , bbox->Top + bbox->Height - 1
554 SetAPen (rp, pens[(recessed) ? SHADOWPEN : SHINEPEN]);
556 /* top */
557 RectFill (rp
558 , bbox->Left
559 , bbox->Top
560 , bbox->Left + bbox->Width - LV_BORDERWIDTH_X
561 , bbox->Top + LV_BORDERWIDTH_Y - 1
564 /* left */
565 RectFill (rp
566 , bbox->Left
567 , bbox->Top
568 , bbox->Left + LV_BORDERWIDTH_X - 1
569 , bbox->Top + bbox->Height - LV_BORDERWIDTH_Y
572 WritePixel (rp, bbox->Left + bbox->Width - 1, bbox->Top);
573 WritePixel (rp, bbox->Left, bbox->Top + bbox->Height - 1);
575 return;
579 /*******************
580 ** ShownEntries **
581 *******************/
582 UWORD ShownEntries(struct LVData *data,
583 struct IBox *container
587 ULONG numentries;
588 UWORD shown;
590 GetAttr(AROSA_List_Entries, data->lvd_List, (IPTR *)&numentries);
592 /* This formula has a little "bug": The height of the rendered texts
593 ** are ibox.Height - height of 2 borders - 1 horizontal spacing line, but
594 ** since hor sp. always is < entryheight, the formula provides the right result
597 shown = (container->Height - LV_BORDERWIDTH_Y * 2) / data->lvd_EntryHeight;
599 shown = MIN(shown, numentries - data->lvd_First);
601 return (shown);
604 /******************
605 ** NotifyAttrs **
606 ******************/
608 VOID NotifyAttrs(Class *cl, Object *o, struct opSet *msg, struct TagItem *tags)
610 struct TagItem idtags[] =
612 {GA_ID, (IPTR)EG(o)->GadgetID},
613 {TAG_MORE, (IPTR)tags}
616 struct opUpdate nmsg = {OM_NOTIFY, idtags, msg->ops_GInfo, 0}, *p_nmsg = &nmsg;
617 struct LVData *data = INST_DATA(cl, o);
619 data->lvd_NotifyCount ++;
620 DoSuperMethodA(cl, o, (Msg)p_nmsg);
621 data->lvd_NotifyCount --;
622 return;