2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
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>
16 #include <dos/rdargs.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
30 #include <aros/debug.h>
32 STATIC VOID
HandleSpecialMinWidth( struct ColumnAttrs
*colattrs
,
36 #define ForeachViewedCol(iterator, numcols) \
37 for (iterator = 0; iterator < numcols; iterator ++)
40 /**************************
41 ** ParseFormatString() **
42 **************************/
43 BOOL
ParseFormatString( STRPTR formatstr
,
49 UBYTE templ
[] = "COL=C/N,BAR=B/S,PREPARSE=P/K,DELTA=D/N,MINWIDTH=MIW/N";
53 struct ColumnAttrs
*colattrs
;
55 /* Give ReadArgs() som stack space to chew on so that time is not
56 * wasted on memory allocations
59 #define WORKBUFSIZE 500
60 UBYTE workbuf
[WORKBUFSIZE
];
62 colattrs
= data
->lvd_ColAttrs
;
64 rdarg
= (struct RDArgs
*)AllocDosObject(DOS_RDARGS
, NULL
);
68 BOOL morecolumns
= TRUE
;
71 /* Reset the as-big-as-biggest-text property */
72 data
->lvd_Flags
&= ~LVFLG_SPECIALCOLWIDTH
;
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
!= ',')
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
))
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];
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';;
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
;
159 formatstr
+= len
+ 1;
164 data
->lvd_ViewedColumns
= curcol
;
166 FreeDosObject(DOS_RDARGS
, rdarg
);
172 /********************
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
;
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
,
207 struct gpRender
*msg
,
213 struct AROSP_List_GetEntry getentry_msg
, *p_getentry_msg
= &getentry_msg
;
215 struct IBox container
;
216 struct TextFont
*oldfont
;
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
++)
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
)
257 DoMethod(data
->lvd_List
,
260 AROSV_List_Select_Ask
,
264 erase_this_entry
= TRUE
;
270 if (pos
== activepos
)
272 erase_this_entry
= TRUE
;
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
,
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
);
299 CallHookPkt( data
->lvd_DisplayHook
,
303 ForeachViewedCol(col
, data
->lvd_ViewedColumns
)
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
]),
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
)
327 left
= colattrs
[col
].ca_Left
;
331 left
= colattrs
[col
].ca_Right
- te
.te_Width
;
335 left
= colattrs
[col
].ca_Left
+ ((colattrs
[col
].ca_Width
- te
.te_Width
) >> 1);
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
);
355 /******************************
356 ** HandleSpecialMinWidth() **
357 ******************************/
359 STATIC VOID
HandleSpecialMinWidth( struct ColumnAttrs
*colattrs
,
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
);
384 /* Get the texts for a row in the list */
385 CallHookPkt(data
->lvd_DisplayHook
,
389 ForeachViewedCol(i
, data
->lvd_ViewedColumns
)
391 UWORD idx
= colattrs
[i
].ca_DHIndex
;
393 if (colattrs
[i
].ca_Flags
& CAFLG_SPECIALCOLWIDTH
)
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) */
413 /************************
414 ** ComputeColumnWidts **
415 ************************/
417 VOID
ComputeColumnWidths(UWORD listwidth
,
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;
429 WORD on_each_col
, pixels2divide
;
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
;
472 colattrs
[i
].ca_Width
++;
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
;
486 colattrs
[i
].ca_Width
--;
491 else /* pixels2divide == 0 */
493 ForeachViewedCol(i
, data
->lvd_ViewedColumns
)
495 colattrs
[i
].ca_Width
= colattrs
[i
].ca_MinWidth
;
502 /**************************
503 ** ComputeColLeftRight **
504 **************************/
506 VOID
ComputeColLeftRight(UWORD gadleft
, struct LVData
*data
)
508 struct ColumnAttrs
*colattrs
;
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
);
526 /*********************
528 *********************/
530 VOID
DrawListBorder( struct RastPort
*rp
,
536 SetAPen (rp
, pens
[(recessed
) ? SHINEPEN
: SHADOWPEN
]);
540 , bbox
->Left
+ bbox
->Width
- LV_BORDERWIDTH_X
542 , bbox
->Left
+ bbox
->Width
- 1
543 , bbox
->Top
+ bbox
->Height
- 1
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
]);
560 , bbox
->Left
+ bbox
->Width
- LV_BORDERWIDTH_X
561 , bbox
->Top
+ LV_BORDERWIDTH_Y
- 1
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);
582 UWORD
ShownEntries(struct LVData
*data
,
583 struct IBox
*container
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
);
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
--;