Some compiler warnings removed.
[cake.git] / workbench / classes / gadgets / aroslistview / helpfuncs.c
blob2ed33fe0c393a0db27fa64fc698012a72ff6e3b4
1 /*
2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
9 #include <proto/dos.h>
10 #include <proto/graphics.h>
11 #include <proto/intuition.h>
12 #include <proto/utility.h>
13 #include <dos/dos.h>
14 #include <dos/rdargs.h>
15 #include <string.h>
16 #include <intuition/intuition.h>
17 #include <intuition/gadgetclass.h>
18 #include <gadgets/aroslist.h>
20 #include "aroslistview_intern.h"
22 //#define TURN_OFF_DEBUG
24 #ifndef TURN_OFF_DEBUG
25 #define DEBUG 1
26 #endif
28 #include <aros/debug.h>
30 STATIC VOID HandleSpecialMinWidth( struct ColumnAttrs *colattrs,
31 struct LVData *data
34 #define ForeachViewedCol(iterator, numcols) \
35 for (iterator = 0; iterator < numcols; iterator ++)
38 /**************************
39 ** ParseFormatString() **
40 **************************/
41 BOOL ParseFormatString( STRPTR formatstr,
42 struct LVData *data
45 #undef NUMPARAMS
46 #define NUMPARAMS 5
47 UBYTE templ[] = "COL=C/N,BAR=B/S,PREPARSE=P/K,DELTA=D/N,MINWIDTH=MIW/N";
49 struct RDArgs *rdarg;
50 BOOL success = FALSE;
51 struct ColumnAttrs *colattrs;
53 /* Give ReadArgs() som stack space to chew on so that time is not
54 * wasted on memory allocations
56 #undef WORKBUFSIZE
57 #define WORKBUFSIZE 500
58 UBYTE workbuf[WORKBUFSIZE];
60 colattrs = data->lvd_ColAttrs;
62 rdarg = (struct RDArgs *)AllocDosObject(DOS_RDARGS, NULL);
63 if (rdarg)
65 UWORD curcol = 0;
66 BOOL morecolumns = TRUE;
69 /* Reset the as-big-as-biggest-text property */
70 data->lvd_Flags &= ~LVFLG_SPECIALCOLWIDTH;
74 UWORD len = 0;
76 STRPTR str = formatstr;
77 IPTR argsarray[NUMPARAMS];
78 memset(argsarray, 0, UB(&argsarray[NUMPARAMS]) - UB(&argsarray[0]));
80 /* An example of format string is ",PREPARSE=c9, ," */
81 while (*str && *str != ',')
83 len ++;
84 str ++;
86 if (!*str)
87 morecolumns = FALSE;
89 /* Skip comma */
90 str ++;
92 rdarg->RDA_Source.CS_Buffer = formatstr;
93 rdarg->RDA_Source.CS_Length = len;
94 rdarg->RDA_Source.CS_CurChr = 0;
95 rdarg->RDA_Buffer = workbuf;
96 rdarg->RDA_BufSiz = WORKBUFSIZE;
98 if (!ReadArgs(templ, argsarray, rdarg))
100 FreeArgs(rdarg);
101 success = FALSE;
102 break;
104 else
107 /* Insert parsed info into colattr array */
108 /* A COL argument specified ? */
109 colattrs[curcol].ca_DHIndex = (UBYTE)((argsarray[0]) ? *((ULONG *)argsarray[0]) : curcol);
110 if (argsarray[1]) /* BAR */
111 colattrs[curcol].ca_Flags |= CAFLG_BAR;
112 if (argsarray[2]) /* PREPARSE */
114 /* Parse the preparse string */
115 str = (STRPTR)argsarray[2];
117 while (*str)
119 if (*str == 'c') /* Centre align text */
121 colattrs[curcol].ca_Flags &= ~CA_ALIGN_MASK;
122 colattrs[curcol].ca_Flags |= CA_ALIGN_CENTRE;
124 else if (*str == 'l') /* Left align text */
126 colattrs[curcol].ca_Flags &= ~CA_ALIGN_MASK;
127 colattrs[curcol].ca_Flags |= CA_ALIGN_LEFT;
129 else if (*str == 'r') /* Right align text */
131 colattrs[curcol].ca_Flags &= ~CA_ALIGN_MASK;
132 colattrs[curcol].ca_Flags |= CA_ALIGN_RIGHT;
134 else if (*str >= '0' && *str <= 9) /* Text background pen */
136 colattrs[curcol].ca_Pen = *str - '0';;
138 str ++;
143 if (argsarray[3]) /* DELTA */
144 colattrs[curcol].ca_Delta = (UWORD)((ULONG *)argsarray)[3];
146 if (argsarray[4]) /* MINWIDTH */
148 colattrs[curcol].ca_MinWidth = (UWORD)((ULONG *)argsarray)[4];
149 if (colattrs[curcol].ca_MinWidth == -1)
151 data->lvd_Flags |= LVFLG_SPECIALCOLWIDTH;
152 colattrs[curcol].ca_Flags |= CAFLG_SPECIALCOLWIDTH;
156 curcol ++;
157 formatstr += len + 1;
160 while (morecolumns);
162 data->lvd_ViewedColumns = curcol;
164 FreeDosObject(DOS_RDARGS, rdarg);
167 return (success);
170 /********************
171 ** GetGadgetIBox **
172 ********************/
174 /* Figure out the size of the gadget rectangle, taking relative
175 * positioning into account.
177 VOID GetGadgetIBox(Object *o, struct GadgetInfo *gi, struct IBox *ibox)
179 ibox->Left = EG(o)->LeftEdge;
180 ibox->Top = EG(o)->TopEdge;
181 ibox->Width = EG(o)->Width;
182 ibox->Height = EG(o)->Height;
184 if (gi)
186 if (EG(o)->Flags & GFLG_RELRIGHT)
187 ibox->Left += gi->gi_Domain.Width - 1;
189 if (EG(o)->Flags & GFLG_RELBOTTOM)
190 ibox->Top += gi->gi_Domain.Height - 1;
192 if (EG(o)->Flags & GFLG_RELWIDTH)
193 ibox->Width += gi->gi_Domain.Width;
195 if (EG(o)->Flags & GFLG_RELHEIGHT)
196 ibox->Height += gi->gi_Domain.Height;
200 /**********************
201 ** RenderEntries() **
202 **********************/
203 VOID RenderEntries( Class *cl,
204 Object *o,
205 struct gpRender *msg,
206 LONG startpos,
207 UWORD num,
208 BOOL erase
211 struct AROSP_List_GetEntry getentry_msg, *p_getentry_msg = &getentry_msg;
212 APTR item;
213 struct IBox container;
214 struct TextFont *oldfont;
215 WORD top;
216 LONG activepos;
217 LONG pos;
219 struct LVData *data = INST_DATA(cl, o);
220 UWORD *pens = msg->gpr_GInfo->gi_DrInfo->dri_Pens;
222 GetGadgetIBox(o, msg->gpr_GInfo, &container);
224 top = container.Top + LV_BORDERWIDTH_Y
225 + (startpos - data->lvd_First) * data->lvd_EntryHeight;
227 SetAPen(msg->gpr_RPort, pens[data->lvd_FrontPen]);
228 SetDrMd(msg->gpr_RPort, JAM1);
230 oldfont = msg->gpr_RPort->Font;
231 SetFont(msg->gpr_RPort, data->lvd_Font);
233 if (!(data->lvd_Flags & (LVFLG_READONLY|LVFLG_MULTISELECT)))
234 GetAttr(AROSA_List_Active, data->lvd_List, (IPTR *)&activepos);
236 getentry_msg.MethodID = AROSM_List_GetEntry;
237 getentry_msg.ItemPtr = &item;
239 /* Start rendering the listview entries */
240 for (pos = startpos; num --; pos ++)
243 register UWORD col;
244 struct TextExtent te;
245 struct ColumnAttrs *colattrs = data->lvd_ColAttrs;
247 BOOL erase_this_entry = erase;
248 UWORD erasepen = data->lvd_BackPen;
250 if (!(data->lvd_Flags & LVFLG_READONLY))
252 if (data->lvd_Flags & LVFLG_MULTISELECT)
254 LONG state;
255 DoMethod(data->lvd_List,
256 AROSM_List_Select,
257 pos,
258 AROSV_List_Select_Ask,
259 &state);
260 if (state)
262 erase_this_entry = TRUE;
263 erasepen = FILLPEN;
266 else
268 if (pos == activepos)
270 erase_this_entry = TRUE;
271 erasepen = FILLPEN;
276 if (erase_this_entry)
278 /* Erase the old text line */
279 SetAPen(msg->gpr_RPort, pens[erasepen]);
281 RectFill(msg->gpr_RPort,
282 container.Left + LV_BORDERWIDTH_X,
283 top,
284 container.Left + container.Width - LV_BORDERWIDTH_X - 1,
285 top + data->lvd_EntryHeight - 1);
287 SetAPen(msg->gpr_RPort, pens[data->lvd_FrontPen]);
292 getentry_msg.Position = pos;
293 DoMethodA(data->lvd_List, (Msg)p_getentry_msg);
294 if (!item)
295 break;
297 CallHookPkt( data->lvd_DisplayHook,
298 data->lvd_DHArray,
299 item);
301 ForeachViewedCol(col, data->lvd_ViewedColumns)
303 UWORD idx, len;
304 WORD left;
306 /* Get the index into DisplayHookArray for getting text for this column */
307 idx = colattrs[col].ca_DHIndex;
308 D(bug("Render: idx=%d, col=%d\n", idx, col));
309 /* How many characters of the string
310 * returned by DispHook are we able to view ?
312 len = TextFit(msg->gpr_RPort,
313 data->lvd_DHArray[idx],
314 strlen(data->lvd_DHArray[idx]),
315 &te,
316 NULL,
318 colattrs[col].ca_Width,
319 10000); /* We allready know that the height fit */
320 D(bug("Textfit len: %d\n", len));
321 /* Where do we place the len characters ? */
322 switch (colattrs[col].ca_Flags & CA_ALIGN_MASK)
324 case CA_ALIGN_LEFT:
325 left = colattrs[col].ca_Left;
326 break;
328 case CA_ALIGN_RIGHT:
329 left = colattrs[col].ca_Right - te.te_Width;
330 break;
332 default:
333 left = colattrs[col].ca_Left + ((colattrs[col].ca_Width - te.te_Width) >> 1);
334 break;
337 D(bug("Render: left=%d,idx=%d,text=%s\n", left, idx, data->lvd_DHArray[idx]));
339 Move(msg->gpr_RPort, left, top + data->lvd_Font->tf_Baseline);
340 Text(msg->gpr_RPort, data->lvd_DHArray[idx], len);
342 } /* ForeachViewedCol */
344 top += data->lvd_EntryHeight;
346 } /* for (entries to view) */
347 SetFont(msg->gpr_RPort, oldfont);
349 return;
353 /******************************
354 ** HandleSpecialMinWidth() **
355 ******************************/
357 STATIC VOID HandleSpecialMinWidth( struct ColumnAttrs *colattrs,
358 struct LVData *data
361 register UWORD i;
362 register LONG pos;
363 APTR item;
364 struct RastPort rp;
366 InitRastPort(&rp);
368 SetFont(&rp, data->lvd_Font);
371 /* Initialize the minwidths to 0 */
372 ForeachViewedCol(i, data->lvd_ViewedColumns)
373 if (colattrs[i].ca_Flags & CAFLG_SPECIALCOLWIDTH)
374 colattrs[i].ca_MinWidth = 0;
376 for (pos = 0; ; pos ++)
378 DoMethod(data->lvd_List, AROSM_List_GetEntry, pos, &item);
379 if (!item)
380 break;
382 /* Get the texts for a row in the list */
383 CallHookPkt(data->lvd_DisplayHook,
384 data->lvd_DHArray,
385 item);
387 ForeachViewedCol(i, data->lvd_ViewedColumns)
389 UWORD idx = colattrs[i].ca_DHIndex;
391 if (colattrs[i].ca_Flags & CAFLG_SPECIALCOLWIDTH)
393 UWORD length;
395 length = TextLength(&rp,
396 data->lvd_DHArray[idx],
397 strlen(data->lvd_DHArray[idx]));
399 if (length > colattrs[i].ca_MinWidth)
400 colattrs[i].ca_MinWidth = length;
402 } /* if (column should be viewed and width is as long as biggest textlength) */
404 } /* ForeachViewedCol() */
406 } /* for (iterate through list of items) */
408 return;
411 /************************
412 ** ComputeColumnWidts **
413 ************************/
415 VOID ComputeColumnWidths(UWORD listwidth,
416 struct LVData *data
420 /* First handle columns that want their minwidth to be the
421 * size of the largest entry in that column
424 struct ColumnAttrs *colattrs = data->lvd_ColAttrs;
425 UWORD sum_minwidths = 0;
426 UWORD remainder;
427 WORD on_each_col, pixels2divide;
428 register UWORD i;
430 /* Find number of pixels to divide between columns */
431 listwidth -= LV_BORDERWIDTH_X * 2
432 + data->lvd_HorSpacing * (data->lvd_ViewedColumns + 1);
434 if (data->lvd_Flags & LVFLG_SPECIALCOLWIDTH)
435 HandleSpecialMinWidth(colattrs, data);
437 /* Compute the sum of the minwidths and the number of columns to be */
438 ForeachViewedCol(i, data->lvd_ViewedColumns)
440 sum_minwidths += colattrs[i].ca_MinWidth;
444 /* Now we have three cases, 1) sum_minwidths > listwidth or
445 * 2) sum_minwidths < listwidth or 3) sum_minwidths == listwidth.
447 * 1): Divide listwidth - sum_minwidths pixels among the columns
449 * 2): Take sum_minwidths - listwidth pixels away from the columns
451 * 3): Just use each column's minwidth as width for the column
454 pixels2divide = listwidth - sum_minwidths;
456 /* Divide pixels equally among the columns */
458 on_each_col = pixels2divide / data->lvd_ViewedColumns;
459 remainder = pixels2divide % data->lvd_ViewedColumns;
461 if (pixels2divide > 0)
463 ForeachViewedCol(i, data->lvd_ViewedColumns)
465 colattrs[i].ca_Width = colattrs[i].ca_MinWidth;
466 colattrs[i].ca_Width += on_each_col;
468 if (remainder)
470 colattrs[i].ca_Width ++;
471 remainder --;
475 else if (pixels2divide < 0)
477 ForeachViewedCol(i, data->lvd_ViewedColumns)
479 colattrs[i].ca_Width = colattrs[i].ca_MinWidth;
480 colattrs[i].ca_Width += on_each_col;
482 if (remainder)
484 colattrs[i].ca_Width --;
485 remainder --;
489 else /* pixels2divide == 0 */
491 ForeachViewedCol(i, data->lvd_ViewedColumns)
493 colattrs[i].ca_Width = colattrs[i].ca_MinWidth;
497 return;
500 /**************************
501 ** ComputeColLeftRight **
502 **************************/
504 VOID ComputeColLeftRight(UWORD gadleft, struct LVData *data)
506 struct ColumnAttrs *colattrs;
507 register UWORD i;
508 register UWORD left;
510 left = gadleft + LV_BORDERWIDTH_X;
511 colattrs = data->lvd_ColAttrs;
513 ForeachViewedCol(i, data->lvd_ViewedColumns)
515 left += data->lvd_HorSpacing;
517 colattrs[i].ca_Left = left;
518 colattrs[i].ca_Right = (left += colattrs[i].ca_Width);
520 return;
524 /*********************
525 ** DrawListBorder **
526 *********************/
528 VOID DrawListBorder( struct RastPort *rp,
529 UWORD *pens,
530 struct IBox *bbox,
531 BOOL recessed
534 SetAPen (rp, pens[(recessed) ? SHINEPEN : SHADOWPEN]);
536 /* right */
537 RectFill (rp
538 , bbox->Left + bbox->Width - LV_BORDERWIDTH_X
539 , bbox->Top
540 , bbox->Left + bbox->Width - 1
541 , bbox->Top + bbox->Height - 1
544 /* bottom */
545 RectFill (rp
546 , bbox->Left
547 , bbox->Top + bbox->Height - LV_BORDERWIDTH_Y
548 , bbox->Left + bbox->Width - LV_BORDERWIDTH_X
549 , bbox->Top + bbox->Height - 1
552 SetAPen (rp, pens[(recessed) ? SHADOWPEN : SHINEPEN]);
554 /* top */
555 RectFill (rp
556 , bbox->Left
557 , bbox->Top
558 , bbox->Left + bbox->Width - LV_BORDERWIDTH_X
559 , bbox->Top + LV_BORDERWIDTH_Y - 1
562 /* left */
563 RectFill (rp
564 , bbox->Left
565 , bbox->Top
566 , bbox->Left + LV_BORDERWIDTH_X - 1
567 , bbox->Top + bbox->Height - LV_BORDERWIDTH_Y
570 WritePixel (rp, bbox->Left + bbox->Width - 1, bbox->Top);
571 WritePixel (rp, bbox->Left, bbox->Top + bbox->Height - 1);
573 return;
577 /*******************
578 ** ShownEntries **
579 *******************/
580 UWORD ShownEntries(struct LVData *data,
581 struct IBox *container
585 ULONG numentries;
586 UWORD shown;
588 GetAttr(AROSA_List_Entries, data->lvd_List, (IPTR *)&numentries);
590 /* This formula has a little "bug": The height of the rendered texts
591 ** are ibox.Height - height of 2 borders - 1 horizontal spacing line, but
592 ** since hor sp. always is < entryheight, the formula provides the right result
595 shown = (container->Height - LV_BORDERWIDTH_Y * 2) / data->lvd_EntryHeight;
597 shown = MIN(shown, numentries - data->lvd_First);
599 return (shown);
602 /******************
603 ** NotifyAttrs **
604 ******************/
606 VOID NotifyAttrs(Class *cl, Object *o, struct opSet *msg, struct TagItem *tags)
608 struct TagItem idtags[] =
610 {GA_ID, (IPTR)EG(o)->GadgetID},
611 {TAG_MORE, (IPTR)tags}
614 struct opUpdate nmsg = {OM_NOTIFY, idtags, msg->ops_GInfo, 0}, *p_nmsg = &nmsg;
615 struct LVData *data = INST_DATA(cl, o);
617 data->lvd_NotifyCount ++;
618 DoSuperMethodA(cl, o, (Msg)p_nmsg);
619 data->lvd_NotifyCount --;
620 return;