2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
10 #include <proto/graphics.h>
11 #include <proto/intuition.h>
12 #include <proto/utility.h>
14 #include <dos/rdargs.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
28 #include <aros/debug.h>
30 STATIC VOID
HandleSpecialMinWidth( struct ColumnAttrs
*colattrs
,
34 #define ForeachViewedCol(iterator, numcols) \
35 for (iterator = 0; iterator < numcols; iterator ++)
38 /**************************
39 ** ParseFormatString() **
40 **************************/
41 BOOL
ParseFormatString( STRPTR formatstr
,
47 UBYTE templ
[] = "COL=C/N,BAR=B/S,PREPARSE=P/K,DELTA=D/N,MINWIDTH=MIW/N";
51 struct ColumnAttrs
*colattrs
;
53 /* Give ReadArgs() som stack space to chew on so that time is not
54 * wasted on memory allocations
57 #define WORKBUFSIZE 500
58 UBYTE workbuf
[WORKBUFSIZE
];
60 colattrs
= data
->lvd_ColAttrs
;
62 rdarg
= (struct RDArgs
*)AllocDosObject(DOS_RDARGS
, NULL
);
66 BOOL morecolumns
= TRUE
;
69 /* Reset the as-big-as-biggest-text property */
70 data
->lvd_Flags
&= ~LVFLG_SPECIALCOLWIDTH
;
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
!= ',')
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
))
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];
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';;
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
;
157 formatstr
+= len
+ 1;
162 data
->lvd_ViewedColumns
= curcol
;
164 FreeDosObject(DOS_RDARGS
, rdarg
);
170 /********************
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
;
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
,
205 struct gpRender
*msg
,
211 struct AROSP_List_GetEntry getentry_msg
, *p_getentry_msg
= &getentry_msg
;
213 struct IBox container
;
214 struct TextFont
*oldfont
;
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
++)
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
)
255 DoMethod(data
->lvd_List
,
258 AROSV_List_Select_Ask
,
262 erase_this_entry
= TRUE
;
268 if (pos
== activepos
)
270 erase_this_entry
= TRUE
;
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
,
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
);
297 CallHookPkt( data
->lvd_DisplayHook
,
301 ForeachViewedCol(col
, data
->lvd_ViewedColumns
)
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
]),
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
)
325 left
= colattrs
[col
].ca_Left
;
329 left
= colattrs
[col
].ca_Right
- te
.te_Width
;
333 left
= colattrs
[col
].ca_Left
+ ((colattrs
[col
].ca_Width
- te
.te_Width
) >> 1);
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
);
353 /******************************
354 ** HandleSpecialMinWidth() **
355 ******************************/
357 STATIC VOID
HandleSpecialMinWidth( struct ColumnAttrs
*colattrs
,
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
);
382 /* Get the texts for a row in the list */
383 CallHookPkt(data
->lvd_DisplayHook
,
387 ForeachViewedCol(i
, data
->lvd_ViewedColumns
)
389 UWORD idx
= colattrs
[i
].ca_DHIndex
;
391 if (colattrs
[i
].ca_Flags
& CAFLG_SPECIALCOLWIDTH
)
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) */
411 /************************
412 ** ComputeColumnWidts **
413 ************************/
415 VOID
ComputeColumnWidths(UWORD listwidth
,
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;
427 WORD on_each_col
, pixels2divide
;
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
;
470 colattrs
[i
].ca_Width
++;
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
;
484 colattrs
[i
].ca_Width
--;
489 else /* pixels2divide == 0 */
491 ForeachViewedCol(i
, data
->lvd_ViewedColumns
)
493 colattrs
[i
].ca_Width
= colattrs
[i
].ca_MinWidth
;
500 /**************************
501 ** ComputeColLeftRight **
502 **************************/
504 VOID
ComputeColLeftRight(UWORD gadleft
, struct LVData
*data
)
506 struct ColumnAttrs
*colattrs
;
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
);
524 /*********************
526 *********************/
528 VOID
DrawListBorder( struct RastPort
*rp
,
534 SetAPen (rp
, pens
[(recessed
) ? SHINEPEN
: SHADOWPEN
]);
538 , bbox
->Left
+ bbox
->Width
- LV_BORDERWIDTH_X
540 , bbox
->Left
+ bbox
->Width
- 1
541 , bbox
->Top
+ bbox
->Height
- 1
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
]);
558 , bbox
->Left
+ bbox
->Width
- LV_BORDERWIDTH_X
559 , bbox
->Top
+ LV_BORDERWIDTH_Y
- 1
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);
580 UWORD
ShownEntries(struct LVData
*data
,
581 struct IBox
*container
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
);
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
--;