7 * (C) Copyright 1998 Manuel Lemos.
8 * (C) Copyright 1996-1997 Ian J. Einman.
9 * (C) Copyright 1993-1996 Jaba Development.
10 * (C) Copyright 1993-1996 Jan van den Baard.
11 * All Rights Reserved.
14 * Revision 42.4 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.3 2000/08/17 15:09:18 chodorowski
18 * Fixed compiler warnings.
20 * Revision 42.2 2000/05/15 19:27:01 stegerg
21 * another hundreds of REG() macro replacements in func headers/protos.
23 * Revision 42.1 2000/05/14 23:32:47 stegerg
24 * changed over 200 function headers which all use register
25 * parameters (oh boy ...), because the simple REG() macro
26 * doesn't work with AROS. And there are still hundreds
27 * of headers left to be fixed :(
29 * Many of these functions would also work with stack
30 * params, but since i have fixed every single one
31 * I encountered up to now, I guess will have to do
32 * the same for the rest.
34 * Revision 42.0 2000/05/09 22:09:28 mlemos
35 * Bumped to revision 42.0 before handing BGUI to AROS team
37 * Revision 41.11 2000/05/09 19:54:37 mlemos
38 * Merged with the branch Manuel_Lemos_fixes.
40 * Revision 41.10.2.17 1999/08/08 23:05:11 mlemos
41 * Assured that the list is redrawn when the list font or the default font
43 * Made the entry height be always recomputed every time the list is rendered.
45 * Revision 41.10.2.16 1999/07/28 06:34:32 mlemos
46 * Added rendering damage list after the ScrollRaster() call.
48 * Revision 41.10.2.15 1999/07/18 06:15:42 mlemos
49 * Fixed the problem of very quick drop without dragging.
51 * Revision 41.10.2.14 1999/07/03 15:17:40 mlemos
52 * Replaced the calls to CallHookPkt to BGUI_CallHookPkt.
54 * Revision 41.10.2.13 1999/05/24 20:20:43 mlemos
55 * Added fix for attempt to free BaseInfo handle twice when dragging 10 or
58 * Revision 41.10.2.12 1998/12/20 01:37:42 mlemos
59 * Ensured that the list is fully redrawn when a change like adding a new
60 * entry that makes the list partially invisible, makes the list overhead
62 * Fixed computation of the top overhead area of a list view with title to
63 * include the height of the separator line (2 pixels).
65 * Revision 41.10.2.11 1998/12/07 03:07:03 mlemos
66 * Replaced OpenFont and CloseFont calls by the respective BGUI debug macros.
68 * Revision 41.10.2.10 1998/12/07 00:49:52 mlemos
69 * Fixed range checking bug of new list top entry when the number of visible
70 * entries is larger than the total entries.
72 * Revision 41.10.2.9 1998/12/06 21:38:21 mlemos
73 * Ensured that when the parent view and window are passed to the listview
74 * scroller gadget on its creation or when are set by OM_SET OM_UPDATE.
76 * Revision 41.10.2.8 1998/12/06 21:20:41 mlemos
77 * Ensured that the key activation selects the previous or the next selected
78 * entries in Multi Selection lists.
79 * Ensured that selecting the previous or the next selected entries in Multi
80 * Selection lists always deselects any previously selected entries.
82 * Revision 41.10.2.7 1998/11/28 13:45:17 mlemos
83 * Made the default flag of the list to pre clear the entries.
85 * Revision 41.10.2.6 1998/11/12 16:23:33 mlemos
86 * Passed NULL rastport pointer to AllocBaseInfo in the methods
87 * BASE_DRAGACTIVE, BASE_DRAGINACTIVE and BASE_DRAGUPDATE to ensure that it
88 * legally obtains the Rastport.
90 * Revision 41.10.2.5 1998/10/11 15:28:58 mlemos
91 * Enforced the columns minimum width value.
93 * Revision 41.10.2.4 1998/10/11 14:50:21 mlemos
94 * Fixed the computation of the initial offset of the column bars when the
95 * user starts to drag them.
97 * Revision 41.10.2.3 1998/06/16 01:22:10 mlemos
98 * Passed NULL rastport pointer to AllocBaseInfo in DrawDragLine to ensure
99 * that it legally obtains the Rastport.
101 * Revision 41.10.2.2 1998/06/15 21:48:43 mlemos
102 * Passed NULL rastport pointer to AllocBaseInfo in NewTop to ensure that it
103 * legally obtains the Rastport.
105 * Revision 41.10.2.1 1998/03/01 15:38:05 mlemos
106 * Added support to track BaseInfo memory leaks.
108 * Revision 41.10 1998/02/25 21:12:31 mlemos
111 * Revision 1.1 1998/02/25 17:09:00 mlemos
118 * Incorporates MultiColumnListview by Nick Christie.
119 * New code, but the interface is the same.
122 #include "include/classdefs.h"
125 * Internal entry storage.
127 typedef struct lvEntry
{
128 struct lvEntry
*lve_Next
; /* Next entry. */
129 struct lvEntry
*lve_Prev
; /* Previous entry. */
130 ULONG lve_Flags
; /* See below. */
131 APTR lve_Entry
; /* Entry data. */
134 #define LVEF_SELECTED (1<<0) /* Entry is selected. */
135 #define LVEF_DISABLED (1<<1) /* Entry is disabled. */
136 #define LVEF_HIDDEN (1<<2) /* Entry is hidden. */
137 #define LVEF_REFRESH (1<<31) /* Entry must be redrawn. */
140 LVE
*lvl_First
; /* First entry. */
141 LVE
*lvl_EndMarker
; /* End marker. */
142 LVE
*lvl_Last
; /* Last entry. */
146 UWORD cd_Offset
; /* Left offset of column. */
147 UWORD cd_Width
; /* Width of column. */
148 UWORD cd_MinWidth
; /* Minimum column width. */
149 UWORD cd_MaxWidth
; /* Maximum column width. */
150 UWORD cd_Weight
; /* Relative Weight of column. */
151 ULONG cd_Flags
; /* Column Flags. */
154 #define LVCF_NOSEPARATOR (1<<0) /* No column separator. */
155 #define LVCF_HIDDEN (1<<1) /* Column is not visible. */
156 #define LVCF_DRAGGABLE (1<<2) /* Column is draggable. */
157 #define LVCF_PRECLEAR (1<<3) /* Column is pre-cleared. */
160 * Object instance data.
163 ULONG ld_Flags
; /* See below. */
164 Object
*ld_Prop
; /* Scroller. */
165 BC
*ld_BC
; /* Bounding boxes. */
166 struct IBox ld_ListArea
; /* Area bounds. */
167 LVL ld_Entries
; /* List of entries. */
168 // LVL ld_Hidden; /* Entries filtered out. */
169 LVE
*ld_TopEntry
; /* Top entry. */
170 ULONG ld_ActiveEntry
; /* Active entry number. */
171 LVE
*ld_LastActive
; /* Last active entry. */
172 ULONG ld_LastNum
; /* Last active entry number. */
173 UWORD ld_LastCol
; /* Last active column. */
174 LVE
*ld_LastAdded
; /* Last added entry. */
176 UWORD ld_EntryHeight
; /* Height of a single entry. */
177 UWORD ld_Overhead
; /* View area overhead. */
178 ULONG ld_Top
; /* Top entry visible. */
179 ULONG ld_Total
; /* Number of entries. */
180 LONG ld_Visible
; /* Number of visible entries. */
181 struct Hook
*ld_Resource
; /* Resource hook. */
182 struct Hook
*ld_Display
; /* Display hook. */
183 struct Hook
*ld_Compare
; /* Comparisson hook. */
184 struct Hook
*ld_TitleHook
; /* Title hook. */
185 UBYTE
*ld_Title
; /* Title. */
186 // struct Hook *ld_Filter; /* Filter hook. */
187 struct TextAttr
*ld_ListFont
; /* List font. */
188 struct TextFont
*ld_Font
; /* List font. */
189 APTR ld_MemoryPool
; /* OS 3.0 memory pool. */
190 ULONG ld_MultiStart
; /* Start of multi-(de)select. */
191 UWORD ld_MultiMode
; /* Mode of multi-(de)select. */
192 UWORD ld_MinShown
; /* Min # lines shown. */
193 ULONG ld_Secs
[2]; /* Double-clicks. */
195 ULONG ld_NewPos
; /* New entry position. */
196 APTR ld_ScanEntry
; /* Last scanned entry. */
197 LVE
*ld_ScanNode
; /* And it's node. */
198 ULONG ld_DropSpot
; /* Place where dropped. */
199 ULONG ld_DrawSpot
; /* Place where line drawn. */
200 struct RastPort
*ld_DragRP
; /* Draggable bitmap+rport. */
201 struct RastPort
*ld_LineBuffer
; /* Place for drop line. */
203 UWORD ld_Columns
; /* number of columns, > 0 */
204 UWORD ld_OneColumn
; /* Render only one column. */
205 UWORD ld_DragColumn
; /* column # being dragged, 0...n */
206 WORD ld_DragXLine
; /* current x position of drag line */
207 CD
*ld_CD
; /* Column Descriptors. */
211 #define ld_InnerBox ld_BC->bc_InnerBox
212 #define ld_OuterBox ld_BC->bc_OuterBox
213 #define ld_HitBox ld_BC->bc_HitBox
214 #define ld_Frame ld_BC->bc_Frame
216 #define LDF_READ_ONLY (1 << 0 ) /* Read-only list. */
217 #define LDF_MULTI_SELECT (1 << 1 ) /* Multi-select list. */
218 #define LDF_REFRESH_ALL (1 << 2 ) /* Refresh whole list. */
219 #define LDF_PROPACTIVE (1 << 4 ) /* Prop gadget is active. */
220 #define LDF_LIST_BUSY (1 << 5 ) /* We are busy with the list. */
221 #define LDF_NOSHIFT (1 << 6 ) /* Multi-select without shift */
222 #define LDF_CUSTOMDISABLE (1 << 7 ) /* Display hook renders disabled state. */
223 #define LDF_SHOWDROPSPOT (1 << 8 ) /* Show where we they drop. */
224 #define LDF_DRAGGABLE (1 << 9 ) /* We are in draggable mode. */
225 #define LDF_ALLOW_DRAG (1 << 10) /* Allow column dragging by user */
226 #define LDF_OFFSETS_VALID (1 << 11) /* Column offsets are valid */
227 #define LDF_DRAGGING_COLUMN (1 << 12) /* Currently dragging a column */
228 #define LDF_NEW_COLUMN_POS (1 << 13) /* Set when user releases column */
229 #define LDF_PRE_CLEAR (1 << 14) /* Pre-clear entry rectangle. */
230 #define LDF_THIN_FRAMES (1 << 15) /* 1:1 Aspect ratio frames. */
231 #define LDF_MOVE_DROPBOX (1 << 16) /* Move the dragbox around? */
232 #define LDF_ONE_COLUMN (1 << 17) /* Redraw only one column. */
234 #define LD_ENTRY(tag, offset, flags) PACK_ENTRY(LISTV_TAGSTART, tag, ld_, offset, flags)
235 #define LD_FLAG(tag, flag) PACK_LONGBIT(LISTV_TAGSTART, tag, ld_, ld_Flags, PKCTRL_BIT, flag)
237 static ULONG ListPackTable
[] =
239 PACK_STARTTABLE(LISTV_TAGSTART
),
241 LD_ENTRY(LISTV_MinEntriesShown
, ld_MinShown
, PKCTRL_UWORD
),
242 LD_ENTRY(LISTV_Top
, ld_Top
, PKCTRL_ULONG
),
243 LD_ENTRY(LISTV_Columns
, ld_Columns
, PKCTRL_UWORD
),
245 LD_FLAG(LISTV_ReadOnly
, LDF_READ_ONLY
),
246 LD_FLAG(LISTV_MultiSelect
, LDF_MULTI_SELECT
),
247 LD_FLAG(LISTV_ThinFrames
, LDF_THIN_FRAMES
),
248 LD_FLAG(LISTV_MultiSelectNoShift
, LDF_NOSHIFT
),
249 LD_FLAG(LISTV_ShowDropSpot
, LDF_SHOWDROPSPOT
),
250 LD_FLAG(LISTV_CustomDisable
, LDF_CUSTOMDISABLE
),
251 LD_FLAG(LISTV_DragColumns
, LDF_ALLOW_DRAG
),
252 LD_FLAG(LISTV_PreClear
, LDF_PRE_CLEAR
),
257 #define LC_ENTRY(tag, offset, flags) PACK_ENTRY(LISTC_TAGSTART, tag, cd_, offset, flags)
258 #define LC_FLAG(tag, flag) PACK_LONGBIT(LISTC_TAGSTART, tag, cd_, cd_Flags, PKCTRL_BIT, flag)
260 static ULONG ColumnPackTable
[] =
262 PACK_STARTTABLE(LISTV_TAGSTART
),
264 LC_ENTRY(LISTC_MinWidth
, cd_MinWidth
, PKCTRL_UWORD
),
265 LC_ENTRY(LISTC_MaxWidth
, cd_MaxWidth
, PKCTRL_UWORD
),
266 LC_ENTRY(LISTC_Weight
, cd_Weight
, PKCTRL_UWORD
),
268 LC_FLAG(LISTC_Draggable
, LVCF_DRAGGABLE
),
269 LC_FLAG(LISTC_Hidden
, LVCF_HIDDEN
),
270 LC_FLAG(LISTC_NoSeparator
, LVCF_NOSEPARATOR
),
271 LC_FLAG(LISTC_PreClear
, LVCF_PRECLEAR
),
279 STATIC
struct TagItem PGA2LISTV
[] = {
280 { PGA_Top
, LISTV_Top
, },
284 STATIC VOID
RenderEntry(Object
*obj
, LD
*ld
, struct BaseInfo
*bi
, LVE
*lve
, ULONG top
);
285 #define REL_ZERO (0x80000000)
288 STATIC VOID ASM
ColumnSeparators(REG(a0
) LD
*ld
, REG(a1
) struct BaseInfo
*bi
, REG(d0
) ULONG x
, REG(d1
) ULONG y
, REG(d2
) ULONG h
)
290 int col
, pena
, penb
, x2
, y2
;
292 struct RastPort
*rp
= bi
->bi_RPort
;
294 x2
= x
+ ld
->ld_InnerBox
.Width
- 4;
297 if (ld
->ld_Flags
& LDF_READ_ONLY
)
308 for (col
= 0; col
< ld
->ld_Columns
; col
++)
310 if (!(ld
->ld_CD
[col
].cd_Flags
& LVCF_HIDDEN
))
312 x
+= ld
->ld_CD
[col
].cd_Width
- 2;
314 if (!(ld
->ld_CD
[col
].cd_Flags
& LVCF_NOSEPARATOR
) && (x
< x2
))
328 * Find a node by it's number (slow!).
330 STATIC ASM LVE
*FindNode( REG(a0
) LD
*ld
, REG(d0
) ULONG num
)
338 if ( ! ld
->ld_Entries
.lvl_First
->lve_Next
)
342 * Scan the list top-down to find
345 for ( lve
= ld
->ld_Entries
.lvl_First
; lve
->lve_Next
; lve
= lve
->lve_Next
, lnum
++ ) {
354 * Find a node by it's number (quickly).
356 STATIC ASM LVE
*FindNodeQuick( REG(a0
) LD
*ld
, REG(d0
) ULONG num
)
358 LVE
*lve
= ld
->ld_TopEntry
;
359 ULONG top
= ld
->ld_Top
;
364 if ( ! ld
->ld_Entries
.lvl_First
->lve_Next
)
368 * Scan the list from the current node
369 * to find the correct entry.
372 for ( ; lve
->lve_Next
; lve
= lve
->lve_Next
, top
++ ) {
376 } else if ( num
< top
) {
377 for ( ; lve
->lve_Prev
!= ( LVE
* )&ld
->ld_Entries
; lve
= lve
->lve_Prev
, top
-- ) {
387 * Add an entry in the list. Ugly code with
390 STATIC ASM VOID
AddEntryInList( REG(a0
) LD
*ld
, REG(a1
) Object
*obj
, REG(a2
) LVE
*lve
, REG(d0
) ULONG how
)
393 struct lvCompare lvc
;
398 ld
->ld_LastAdded
= lve
;
401 * Set top entry if not
404 if (!ld
->ld_TopEntry
)
405 ld
->ld_TopEntry
= lve
;
413 if (!ld
->ld_Entries
.lvl_First
->lve_Next
)
415 * No. Simply AddTail the entry.
420 * Scan through the entries.
422 for (tmp
= ld
->ld_Entries
.lvl_Last
; ; tmp
= tmp
->lve_Prev
)
430 * No. Simple string comparrison.
432 if (Stricmp((STRPTR
)lve
->lve_Entry
, (STRPTR
)tmp
->lve_Entry
) >= 0)
437 lvc
.lvc_EntryA
= lve
->lve_Entry
;
438 lvc
.lvc_EntryB
= tmp
->lve_Entry
;
439 if ((LONG
)BGUI_CallHookPkt(ld
->ld_Compare
, (VOID
*)obj
, (VOID
*)&lvc
) >= 0)
445 if (tmp
== ld
->ld_Entries
.lvl_First
)
447 ld
->ld_TopEntry
= lve
;
449 * First entry is AddHead'ed.
455 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
456 Insert((struct List
*)&ld
->ld_Entries
, (struct Node
*)lve
, (struct Node
*)tmp
);
461 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
462 AddHead((struct List
*)&ld
->ld_Entries
, (struct Node
*)lve
);
463 ld
->ld_TopEntry
= lve
;
469 AddTail((struct List
*)&ld
->ld_Entries
, (struct Node
*)lve
);
475 * Add entries to the list.
477 STATIC ASM BOOL
AddEntries(REG(a0
) LD
*ld
, REG(a1
) APTR
*entries
, REG(a2
) Object
*obj
, REG(d0
) ULONG how
, REG(a3
) LVE
*pred
)
480 struct lvResource lvr
;
486 if (!entries
) return FALSE
;
489 * Initialize lvResource structure to make entries.
491 lvr
.lvr_Command
= LVRC_MAKE
;
493 ld
->ld_Flags
|= LDF_LIST_BUSY
;
496 * Loop through the entries.
498 while ((lvr
.lvr_Entry
= *entries
++))
503 if ((lve
= (LVE
*)BGUI_AllocPoolMem(sizeof(LVE
))))
506 * Do we have a resource hook?
511 * Let the hook make the entry.
513 lve
->lve_Entry
= (APTR
)BGUI_CallHookPkt(ld
->ld_Resource
, (void *)obj
, (void *)&lvr
);
518 * Simple string copy.
520 if ((lve
->lve_Entry
= (APTR
)BGUI_AllocPoolMem(strlen((STRPTR
)lvr
.lvr_Entry
) + 1)))
521 strcpy((STRPTR
)lve
->lve_Entry
, (STRPTR
)lvr
.lvr_Entry
);
530 AddEntryInList(ld
, obj
, lve
, how
);
531 if (how
== LVAP_HEAD
)
536 Insert((struct List
*)&ld
->ld_Entries
, (struct Node
*)lve
, (struct Node
*)pred
);
539 ld
->ld_LastAdded
= lve
;
545 BGUI_FreePoolMem(lve
);
549 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
555 * Make an entry visible.
557 STATIC ASM ULONG
MakeVisible(REG(a0
) LD
*ld
, REG(d0
) ULONG entry
)
562 * # of visible items known?
568 * Otherwise adjust the top to
571 if (entry
< ld
->ld_Top
) new_top
= entry
;
572 else if (entry
>= (ld
->ld_Top
+ ld
->ld_Visible
)) new_top
= max((LONG
)(entry
- (ld
->ld_Visible
- 1)), 0);
573 else if (entry
>= ld
->ld_Total
) new_top
= max((LONG
)ld
->ld_Total
- (LONG
)(ld
->ld_Visible
- 1), 0);
574 else new_top
= ld
->ld_Top
;
580 * De-select node list (slow!).
582 STATIC ASM VOID
DeSelect(REG(a0
) LD
*ld
)
586 for (lve
= ld
->ld_Entries
.lvl_First
; lve
->lve_Next
; lve
= lve
->lve_Next
)
588 if (lve
->lve_Flags
& LVEF_SELECTED
)
590 lve
->lve_Flags
&= ~LVEF_SELECTED
;
591 lve
->lve_Flags
|= LVEF_REFRESH
;
597 * Select node list (slow!).
599 STATIC ASM VOID
Select(REG(a0
) LD
*ld
)
603 for ( lve
= ld
->ld_Entries
.lvl_First
; lve
->lve_Next
; lve
= lve
->lve_Next
) {
604 if ( ! ( lve
->lve_Flags
& LVEF_SELECTED
))
605 lve
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
610 * Setup a new top-value.
612 STATIC ASM VOID
NewTop(REG(a0
) LD
*ld
, REG(a1
) struct GadgetInfo
*gi
, REG(a2
) Object
*obj
, REG(d0
) ULONG new_top
)
616 BC
*bc
= BASE_DATA(obj
);
619 * How much do we need to go up?
621 int diff
= new_top
- ld
->ld_Top
;
624 * Gadget info present?
625 * New position different than old one?
633 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
635 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
638 BOOL needs_refresh
=FALSE
;
643 BSetFont(bi
, ld
->ld_Font
);
648 ld
->ld_TopEntry
= FindNodeQuick(ld
, new_top
);
649 ld
->ld_Top
= new_top
;
651 if (diff
<= -ld
->ld_Visible
)
654 * More than a single view?
656 diff
= -ld
->ld_Visible
;
658 else if (diff
>= +ld
->ld_Visible
)
661 * More than a single view?
663 diff
= +ld
->ld_Visible
;
668 * Scroll view 'diff' lines.
670 ScrollRaster(bi
->bi_RPort
, 0, diff
* ld
->ld_EntryHeight
,
671 ld
->ld_ListArea
.Left
, ld
->ld_ListArea
.Top
,
672 ld
->ld_ListArea
.Left
+ ld
->ld_ListArea
.Width
- 1,
673 ld
->ld_ListArea
.Top
+ ld
->ld_ListArea
.Height
- 1);
674 needs_refresh
=(bi
->bi_RPort
->Layer
->Flags
& LAYERREFRESH
);
677 ColumnSeparators(ld
, bi
, bc
->bc_InnerBox
.Left
, bc
->bc_InnerBox
.Top
, bc
->bc_InnerBox
.Height
);
680 * Re-render first 'diff' lines.
689 new_top
+= ld
->ld_Visible
- diff
;
694 RenderEntry(obj
, ld
, bi
, FindNodeQuick(ld
, new_top
), new_top
- ld
->ld_Top
);
707 if(!(update
=BeginUpdate(gi
->gi_Layer
)))
708 EndUpdate(gi
->gi_Layer
,FALSE
);
709 DoRenderMethod( obj
, gi
, GREDRAW_REDRAW
);
711 EndUpdate(gi
->gi_Layer
,TRUE
);
715 * Needed by RenderEntry().
717 ld
->ld_Flags
&= ~LDF_REFRESH_ALL
;
722 ld
->ld_TopEntry
= FindNodeQuick(ld
, new_top
);
723 ld
->ld_Top
= new_top
;
729 /************************************************************************
730 ********************** MCLV_GETCOLUMNPOSITIONS() **********************
731 *************************************************************************
732 * Work out the left offset (relative to listview view area) of each
733 * column separator. Put the results in ld_Offsets array, starting
734 * with the first separator (ie. the left offset of the *second* column
735 * from the left). Returns TRUE or FALSE to indicate success. Currently
736 * this can only fail if the object is not displayed when this function
737 * is called. If all goes well, LDF_OFFSETS_VALID is set to TRUE.
739 *************************************************************************/
741 STATIC BOOL
GetColumnPositions(Object
*obj
, LD
*ld
)
744 int totalwidth
, columnwidth
, totalweight
, lastwidth
;
745 int listwidth
= ld
->ld_ListArea
.Width
;
746 CD
*cd
, *fcd
= ld
->ld_CD
, *lcd
= fcd
+ ld
->ld_Columns
- 1;
749 * Start widths at minimum and compute width of all columns.
752 for (cd
= fcd
; cd
<= lcd
; ++cd
)
754 cd
->cd_Width
= cd
->cd_MinWidth
;
755 columnwidth
+= cd
->cd_Width
;
759 * Cycle through until all extra space is used.
761 while (columnwidth
< listwidth
)
763 lastwidth
= columnwidth
;
764 totalwidth
= listwidth
;
766 for (cd
= fcd
; cd
<= lcd
; ++cd
)
768 if (!(cd
->cd_Flags
& LVCF_HIDDEN
))
770 if (cd
->cd_Width
< cd
->cd_MaxWidth
)
772 totalweight
+= cd
->cd_Weight
;
776 cd
->cd_Width
= cd
->cd_MaxWidth
;
777 totalwidth
-= cd
->cd_Width
;
782 if (totalweight
== 0) break;
784 for (cd
= fcd
; cd
<= lcd
; ++cd
)
786 if (!(cd
->cd_Flags
& LVCF_HIDDEN
))
788 if (cd
->cd_Width
< cd
->cd_MaxWidth
)
790 w
= (cd
->cd_Weight
* totalwidth
) / totalweight
;
791 if (w
> cd
->cd_MaxWidth
) w
= cd
->cd_MaxWidth
;
792 if (w
< cd
->cd_MinWidth
) w
= cd
->cd_MinWidth
;
794 dw
= w
- cd
->cd_Width
;
795 if (dw
> listwidth
- columnwidth
)
797 dw
= listwidth
- columnwidth
;
807 if (columnwidth
== lastwidth
) break;
811 for (cd
= fcd
; cd
<= lcd
; ++cd
)
813 if (!(cd
->cd_Flags
& LVCF_HIDDEN
))
819 cd
->cd_Offset
= x
; // Last "dummy" column needs right offset of list.
821 ld
->ld_Flags
|= LDF_OFFSETS_VALID
|LDF_REFRESH_ALL
;
826 /************************************************************************
827 ************************* MCLV_DRAWDRAGLINE() *************************
828 *************************************************************************
829 * Draw, using complement mode, the line that shows the user the position
830 * s/he has dragged the column separator to within the mclv.
832 *************************************************************************/
834 STATIC ASM VOID
DrawDragLine(REG(a0
) LD
*ld
, REG(a1
) struct GadgetInfo
*gi
)
836 WORD x1
= ld
->ld_InnerBox
.Left
+ ld
->ld_DragXLine
- 2;
838 WORD y1
= ld
->ld_InnerBox
.Top
;
839 WORD y2
= ld
->ld_InnerBox
.Top
+ ld
->ld_InnerBox
.Height
- 1;
844 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
846 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
849 BSetDrMd(bi
, COMPLEMENT
);
850 BRectFill(bi
, x1
, y1
, x2
, y2
);
857 * Create a new object.
859 METHOD(ListClassNew
, struct opSet
*, ops
)
863 ULONG sort
= LVAP_TAIL
;
864 struct TagItem
*tags
, *tag
;
865 struct TagItem
*tstate
;
866 ULONG
*new_weights
= NULL
;
867 APTR
*new_entries
= NULL
;
870 tags
= DefTagList(BGUI_LISTVIEW_GADGET
, ops
->ops_AttrList
);
873 * Let the superclass make the object.
875 if ((rc
= NewSuperObject(cl
, obj
, tags
)))
878 * Get the instance data.
880 ld
= INST_DATA(cl
, rc
);
881 ld
->ld_BC
= BASE_DATA(rc
);
883 ld
->ld_Flags
= LDF_REFRESH_ALL
|LDF_PRE_CLEAR
;
886 ld
->ld_Prop
= (Object
*)~0;
889 * Initialize the list of entries.
891 NewList((struct List
*)&ld
->ld_Entries
);
892 // NewList((struct List *)&ld->ld_Hidden);
894 BGUI_PackStructureTags((APTR
)ld
, ListPackTable
, tags
);
898 while ((tag
= NextTagItem(&tstate
)))
903 case LISTV_EntryArray
:
904 new_entries
= (APTR
*)data
;
907 case LISTV_SortEntryArray
:
911 case LISTV_ColumnWeights
:
912 new_weights
= (ULONG
*)data
;
915 case LISTV_PropObject
:
916 ld
->ld_Prop
= (Object
*)data
;
920 ld
->ld_ListFont
= (struct TextAttr
*)data
;
924 ld
->ld_Title
= (UBYTE
*)data
;
927 case LISTV_TitleHook
:
928 ld
->ld_TitleHook
= (struct Hook
*)data
;
931 case LISTV_CompareHook
:
932 ld
->ld_Compare
= (struct Hook
*)data
;
935 case LISTV_DisplayHook
:
936 ld
->ld_Display
= (struct Hook
*)data
;
939 case LISTV_ResourceHook
:
940 ld
->ld_Resource
= (struct Hook
*)data
;
945 if (ld
->ld_Columns
< 1) ld
->ld_Columns
= 1;
947 ld
->ld_CD
= BGUI_AllocPoolMem((ld
->ld_Columns
+ 1) * sizeof(CD
));
950 * Verify array allocated.
954 for (i
= 0; i
<= ld
->ld_Columns
; i
++)
956 ld
->ld_CD
[i
].cd_MinWidth
= 24;
957 ld
->ld_CD
[i
].cd_MaxWidth
= 0xFFFF;
958 ld
->ld_CD
[i
].cd_Weight
= new_weights
? (new_weights
[i
] ? new_weights
[i
] : 1) : DEFAULT_WEIGHT
;
961 if (ld
->ld_Prop
== (Object
*)~0)
964 * Filter out frame and label attributes.
968 while ((tag
= NextTagItem(&tstate
)))
973 * Don't disable prop!
977 * No drag'n'drop on the prop.
981 tag
->ti_Tag
= TAG_IGNORE
;
985 if (FRM_TAG(tag
->ti_Tag
) || LAB_TAG(tag
->ti_Tag
))
986 tag
->ti_Tag
= TAG_IGNORE
;
994 ld
->ld_Prop
= BGUI_NewObject(BGUI_PROP_GADGET
, GA_ID
, GADGET(rc
)->GadgetID
,
995 PGA_DontTarget
, TRUE
, BT_ParentView
, ld
->ld_BC
->bc_View
, BT_ParentWindow
, ld
->ld_BC
->bc_Window
,TAG_MORE
, tags
);
1001 * Setup scroller notification.
1003 AsmDoMethod(ld
->ld_Prop
, BASE_ADDMAP
, rc
, PGA2LISTV
);
1009 * Set frame attributes to match list attributes.
1011 DoSetMethodNG(ld
->ld_Frame
, FRM_Recessed
, ld
->ld_Flags
& LDF_READ_ONLY
,
1012 FRM_ThinFrame
, ld
->ld_Flags
& LDF_THIN_FRAMES
,
1019 AddEntries(ld
, new_entries
, (Object
*)rc
, sort
, NULL
);
1023 AsmCoerceMethod(cl
, (Object
*)rc
, OM_DISPOSE
);
1033 /// OM_SET, OM_UPDATE
1035 * Set or update some attributes.
1037 METHOD(ListClassSetUpdate
, struct opUpdate
*, opu
)
1039 LD
*ld
= INST_DATA( cl
, obj
);
1040 struct TagItem
*tstate
= opu
->opu_AttrList
;
1041 struct TagItem
*tag
;
1044 ULONG otop
= ld
->ld_Top
, ntop
= otop
, num
, oldcol
= ld
->ld_Columns
;
1045 WORD dis
= GADGET(obj
)->Flags
& GFLG_DISABLED
;
1052 * First the superclass...
1054 AsmDoSuperMethodA(cl
, obj
, (Msg
)opu
);
1056 BGUI_PackStructureTags((APTR
)ld
, ListPackTable
, opu
->opu_AttrList
);
1059 * Scan for known attributes.
1061 while ((tag
= NextTagItem(&tstate
)))
1063 data
= tag
->ti_Data
;
1064 switch (tag
->ti_Tag
)
1067 ld
->ld_Title
= (UBYTE
*)data
;
1070 case LISTV_TitleHook
:
1071 ld
->ld_TitleHook
= (struct Hook
*)data
;
1074 case LISTV_CompareHook
:
1075 ld
->ld_Compare
= (struct Hook
*)data
;
1078 case LISTV_DisplayHook
:
1079 ld
->ld_Display
= (struct Hook
*)data
;
1082 case LISTV_ResourceHook
:
1083 ld
->ld_Resource
= (struct Hook
*)data
;
1086 case LISTV_PropObject
:
1087 if (ld
->ld_Prop
) DisposeObject(ld
->ld_Prop
);
1088 ld
->ld_Flags
&= ~LDF_PROPACTIVE
;
1090 if ((ld
->ld_Prop
= (Object
*)data
))
1093 * Setup scroller notification.
1095 AsmDoMethod(ld
->ld_Prop
, BASE_ADDMAP
, obj
, PGA2LISTV
);
1102 * Set frame thickness.
1104 if (ld
->ld_Frame
) DoSetMethodNG(ld
->ld_Frame
, FRM_ThinFrame
, data
, TAG_END
);
1105 if (ld
->ld_Prop
) DoSetMethodNG(ld
->ld_Prop
, FRM_ThinFrame
, data
, TAG_END
);
1110 * Pickup superclass font.
1114 BGUI_CloseFont(ld
->ld_Font
);
1120 case LISTV_ListFont
:
1121 ld
->ld_ListFont
= (struct TextAttr
*)data
;
1124 BGUI_CloseFont(ld
->ld_Font
);
1131 ld
->ld_Top
= otop
; // Needed to circumvent PackStructureTags.
1133 * Make sure we stay in range.
1135 ntop
= range(data
, 0, (ld
->ld_Total
> ld
->ld_Visible
) ? ld
->ld_Total
- ld
->ld_Visible
: 0);
1138 case LISTV_MakeVisible
:
1142 if ((num
= data
) >= ld
->ld_Total
)
1143 num
= ld
->ld_Total
- 1;
1148 ntop
= MakeVisible( ld
, num
);
1152 case LISTV_DeSelect
:
1154 * Get the node number.
1156 if (( num
= data
) == ~0 ) {
1158 * A value of -1 means deselect
1167 num
= num
>= ld
->ld_Total
? ld
->ld_Total
- 1 : num
;
1170 * Find the node to deselect.
1172 if (( lve
= FindNodeQuick( ld
, num
))) {
1176 ld
->ld_LastActive
= lve
;
1177 ld
->ld_LastNum
= num
;
1180 * Already unselected?
1182 if (( lve
->lve_Flags
& LVEF_SELECTED
) && ( ! ( ld
->ld_Flags
& LDF_READ_ONLY
))) {
1184 * Mark it for a refresh.
1186 lve
->lve_Flags
&= ~LVEF_SELECTED
;
1187 lve
->lve_Flags
|= LVEF_REFRESH
;
1192 DoNotifyMethod( obj
, opu
->opu_GInfo
, opu
->MethodID
== OM_UPDATE
? opu
->opu_Flags
: 0L, GA_ID
, GADGET( obj
)->GadgetID
, LISTV_Entry
, lve
->lve_Entry
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
1199 case LISTV_SelectMulti
:
1200 case LISTV_SelectMultiNotVisible
:
1202 * Must be a multi-select object.
1204 if ( ! ( ld
->ld_Flags
& LDF_MULTI_SELECT
))
1210 if (data
== LISTV_Select_All
)
1220 case LISTV_SelectNotVisible
:
1226 case LISTV_Select_First
:
1230 case LISTV_Select_Last
:
1231 num
= ld
->ld_Total
- 1;
1234 case LISTV_Select_Next
:
1235 if (!ld
->ld_LastActive
) num
= ld
->ld_Top
;
1236 else num
= ld
->ld_LastNum
+ 1;
1239 case LISTV_Select_Previous
:
1240 if (!ld
->ld_LastActive
) num
= ld
->ld_Top
;
1241 else num
= max((LONG
)ld
->ld_LastNum
- 1, 0);
1244 case LISTV_Select_Top
:
1248 case LISTV_Select_Page_Up
:
1249 if (!ld
->ld_LastActive
) num
= ld
->ld_Top
;
1252 num
= ld
->ld_LastNum
;
1253 if (num
> ld
->ld_Top
) num
= ld
->ld_Top
;
1254 else num
= max((LONG
)(num
- ld
->ld_Visible
+ 1), 0);
1258 case LISTV_Select_Page_Down
:
1259 if (!ld
->ld_LastActive
) num
= ld
->ld_Top
;
1262 num
= ld
->ld_LastNum
;
1263 if (num
< (ld
->ld_Top
+ ld
->ld_Visible
- 1)) num
= ld
->ld_Top
+ ld
->ld_Visible
- 1;
1264 else num
= min((LONG
)(num
+ (ld
->ld_Visible
- 1)), ld
->ld_Total
- 1);
1274 * Make sure we stay in range.
1276 num
= (num
>= ld
->ld_Total
) ? ld
->ld_Total
- 1 : num
;
1279 * Find the node to select.
1281 if ((lve
= ld
->ld_LastActive
= FindNodeQuick(ld
, num
)))
1284 * Setup the number as the last
1287 ld
->ld_LastNum
= num
;
1292 if (((( tag
->ti_Tag
!= LISTV_SelectMulti
) && ( tag
->ti_Tag
!= LISTV_SelectMultiNotVisible
)) || ! ( lve
->lve_Flags
& LVEF_SELECTED
)) && ( ! ( ld
->ld_Flags
& LDF_READ_ONLY
))) {
1294 * No? DeSelect all other labels if we are not
1297 if (( tag
->ti_Tag
!= LISTV_SelectMulti
) && ( tag
->ti_Tag
!= LISTV_SelectMultiNotVisible
))
1301 * Mark this entry as selected.
1303 lve
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
1308 DoNotifyMethod( obj
, opu
->opu_GInfo
, opu
->MethodID
== OM_UPDATE
? opu
->opu_Flags
: 0L, GA_ID
, GADGET( obj
)->GadgetID
, LISTV_Entry
, lve
->lve_Entry
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
1312 * Make the entry visible if requested.
1314 if (( tag
->ti_Tag
!= LISTV_SelectNotVisible
) && ( tag
->ti_Tag
!= LISTV_SelectMultiNotVisible
))
1315 ntop
= MakeVisible( ld
, num
);
1321 case LISTV_ColumnWeights
:
1322 if (!(ld
->ld_Flags
& LDF_DRAGGING_COLUMN
))
1324 new_weights
= (ULONG
*)data
;
1325 for (i
= 0; i
< ld
->ld_Columns
; i
++)
1327 ld
->ld_CD
[i
].cd_Weight
= new_weights
? (new_weights
[i
] ? new_weights
[i
] : 1) : DEFAULT_WEIGHT
;
1329 ld
->ld_Flags
&= ~LDF_OFFSETS_VALID
;
1335 ld
->ld_Columns
= oldcol
; // can't change yet
1338 case BT_ParentWindow
:
1340 DoSetMethodNG(ld
->ld_Prop
, tag
->ti_Tag
, data
, TAG_DONE
);
1346 * Disabled state changed?
1348 if ((GADGET(obj
)->Flags
& GFLG_DISABLED
) != dis
)
1350 if ( opu
->opu_GInfo
) {
1351 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
1352 DoRenderMethod( obj
, opu
->opu_GInfo
, GREDRAW_REDRAW
);
1358 * Top value changed?
1362 DoRenderMethod(obj
, opu
->opu_GInfo
, GREDRAW_UPDATE
);
1365 NewTop(ld
, opu
->opu_GInfo
, obj
, ntop
);
1366 if (ld
->ld_Prop
) DoSetMethod(ld
->ld_Prop
, opu
->opu_GInfo
, PGA_Top
, ntop
, TAG_DONE
);
1369 else if (ntop
!= otop
)
1371 if (!FindTagItem(GA_ID
, opu
->opu_AttrList
))
1372 if (ld
->ld_Prop
) DoSetMethod(ld
->ld_Prop
, opu
->opu_GInfo
, PGA_Top
, ntop
, TAG_END
);
1373 NewTop(ld
, opu
->opu_GInfo
, obj
, ntop
);
1382 * They want to know something.
1384 METHOD(ListClassGet
, struct opGet
*, opg
)
1386 LD
*ld
= INST_DATA( cl
, obj
);
1387 ULONG rc
= TRUE
, num
= ~0;
1388 Tag tag
= opg
->opg_AttrID
;
1389 IPTR
*store
= opg
->opg_Storage
;
1393 case LISTV_LastClicked
:
1394 if (ld
->ld_LastActive
) STORE ld
->ld_LastActive
->lve_Entry
;
1398 case LISTV_LastClickedNum
:
1399 if (ld
->ld_LastActive
)
1400 num
= ld
->ld_LastNum
;
1404 case LISTV_NumEntries
:
1408 case LISTV_DropSpot
:
1409 STORE ld
->ld_DropSpot
;
1412 case LISTV_NewPosition
:
1413 STORE ld
->ld_NewPos
;
1416 case LISTV_ViewBounds
:
1417 STORE
&ld
->ld_InnerBox
;
1420 case LISTV_LastColumn
:
1421 STORE ld
->ld_LastCol
;
1424 case LISTV_PropObject
:
1428 case LISTV_ListFont
:
1429 STORE ld
->ld_ListFont
;
1436 case LISTV_TitleHook
:
1437 STORE ld
->ld_TitleHook
;
1440 case LISTV_CompareHook
:
1441 STORE ld
->ld_Compare
;
1444 case LISTV_DisplayHook
:
1445 STORE ld
->ld_Display
;
1448 case LISTV_ResourceHook
:
1449 STORE ld
->ld_Resource
;
1453 rc
= BGUI_UnpackStructureTag((UBYTE
*)ld
, ListPackTable
, tag
, store
);
1454 if (!rc
) rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)opg
);
1463 * Dispose of the object.
1465 METHOD(ListClassDispose
, Msg
, msg
)
1467 LD
*ld
= INST_DATA(cl
, obj
);
1469 struct lvResource lvr
;
1474 while ((lve
= (LVE
*)RemHead((struct List
*)&ld
->ld_Entries
)))
1477 * Do we have a resource hook?
1479 if (ld
->ld_Resource
)
1482 * Initialize lvResource structure to kill the entry.
1484 lvr
.lvr_Command
= LVRC_KILL
;
1485 lvr
.lvr_Entry
= lve
->lve_Entry
;
1490 BGUI_CallHookPkt(ld
->ld_Resource
, (VOID
*)obj
, (VOID
*)&lvr
);
1495 * Simple deallocation.
1497 BGUI_FreePoolMem(lve
->lve_Entry
);
1501 * Free the entry node.
1503 BGUI_FreePoolMem(lve
);
1507 * Kill the scroller.
1509 if (ld
->ld_Prop
) AsmDoMethod(ld
->ld_Prop
, OM_DISPOSE
);
1511 if (ld
->ld_CD
) BGUI_FreePoolMem(ld
->ld_CD
);
1513 if (ld
->ld_Font
) BGUI_CloseFont(ld
->ld_Font
);
1516 * The superclass takes care of the rest.
1518 return AsmDoSuperMethodA(cl
, obj
, msg
);
1525 * Setup the list area bounds.
1527 STATIC ASM VOID
ListAreaBounds(REG(a0
) Object
*obj
, REG(a1
) LD
*ld
)
1529 int fh
= ld
->ld_EntryHeight
;
1532 if (ld
->ld_ListArea
.Width
!= ld
->ld_InnerBox
.Width
)
1533 ld
->ld_Flags
&= ~LDF_OFFSETS_VALID
;
1536 * Setup list display area and view bounds.
1538 ld
->ld_ListArea
= ld
->ld_InnerBox
;
1543 if (ld
->ld_Title
|| ld
->ld_TitleHook
)
1545 ld
->ld_ListArea
.Top
+= (fh
+ 2);
1546 ld
->ld_ListArea
.Height
-= (fh
+ 2);
1550 * Setup the amount of visible entries
1551 * and the amount of pixels to adjust.
1553 ld
->ld_Visible
= ld
->ld_ListArea
.Height
/ fh
;
1554 overhead
= ld
->ld_ListArea
.Height
% fh
;
1557 * If the list area is larger than the
1558 * total amount of entries we set overhead
1561 if (ld
->ld_Total
<= ld
->ld_Visible
)
1567 ld
->ld_ListArea
.Top
+= overhead
/ 2;
1568 ld
->ld_ListArea
.Height
-= overhead
;
1572 * Any change in the overhead?
1574 if (overhead
!= ld
->ld_Overhead
)
1576 ld
->ld_Overhead
= overhead
;
1577 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
1581 * Recompute the columns.
1583 if (!(ld
->ld_Flags
& LDF_OFFSETS_VALID
))
1584 GetColumnPositions(obj
, ld
);
1587 * Check top setting.
1589 ld
->ld_Top
= max(0, min(ld
->ld_Top
, ld
->ld_Total
- ld
->ld_Visible
));
1594 ld
->ld_TopEntry
= FindNode(ld
, ld
->ld_Top
);
1600 STATIC ASM SAVEDS VOID
RenderColumn(REG(a0
) char *text
, REG(a2
) Object
*obj
, REG(a1
) struct lvRender
*lvr
)
1602 int col
= lvr
->lvr_Column
;
1603 struct BaseInfo
*bi
;
1608 * Setup rendering area.
1610 area
.Left
= lvr
->lvr_Bounds
.MinX
+ 2;
1611 area
.Width
= lvr
->lvr_Bounds
.MaxX
- lvr
->lvr_Bounds
.MinX
- 3;
1612 area
.Top
= lvr
->lvr_Bounds
.MinY
;
1613 area
.Height
= lvr
->lvr_Bounds
.MaxY
- lvr
->lvr_Bounds
.MinY
+ 1;
1615 if (strchr(text
, '\t'))
1619 text
= strchr(text
, '\t');
1625 term
= strchr(text
, '\t');
1626 if (term
) *term
= 0;
1631 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_DrawInfo
, lvr
->lvr_DrawInfo
, BI_RastPort
, lvr
->lvr_RPort
, TAG_DONE
)))
1633 if ((bi
= AllocBaseInfo(BI_DrawInfo
, lvr
->lvr_DrawInfo
, BI_RastPort
, lvr
->lvr_RPort
, TAG_DONE
)))
1641 RenderText(bi
, text
, &area
);
1642 if (term
) *term
= '\t';
1645 if (GADGET(obj
)->Flags
& GFLG_DISABLED
)
1652 BDisableBox(bi
, &area
);
1660 * Render a single entry.
1662 STATIC VOID
RenderEntry(Object
*obj
, LD
*ld
, struct BaseInfo
*bi
, LVE
*lve
, ULONG top
)
1664 BC
*bc
= BASE_DATA(obj
);
1665 struct lvRender lvr
;
1668 int cx
, cw
, xoff
, yoff
;
1671 struct RastPort
*rp
= bi
->bi_RPort
;
1680 xoff
= ld
->ld_ListArea
.Left
;
1681 yoff
= ld
->ld_ListArea
.Top
;
1685 * Initialize the lvRender structure.
1688 lvr
.lvr_DrawInfo
= bi
->bi_DrInfo
;
1692 sel
= lve
->lve_Flags
& LVEF_SELECTED
;
1693 hook
= ld
->ld_Display
;
1695 lvr
.lvr_Entry
= lve
->lve_Entry
;
1696 lvr
.lvr_Bounds
.MinY
= yoff
+ ld
->ld_EntryHeight
* top
;
1697 lvr
.lvr_Bounds
.MaxY
= lvr
.lvr_Bounds
.MinY
+ ld
->ld_EntryHeight
- 1;
1702 * A NULL entry means render the title.
1705 hook
= ld
->ld_TitleHook
;
1707 lvr
.lvr_Entry
= ld
->ld_Title
;
1708 lvr
.lvr_Bounds
.MinY
= bc
->bc_InnerBox
.Top
;
1709 lvr
.lvr_Bounds
.MaxY
= bc
->bc_InnerBox
.Top
+ ld
->ld_EntryHeight
- 1;
1713 * Setup state information.
1715 if (GADGET(obj
)->Flags
& GFLG_DISABLED
)
1716 lvr
.lvr_State
= sel
? LVRS_SELECTED_DISABLED
: LVRS_NORMAL_DISABLED
;
1718 lvr
.lvr_State
= sel
? LVRS_SELECTED
: LVRS_NORMAL
;
1720 for (col
= 0, cx
= xoff
; col
< ld
->ld_Columns
; col
++)
1722 if (!(ld
->ld_CD
[col
].cd_Flags
& LVCF_HIDDEN
))
1724 cw
= ld
->ld_CD
[col
].cd_Width
;
1726 lvr
.lvr_Bounds
.MinX
= cx
;
1727 lvr
.lvr_Bounds
.MaxX
= cx
+ cw
- ((col
< (ld
->ld_Columns
- 1)) ? 3 : 1);
1728 lvr
.lvr_Column
= col
;
1732 if (!(ld
->ld_Flags
& LDF_ONE_COLUMN
) || (col
== ld
->ld_OneColumn
))
1735 * Do we have a display hook?
1739 clear
= (ld
->ld_Flags
& LDF_PRE_CLEAR
) || (ld
->ld_CD
[col
].cd_Flags
& LVCF_PRECLEAR
);
1743 AsmDoMethod(ld
->ld_Frame
, FRAMEM_BACKFILL
, bi
, &lvr
.lvr_Bounds
, sel
? IDS_SELECTED
: IDS_NORMAL
);
1749 txt
= (UBYTE
*)BGUI_CallHookPkt(hook
, (void *)obj
, (void *)&lvr
);
1754 * Pick up the entry text.
1757 txt
= lvr
.lvr_Entry
;
1763 AsmDoMethod(ld
->ld_Frame
, FRAMEM_BACKFILL
, bi
, &lvr
.lvr_Bounds
, sel
? IDS_SELECTED
: IDS_NORMAL
);
1765 BSetDPenA(bi
, sel
? FILLTEXTPEN
: TEXTPEN
);
1766 RenderColumn(txt
, obj
, &lvr
);
1774 if (lve
) lve
->lve_Flags
&= ~LVEF_REFRESH
;
1781 METHOD(ListClassLayout
, struct bmLayout
*, bml
)
1783 LD
*ld
= INST_DATA(cl
, obj
);
1784 BC
*bc
= BASE_DATA(obj
);
1785 struct TextAttr
*lf
;
1791 lf
= ld
->ld_ListFont
? ld
->ld_ListFont
: bc
->bc_TextAttr
;
1794 sw
= max((lf
->ta_YSize
* 2) / 3, 16);
1803 bml
->bml_Bounds
->Width
-= sw
;
1807 * First the superclass.
1809 rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)bml
);
1811 if (sw
) bml
->bml_Bounds
->Width
+= sw
;
1821 METHOD(ListClassRender
, struct bmRender
*, bmr
)
1823 LD
*ld
= INST_DATA(cl
, obj
);
1824 BC
*bc
= BASE_DATA(obj
);
1825 struct BaseInfo
*bi
= bmr
->bmr_BInfo
;
1826 struct RastPort
*rp
= bi
->bi_RPort
;
1827 struct TextFont
*tf
= ld
->ld_Font
, *of
;
1828 struct TextAttr
*lf
= ld
->ld_ListFont
;
1829 struct Rectangle rect
;
1836 * Render the baseclass.
1838 AsmDoSuperMethodA(cl
, obj
, (Msg
)bmr
);
1840 if (!lf
) lf
= bc
->bc_TextAttr
;
1842 sw
= lf
? ((lf
->ta_YSize
* 2) / 3) : 0;
1843 if (sw
< 16) sw
= 16;
1853 if ((tf
= BGUI_OpenFont(lf
)))
1870 * Setup entry height always even.
1872 ld
->ld_EntryHeight
= (tf
->tf_YSize
+ 1) & (ULONG
)~1;
1874 overhead
=ld
->ld_Overhead
;
1877 * Setup the list area bounds.
1879 ListAreaBounds(obj
, ld
);
1881 x
= bc
->bc_InnerBox
.Left
;
1882 w
= bc
->bc_InnerBox
.Width
;
1887 if (overhead
<ld
->ld_Overhead
1888 || bmr
->bmr_Flags
== GREDRAW_REDRAW
)
1890 if(overhead
<ld
->ld_Overhead
)
1891 overhead
=ld
->ld_Overhead
;
1894 * Clear the overhead.
1896 if ((h
= overhead
>> 1))
1898 y
= bc
->bc_InnerBox
.Top
;
1899 if (ld
->ld_Title
|| ld
->ld_TitleHook
) y
+= ld
->ld_EntryHeight
+2;
1901 rect
.MinX
= x
; rect
.MaxX
= x
+ w
- 1;
1902 rect
.MinY
= y
; rect
.MaxY
= y
+ h
- 1;
1904 AsmDoMethod(bc
->bc_Frame
, FRAMEM_BACKFILL
, bi
, &rect
, IDS_NORMAL
);
1907 if ((h
= overhead
- h
))
1909 y
= bc
->bc_InnerBox
.Top
+ bc
->bc_InnerBox
.Height
- h
;
1911 rect
.MinX
= x
; rect
.MaxX
= x
+ w
- 1;
1912 rect
.MinY
= y
; rect
.MaxY
= y
+ h
- 1;
1914 AsmDoMethod(bc
->bc_Frame
, FRAMEM_BACKFILL
, bi
, &rect
, IDS_NORMAL
);
1918 * Draw the separators.
1920 ColumnSeparators(ld
, bi
, bc
->bc_InnerBox
.Left
, bc
->bc_InnerBox
.Top
, bc
->bc_InnerBox
.Height
);
1923 * If we have a title render it.
1925 if (ld
->ld_Title
|| ld
->ld_TitleHook
)
1928 * Just in case the font changed.
1930 if (tf
) BSetFont(bi
, tf
);
1932 RenderEntry(obj
, ld
, bi
, NULL
, 0);
1934 if (ld
->ld_Columns
> 1)
1936 y
= bc
->bc_InnerBox
.Top
+ ld
->ld_EntryHeight
;
1937 BSetDPenA(bi
, ld
->ld_Flags
& LDF_READ_ONLY
? SHINEPEN
: SHADOWPEN
);
1938 HLine(rp
, x
, y
++, x
+ w
- 1);
1939 BSetDPenA(bi
, ld
->ld_Flags
& LDF_READ_ONLY
? SHADOWPEN
: SHINEPEN
);
1940 HLine(rp
, x
, y
, x
+ w
- 1);
1947 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
1951 * Just in case the font changed.
1953 if (tf
) BSetFont(bi
, tf
);
1956 * Loop through the entries.
1958 for (num
= ld
->ld_Top
, a
= 0; (a
< ld
->ld_Visible
) && (num
< ld
->ld_Total
); num
++, a
++)
1963 if ((lve
= FindNodeQuick(ld
, num
)))
1966 * Only render when necessary.
1968 if ((ld
->ld_Flags
& LDF_REFRESH_ALL
) || (lve
->lve_Flags
& LVEF_REFRESH
))
1970 RenderEntry(obj
, ld
, bi
, lve
, a
);
1978 if ((!(ld
->ld_Flags
& LDF_CUSTOMDISABLE
)) && ld
->ld_Display
)
1980 if (GADGET(obj
)->Flags
& GFLG_DISABLED
)
1982 BDisableBox(bi
, &bc
->bc_HitBox
);
1989 ld
->ld_Flags
&= ~LDF_REFRESH_ALL
;
1999 * Setup scroller bounds.
2001 GADGETBOX(ld
->ld_Prop
)->Left
= ld
->ld_HitBox
.Left
+ ld
->ld_HitBox
.Width
;
2002 GADGETBOX(ld
->ld_Prop
)->Top
= ld
->ld_HitBox
.Top
;
2003 GADGETBOX(ld
->ld_Prop
)->Width
= sw
;
2004 GADGETBOX(ld
->ld_Prop
)->Height
= ld
->ld_HitBox
.Height
;
2007 * Set top, total etc.
2009 DoSetMethodNG(ld
->ld_Prop
, PGA_Top
, ld
->ld_Top
, PGA_Total
, ld
->ld_Total
,
2010 PGA_Visible
, ld
->ld_Visible
, TAG_DONE
);
2013 * Re-render the scroller.
2015 AsmDoMethod(ld
->ld_Prop
, GM_RENDER
, bi
, rp
, bmr
->bmr_Flags
);
2023 * Find out over which entry the mouse is located.
2025 STATIC ASM LONG
MouseOverEntry(REG(a0
) LD
*ld
, REG(d0
) LONG t
)
2027 t
-= ld
->ld_ListArea
.Top
;
2028 if (t
< 0) return -1;
2030 t
= (t
/ ld
->ld_EntryHeight
) + ld
->ld_Top
;
2032 if (t
> ld
->ld_Total
) t
= ld
->ld_Total
;
2038 * Perform multi-(de)selection.
2040 STATIC ASM BOOL
MultiSelect( REG(a0
) LD
*ld
, REG(d0
) ULONG active
)
2042 LVE
*node
= FindNodeQuick( ld
, ld
->ld_MultiStart
), *anode
= FindNodeQuick( ld
, active
);
2048 if ( ld
->ld_MultiStart
> active
) {
2050 * Loop through the entries.
2052 for ( ; ; node
= node
->lve_Prev
) {
2056 if ( ! ld
->ld_MultiMode
) {
2060 if ( ! ( node
->lve_Flags
& LVEF_SELECTED
)) {
2061 node
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
2067 if (node
->lve_Flags
& LVEF_SELECTED
)
2069 node
->lve_Flags
&= ~LVEF_SELECTED
;
2070 node
->lve_Flags
|= LVEF_REFRESH
;
2077 if ( node
== anode
)
2082 * Loop through the entries.
2084 for ( ; ; node
= node
->lve_Next
) {
2088 if ( ! ld
->ld_MultiMode
) {
2092 if ( ! ( node
->lve_Flags
& LVEF_SELECTED
)) {
2093 node
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
2097 if ( node
->lve_Flags
& LVEF_SELECTED
) {
2098 node
->lve_Flags
&= ~LVEF_SELECTED
;
2099 node
->lve_Flags
|= LVEF_REFRESH
;
2106 if ( node
== anode
)
2114 * Test if the gadget was hit.
2116 METHOD(ListClassHitTest
, struct gpHitTest
*, gph
)
2118 LD
*ld
= INST_DATA(cl
, obj
);
2119 BC
*bc
= BASE_DATA(obj
);
2123 * Get absolute click position.
2125 WORD l
= GADGET(obj
)->LeftEdge
+ gph
->gpht_Mouse
.X
;
2126 WORD t
= GADGET(obj
)->TopEdge
+ gph
->gpht_Mouse
.Y
;
2128 if (PointInBox(&bc
->bc_InnerBox
, l
, t
))
2130 * Hit inside the list area?
2132 return GMR_GADGETHIT
;
2137 * Route the message.
2139 rc
= ForwardMsg(obj
, ld
->ld_Prop
, (Msg
)gph
);
2141 if (rc
== GMR_GADGETHIT
)
2143 * Mark the scroller active.
2145 ld
->ld_Flags
|= LDF_PROPACTIVE
;
2153 * They want us to go active.
2155 METHOD(ListClassGoActive
, struct gpInput
*, gpi
)
2157 LD
*ld
= INST_DATA(cl
, obj
);
2159 ULONG rc
= GMR_NOREUSE
, last
= ld
->ld_LastNum
;
2161 struct GadgetInfo
*gi
= gpi
->gpi_GInfo
;
2166 int x
= gpi
->gpi_Mouse
.X
;
2167 int y
= gpi
->gpi_Mouse
.Y
;
2168 //int l = x + GADGET(obj)->LeftEdge;
2169 int t
= y
+ GADGET(obj
)->TopEdge
;
2172 * We do not go active if we were activated by ActivateGadget().
2174 if (!gpi
->gpi_IEvent
)
2178 * Check for left mouse button down event
2180 if ((gpi
->gpi_IEvent
->ie_Class
== IECLASS_RAWMOUSE
) && (gpi
->gpi_IEvent
->ie_Code
== SELECTDOWN
))
2183 * Update column positions if required
2185 if (!(ld
->ld_Flags
& LDF_OFFSETS_VALID
))
2186 GetColumnPositions(obj
, ld
);
2189 * Step through column positions array, marking a hit if
2190 * mouse is within 4 pixels either side of column separator.
2192 col
= ld
->ld_Columns
- 1;
2195 if (!(ld
->ld_CD
[col
].cd_Flags
& LVCF_HIDDEN
))
2197 dx
= x
- ld
->ld_CD
[col
+ 1].cd_Offset
;
2199 * If hit column separator, set Dragging to TRUE, record
2200 * drag column and initial drag position, draw first
2201 * drag line and return GMR_MEACTIVE.
2203 if ((dx
>= -4) && (dx
<= 4))
2206 * Check for column dragging enabled.
2208 if ((ld
->ld_Flags
& LDF_ALLOW_DRAG
) || (ld
->ld_CD
[col
].cd_Flags
& LVCF_DRAGGABLE
))
2210 ld
->ld_Flags
|= LDF_DRAGGING_COLUMN
;
2211 ld
->ld_DragColumn
= col
;
2212 ld
->ld_DragXLine
= ld
->ld_CD
[col
+1].cd_Offset
;
2213 DrawDragLine(ld
, gi
);
2215 return GMR_MEACTIVE
;
2227 if (ld
->ld_Flags
& LDF_PROPACTIVE
)
2230 * Adjust coordinates and re-direct message.
2232 return ForwardMsg(obj
, ld
->ld_Prop
, (Msg
)gpi
) & ~GMR_VERIFY
;
2239 if (( GADGET( obj
)->Flags
& GFLG_DISABLED
) || ( ld
->ld_Flags
& LDF_READ_ONLY
) || ( ld
->ld_Flags
& LDF_LIST_BUSY
))
2240 return( GMR_NOREUSE
);
2243 * Get the entry which lays under the mouse.
2245 ld
->ld_ActiveEntry
= (ULONG
)MouseOverEntry(ld
, t
);
2247 col
= ld
->ld_Columns
;
2250 if (x
>= ld
->ld_CD
[col
].cd_Offset
)
2253 ld
->ld_LastCol
= col
;
2258 if (ld
->ld_ActiveEntry
< ld
->ld_Total
)
2260 if ((lve
= ld
->ld_LastActive
= FindNodeQuick(ld
, ld
->ld_ActiveEntry
)))
2262 ld
->ld_LastNum
= ld
->ld_ActiveEntry
;
2264 * If we are not a multi-select object we
2265 * de-select all entries. Otherwise we mark the
2266 * entry which initiated the multi-(de)select.
2268 if (!(ld
->ld_Flags
& LDF_MULTI_SELECT
)) DeSelect(ld
);
2271 * De-select entries if shift isn't down.
2273 if (!(ld
->ld_Flags
& LDF_NOSHIFT
))
2275 if (!(gpi
->gpi_IEvent
->ie_Qualifier
& (IEQUALIFIER_LSHIFT
|IEQUALIFIER_RSHIFT
)))
2280 * Multi-selection. When MultiMode is 1 we need
2281 * to multi-deselect. Otherwise we multi-select.
2283 if (lve
->lve_Flags
& LVEF_SELECTED
) ld
->ld_MultiMode
= 1;
2284 else ld
->ld_MultiMode
= 0;
2287 * Setup starting position.
2289 ld
->ld_MultiStart
= ld
->ld_ActiveEntry
;
2292 * Select entry if necessary.
2294 if ( ! ld
->ld_MultiMode
) {
2296 * Note the time we got clicked.
2298 CurrentTime( &ld
->ld_Secs
[ 0 ], &ld
->ld_Mics
[ 0 ] );
2299 lve
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
2302 * De-selection only in multi-mode.
2304 if ( ld
->ld_Flags
& LDF_MULTI_SELECT
) {
2306 * The same selection as the previous?
2308 if ( ld
->ld_ActiveEntry
== last
) {
2312 CurrentTime( &ld
->ld_Secs
[ 1 ], &ld
->ld_Mics
[ 1 ] );
2315 * Double clicked the selection?
2317 if ( ! DoubleClick( ld
->ld_Secs
[ 0 ], ld
->ld_Mics
[ 0 ], ld
->ld_Secs
[ 1 ], ld
->ld_Mics
[ 1 ] )) {
2321 lve
->lve_Flags
&= ~LVEF_SELECTED
;
2322 lve
->lve_Flags
|= LVEF_REFRESH
;
2326 * Deselect the entry.
2328 lve
->lve_Flags
&= ~LVEF_SELECTED
;
2329 lve
->lve_Flags
|= LVEF_REFRESH
;
2332 lve
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
2335 * Notify & Re-render.
2337 DoNotifyMethod(obj
, gi
, OPUF_INTERIM
, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, lve
->lve_Entry
,
2338 LISTV_EntryNumber
, ld
->ld_LastNum
, LISTV_LastColumn
, ld
->ld_LastCol
, TAG_DONE
);
2339 DoRenderMethod(obj
, gi
, GREDRAW_UPDATE
);
2342 * Setup any drag and drop buffers we may need.
2344 if ( AsmDoSuperMethodA( cl
, obj
, ( Msg
)gpi
) == GMR_MEACTIVE
)
2345 ld
->ld_Flags
|= LDF_DRAGGABLE
;
2349 else if (ld
->ld_ActiveEntry
== (ULONG
)-1)
2354 DoNotifyMethod(obj
, gi
, OPUF_INTERIM
, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, -1,
2355 LISTV_EntryNumber
, -1, LISTV_LastColumn
, ld
->ld_LastCol
, TAG_DONE
);
2363 * Handle user input.
2365 METHOD(ListClassHandleInput
, struct gpInput
*, gpi
)
2367 LD
*ld
= INST_DATA(cl
, obj
);
2370 int vc
, xmin
, xmax
, dx
;
2371 ULONG rc
= GMR_MEACTIVE
, otop
= ld
->ld_Top
, ntop
= ld
->ld_Top
;
2373 int dcol
= ld
->ld_DragColumn
;
2374 int totalwidth
, totalweight
;
2375 struct GadgetInfo
*gi
= gpi
->gpi_GInfo
;
2380 * Get mouse position.
2382 int x
= gpi
->gpi_Mouse
.X
;
2383 int y
= gpi
->gpi_Mouse
.Y
;
2384 //int l = x + GADGET(obj)->LeftEdge;
2385 int t
= y
+ GADGET(obj
)->TopEdge
;
2390 if (ld
->ld_Flags
& LDF_LIST_BUSY
)
2396 if (ld
->ld_Flags
& LDF_DRAGGING_COLUMN
)
2398 cd
= ld
->ld_CD
+ dcol
;
2403 * Return this by default, implying we want to
2404 * remain the active gadget.
2409 * If this is a mouse event (movement or button)
2412 if (gpi
->gpi_IEvent
->ie_Class
== IECLASS_RAWMOUSE
)
2415 * Update column offsets if required
2417 if (!(ld
->ld_Flags
& LDF_OFFSETS_VALID
))
2418 GetColumnPositions(obj
, ld
);
2421 * gpi_Mouse.X has mouse-x relative to left side of gadget
2422 * hitbox. Set minimum and maximum values for x at positions
2423 * of columns either side of the one being dragged. Add a
2424 * minimum column width to those limits as well.
2426 xmin
= cd
->cd_Offset
+ cd
->cd_MinWidth
;
2427 xmax
= min(cd
->cd_Offset
+ cd
->cd_MaxWidth
, cd3
->cd_Offset
- cd2
->cd_MinWidth
);
2429 if (xmax
< xmin
) /* just in case column is */
2430 { /* already very narrow, */
2431 xmin
= xmax
= cd2
->cd_Offset
; /* stop user from adjusting it */
2435 * Prevent dragline from wandering outside of limits.
2437 if (x
< xmin
) x
= xmin
;
2438 if (x
> xmax
) x
= xmax
;
2441 * Don't update if dragline position hasn't changed.
2444 if (x
!= ld
->ld_DragXLine
)
2447 * Reposition dragline by drawing again at old position
2448 * using complement mode, then drawing at new position.
2451 DrawDragLine(ld
, gi
);
2452 ld
->ld_DragXLine
= x
;
2453 DrawDragLine(ld
, gi
);
2457 * Check for left mouse button release: implies user
2458 * has stopped dragging column and it's time to recalculate
2459 * the column weights.
2461 if (gpi
->gpi_IEvent
->ie_Code
== SELECTUP
)
2463 rc
= GMR_NOREUSE
; /* we will use LMB-up event */
2466 * No need to do anything if column position not changed.
2468 if ((dx
= x
- cd2
->cd_Offset
))
2471 * Set new column position at x.
2474 cd2
->cd_Width
-= dx
;
2478 * Set new weights for dragged column and the one to the
2479 * right of it, by redistributing the total of their
2480 * original weights in the ratio of their new positions
2481 * over the original total distance between them. Both
2482 * total weight and total distance remain unchanged.
2484 totalweight
= cd
->cd_Weight
+ cd2
->cd_Weight
;
2485 totalwidth
= cd3
->cd_Offset
- cd
->cd_Offset
;
2487 cd2
->cd_Weight
= ((cd3
->cd_Offset
- x
) * totalweight
) / totalwidth
;
2488 cd
->cd_Weight
= totalweight
- cd2
->cd_Weight
;
2491 * If we have a GadgetInfo, invoke GM_RENDER
2492 * to update gadget visuals.
2497 DoRenderMethod(obj
, gi
, GREDRAW_REDRAW
);
2500 * No need for GoInactive() to erase dragline:
2502 ld
->ld_Flags
|= LDF_NEW_COLUMN_POS
;
2505 } /* endif posn changed */
2507 } /* endif LMB down */
2509 * If event was menu button down, abandon dragging
2510 * and let Intuition activate menus.
2513 if (gpi
->gpi_IEvent
->ie_Code
== MENUDOWN
)
2516 } /* endif mouse event */
2519 * If event was either shift key going down, abandon
2520 * dragging as per BGUI standard.
2523 if (gpi
->gpi_IEvent
->ie_Class
== IECLASS_RAWKEY
)
2525 if ((gpi
->gpi_IEvent
->ie_Code
== 0x60) || (gpi
->gpi_IEvent
->ie_Code
== 0x61))
2532 * Prop gadget active?
2534 if (ld
->ld_Prop
&& (ld
->ld_Flags
& LDF_PROPACTIVE
))
2537 * Adjust coordinates and route message.
2539 return ForwardMsg(obj
, ld
->ld_Prop
, (Msg
)gpi
) & ~GMR_VERIFY
;
2543 hit
.MethodID
= BASE_DRAGGING
;
2545 nc
= AsmDoMethodA(obj
, (Msg
)&hit
);
2550 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, ld
->ld_LastActive
? ld
->ld_LastActive
->lve_Entry
: NULL
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
2560 * Get the entry which lies under the mouse.
2562 nc
= MouseOverEntry(ld
, t
);
2565 * There are only so much entries...
2567 if (nc
< 0) nc
= ld
->ld_Top
- 1;
2569 if (nc
>= ld
->ld_Total
) nc
= ld
->ld_Total
- 1;
2572 * Let's see what we got...
2574 if (gpi
->gpi_IEvent
->ie_Class
== IECLASS_RAWMOUSE
)
2577 * We do not support drag-selection when we
2578 * are in drag and drop mode.
2580 if (!(ld
->ld_Flags
& LDF_DRAGGABLE
))
2583 * We only respond when:
2584 * A) The entry under the mouse changed.
2585 * B) The entry under the mouse is in the visible area.
2587 if ((nc
!= ld
->ld_ActiveEntry
) && (nc
>= ld
->ld_Top
) && (nc
< (ld
->ld_Top
+ ld
->ld_Visible
)))
2590 * Mark the new entry.
2592 ld
->ld_ActiveEntry
= nc
;
2597 if ((lve
= ld
->ld_LastActive
= FindNodeQuick(ld
, nc
)))
2599 ld
->ld_LastNum
= nc
;
2601 * Are we a multi-select object?
2603 if (!(ld
->ld_Flags
& LDF_MULTI_SELECT
))
2606 * No. Deselect other entries.
2611 * We need a visual change.
2618 lve
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
2621 * Do a multi-(de)select.
2623 vc
= MultiSelect( ld
, nc
);
2626 * Update visuals if necessary.
2628 if (vc
) DoRenderMethod(obj
, gi
, GREDRAW_UPDATE
);
2629 DoNotifyMethod(obj
, gi
, OPUF_INTERIM
, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, lve
->lve_Entry
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
2635 * What code do we have...
2637 switch (gpi
->gpi_IEvent
->ie_Code
)
2641 * Releasing the left button
2642 * de-activates the object.
2644 rc
= GMR_NOREUSE
| GMR_VERIFY
;
2645 CurrentTime(&ld
->ld_Secs
[0], &ld
->ld_Mics
[0]);
2646 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, ld
->ld_LastActive
->lve_Entry
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
2651 * Reuse menu events.
2653 rc
= GMR_REUSE
| GMR_VERIFY
;
2654 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, ld
->ld_LastActive
->lve_Entry
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
2658 else if (gpi
->gpi_IEvent
->ie_Class
== IECLASS_TIMER
)
2661 * When the mouse is moved above or below
2662 * the visible area the entries scroll up
2663 * or down using timer events for a delay.
2665 if ((nc
!= ld
->ld_ActiveEntry
) && (!(ld
->ld_Flags
& LDF_DRAGGABLE
)))
2668 * When the active entry is located before
2669 * the top entry we scroll up one entry. When the
2670 * entry is located after the last visible entry
2671 * we scroll down one entry.
2674 if (nc
>= ntop
+ ld
->ld_Visible
)
2676 nc
= ntop
++ + ld
->ld_Visible
;
2688 * Set the new entry.
2690 ld
->ld_LastNum
= ld
->ld_ActiveEntry
= nc
;
2695 if ((lve
= ld
->ld_LastActive
= FindNodeQuick(ld
, nc
)))
2698 * Are we a multi-select object?
2700 if (ld
->ld_Flags
& LDF_MULTI_SELECT
)
2703 * Do a multi-(de)select.
2705 vc
= MultiSelect(ld
, nc
);
2710 * No. Deselect all entries.
2716 lve
->lve_Flags
|= LVEF_SELECTED
| LVEF_REFRESH
;
2718 * We need a visual change.
2724 * Update visuals when necessary.
2726 if (vc
|| (otop
!= ntop
))
2731 DoRenderMethod(obj
, gi
, GREDRAW_UPDATE
);
2734 NewTop(ld
, gi
, obj
, ntop
);
2736 DoSetMethod(ld
->ld_Prop
, gi
, PGA_Top
, ntop
, TAG_END
);
2738 DoNotifyMethod(obj
, gi
, OPUF_INTERIM
, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, lve
->lve_Entry
, LISTV_EntryNumber
, ld
->ld_LastNum
, TAG_END
);
2754 METHOD(ListClassGoInActive
, struct gpGoInactive
*, ggi
)
2756 LD
*ld
= INST_DATA(cl
, obj
);
2758 if (ld
->ld_Flags
& LDF_DRAGGING_COLUMN
)
2760 if (!(ld
->ld_Flags
& LDF_NEW_COLUMN_POS
))
2761 DrawDragLine(ld
, ggi
->gpgi_GInfo
);
2763 ld
->ld_Flags
&= ~(LDF_DRAGGING_COLUMN
|LDF_NEW_COLUMN_POS
);
2769 * Clear draggable bit.
2771 ld
->ld_Flags
&= ~LDF_DRAGGABLE
;
2776 * If the scroller was active pass this message on for compatibility reasons.
2778 if (ld
->ld_Flags
& LDF_PROPACTIVE
)
2781 * Mark the scroller as not active.
2783 ld
->ld_Flags
&= ~LDF_PROPACTIVE
;
2785 return AsmDoMethodA(ld
->ld_Prop
, (Msg
)ggi
);
2788 return AsmDoSuperMethodA(cl
, obj
, (Msg
)ggi
);
2795 * They want our minimum dimensions.
2797 METHOD(ListClassDimensions
, struct bmDimensions
*, bmd
)
2799 LD
*ld
= INST_DATA(cl
, obj
);
2800 struct BaseInfo
*bi
= bmd
->bmd_BInfo
;
2801 UWORD my
, mx
= 0, mpx
= 0, mpy
= 0;
2802 int th
= ld
->ld_EntryHeight
, col
;
2803 struct TextAttr
*lf
= ld
->ld_ListFont
;
2808 if (ld
->ld_Prop
) AsmDoMethod(ld
->ld_Prop
, GRM_DIMENSIONS
, bi
, bi
->bi_RPort
, &mpx
, &mpy
, 0);
2813 * Pickup superclass font.
2815 Get_SuperAttr(cl
, obj
, BT_TextAttr
, (IPTR
*)&lf
);
2818 * Setup entry height always even.
2820 ld
->ld_EntryHeight
= (lf
->ta_YSize
+ 1) & (ULONG
)~1;
2823 * Calculate minimum x&y size.
2825 my
= ld
->ld_EntryHeight
* ld
->ld_MinShown
;
2827 for (col
= 0; col
< ld
->ld_Columns
; col
++)
2829 mx
+= ld
->ld_CD
[col
].cd_MinWidth
;
2833 * The listview grows when a title
2834 * hook is specified.
2840 if (my
> mpy
) mpy
= my
;
2845 return CalcDimensions(cl
, obj
, bmd
, mpx
, mpy
);
2853 METHOD(ListClassKeyActive
, struct wmKeyInput
*, wmki
)
2855 LD
*ld
= ( LD
* )INST_DATA( cl
, obj
);
2856 UWORD qual
= wmki
->wmki_IEvent
->ie_Qualifier
;
2857 LONG nnum
= 0, otop
= ld
->ld_Top
, newtop
= otop
;
2864 if ( ld
->ld_Flags
& LDF_READ_ONLY
) {
2866 * Shifted scrolls up.
2868 if ( qual
& ( IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) {
2869 if ( newtop
) newtop
--;
2871 if ( newtop
< ( ld
->ld_Total
- ld
->ld_Visible
)) newtop
++;
2877 if ( newtop
!= otop
)
2878 DoSetMethod( obj
, wmki
->wmki_GInfo
, LISTV_Top
, newtop
, TAG_END
);
2883 *( wmki
->wmki_ID
) = WMHI_IGNORE
;
2886 * Find the selected node.
2888 for ( node
= ld
->ld_Entries
.lvl_First
; node
->lve_Next
; node
= node
->lve_Next
, nnum
++ ) {
2889 if ( node
->lve_Flags
& LVEF_SELECTED
) {
2900 * Select first entry.
2902 DoSetMethod( obj
, wmki
->wmki_GInfo
, LISTV_Select
, 0L, TAG_END
);
2904 if ( qual
& ( IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) {
2906 * Shifted selectes the previous entry.
2908 nnum
=LISTV_Select_Previous
;
2911 * Normal the next entry.
2913 nnum
=LISTV_Select_Next
;
2917 * Select the new entry.
2919 DoSetMethod( obj
, wmki
->wmki_GInfo
, LISTV_Select
, nnum
, TAG_END
);
2924 *( wmki
->wmki_ID
) = WMHI_IGNORE
;
2927 return( WMKF_VERIFY
);
2932 * Get entry predecessor, position and add method.
2934 STATIC ASM VOID
EntryPosHow( REG(a0
) LD
*ld
, REG(a1
) LVE
**lve
, REG(d0
) ULONG pos
, REG(a2
) ULONG
*how
)
2938 * Position of 0 means add to the head.
2942 } else if ( pos
>= ld
->ld_Total
) {
2944 * A position larger or equal to the
2945 * number of available entries means
2952 * Look up the entry to insert after.
2955 *lve
= FindNodeQuick( ld
, pos
- 1 );
2961 * (Multi)Select entry and/or make it visible.
2963 STATIC SAVEDS ASM VOID
DoEntry(REG(a0
) struct GadgetInfo
*gi
, REG(a1
) Object
*obj
, REG(a2
) LD
*ld
, REG(d0
) ULONG flags
, REG(d1
) ULONG number
)
2968 * Make visible? Select?
2970 if (flags
& LVASF_SELECT
)
2975 tag
= (flags
& LVASF_NOT_VISIBLE
) ? LISTV_SelectNotVisible
: LISTV_Select
;
2977 DoSetMethod(obj
, gi
, tag
, number
, TAG_DONE
);
2979 else if (flags
& LVASF_MULTISELECT
)
2984 tag
= (flags
& LVASF_NOT_VISIBLE
) ? LISTV_SelectMultiNotVisible
: LISTV_SelectMulti
;
2986 DoSetMethod(obj
, gi
, tag
, number
, TAG_DONE
);
2988 else if (flags
& LVASF_MAKEVISIBLE
)
2991 * Just make it visible.
2993 DoSetMethod(obj
, gi
, LISTV_MakeVisible
, number
, TAG_DONE
);
3000 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3001 DoRenderMethod(obj
, gi
, GREDRAW_UPDATE
);
3004 /// LVM_INSERTENTRIES
3008 METHOD(ListClassInsertEntries
, struct lvmInsertEntries
*, lvmi
)
3010 LD
*ld
= INST_DATA( cl
, obj
);
3012 ULONG rc
, pos
= lvmi
->lvmi_Pos
, how
;
3015 * Where do we insert them.
3017 EntryPosHow(ld
, &lve
, pos
, &how
);
3020 * Insert the entries.
3022 rc
= AddEntries(ld
, lvmi
->lvmi_Entries
, obj
, how
, lve
);
3025 * We want the list completely refreshed.
3027 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3030 * Render the object.
3032 DoRenderMethod(obj
, lvmi
->lvmi_GInfo
, GREDRAW_UPDATE
);
3038 /// LVM_INSERTSINGLE
3040 * Insert a single entry.
3042 METHOD(ListClassInsertSingle
, struct lvmInsertSingle
*, lvis
)
3044 LD
*ld
= INST_DATA(cl
, obj
);
3045 struct lvmInsertEntries lvmi
;
3052 entries
[0] = lvis
->lvis_Entry
;
3055 lvmi
.MethodID
= LVM_INSERTENTRIES
;
3056 lvmi
.lvmi_GInfo
= lvis
->lvis_GInfo
;
3057 lvmi
.lvmi_Entries
= entries
;
3058 lvmi
.lvmi_Pos
= lvis
->lvis_Pos
;
3063 rc
= METHOD_CALL(ListClassInsertEntries
, cl
, obj
, (Msg
)&lvmi
, (APTR
)getreg(REG_A4
));
3066 * Select the entry or make it visible
3067 * or just redraw the list.
3069 ld
->ld_LastAdded
->lve_Flags
|= LVEF_REFRESH
;
3072 * Make visible? Select?
3074 DoEntry(lvis
->lvis_GInfo
, obj
, ld
, lvis
->lvis_Flags
, lvis
->lvis_Pos
>= ld
->ld_Total
? ld
->ld_Total
- 1 : lvis
->lvis_Pos
);
3084 METHOD(ListClassAddEntries
, struct lvmAddEntries
*, lva
)
3086 LD
*ld
= INST_DATA( cl
, obj
);
3092 rc
= AddEntries(ld
, lva
->lvma_Entries
, obj
, lva
->lvma_How
, NULL
);
3095 * We want the list completely refreshed.
3097 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3100 * Render the object.
3102 DoRenderMethod(obj
, lva
->lvma_GInfo
, GREDRAW_UPDATE
);
3110 * Add a single entry.
3112 METHOD(ListClassAddSingle
, struct lvmAddSingle
*, lva
)
3114 LD
*ld
= INST_DATA(cl
, obj
);
3122 entries
[0] = lva
->lvma_Entry
;
3128 ld
->ld_LastAdded
= NULL
;
3129 rc
= AddEntries(ld
, entries
, obj
, lva
->lvma_How
, NULL
);
3132 * No need to compute the number of the
3133 * entry when it is added to the start or
3134 * the end of the list.
3136 if (lva
->lvma_How
== LVAP_HEAD
) number
= 0;
3137 else if (lva
->lvma_How
== LVAP_TAIL
) number
= ld
->ld_Total
- 1;
3143 for (tmp
= ld
->ld_Entries
.lvl_First
, number
= 0; tmp
->lve_Next
; tmp
= tmp
->lve_Next
, number
++)
3145 if (tmp
== ld
->ld_LastAdded
)
3149 * Select the entry or make it visible
3150 * or just redraw the list.
3152 tmp
->lve_Flags
|= LVEF_REFRESH
;
3156 * New top visible entry?
3158 if (number
== ld
->ld_Top
)
3159 ld
->ld_TopEntry
= ld
->ld_LastAdded
;
3162 * Make visible? Select?
3164 DoEntry(lva
->lvma_GInfo
, obj
, ld
, lva
->lvma_Flags
, number
);
3172 * Clear the entire list.
3174 METHOD(ListClassClear
, struct lvmCommand
*, lvc
)
3176 LD
*ld
= INST_DATA(cl
, obj
);
3178 struct lvResource lvr
;
3181 * Initialize lvResource structure to kill the entry.
3183 lvr
.lvr_Command
= LVRC_KILL
;
3188 ld
->ld_Flags
|= LDF_LIST_BUSY
;
3193 while ((lve
= (LVE
*)RemHead((struct List
*)&ld
->ld_Entries
)))
3196 * Do we have a resource hook?
3198 if (ld
->ld_Resource
)
3203 lvr
.lvr_Entry
= lve
->lve_Entry
;
3208 BGUI_CallHookPkt(ld
->ld_Resource
, (VOID
*)obj
, (VOID
*)&lvr
);
3213 * Simple deallocation.
3215 BGUI_FreePoolMem(lve
->lve_Entry
);
3218 * Free the entry node.
3220 BGUI_FreePoolMem(lve
);
3226 ld
->ld_Total
= ld
->ld_Top
= 0;
3227 ld
->ld_TopEntry
= NULL
;
3228 ld
->ld_LastActive
= NULL
;
3230 ld
->ld_LastAdded
= NULL
;
3233 * We ain't busy no more.
3235 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3238 * Notify a NULL entry.
3240 DoNotifyMethod(obj
, lvc
->lvmc_GInfo
, 0, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, NULL
, TAG_END
);
3243 * We need a complete refresh.
3245 DoRenderMethod(obj
, lvc
->lvmc_GInfo
, GREDRAW_REDRAW
);
3252 * Find a node by it's entry data (slow!).
3254 STATIC ASM LVE
*FindEntryData(REG(a0
) LD
*ld
, REG(a1
) APTR data
, REG(a2
) ULONG
*number
)
3259 for (lve
= ld
->ld_Entries
.lvl_First
; lve
->lve_Next
; lve
= lve
->lve_Next
, num
++)
3261 if (lve
->lve_Entry
== data
)
3263 if (number
) *number
= num
;
3271 * Find a node by it's entry data (can be fast!).
3273 STATIC ASM LVE
*FindEntryDataF(REG(a0
) LD
*ld
, REG(a1
) APTR data
)
3277 if (data
== ld
->ld_ScanEntry
)
3278 return ld
->ld_ScanNode
;
3280 for (lve
= ld
->ld_Entries
.lvl_First
; lve
->lve_Next
; lve
= lve
->lve_Next
)
3282 if (lve
->lve_Entry
== data
)
3292 STATIC
METHOD(ListClassGetEntry
, struct lvmGetEntry
*, lvg
)
3294 LD
*ld
= ( LD
* )INST_DATA( cl
, obj
);
3301 ld
->ld_Flags
|= LDF_LIST_BUSY
;
3304 * What do they want?
3306 switch ( lvg
->MethodID
) {
3308 case LVM_FIRSTENTRY
:
3312 if ( ld
->ld_Total
) {
3316 if ( lvg
->lvmg_Flags
& LVGEF_SELECTED
) {
3320 for ( lve
= ld
->ld_Entries
.lvl_First
; lve
->lve_Next
; lve
= lve
->lve_Next
) {
3324 if ( lve
->lve_Flags
& LVEF_SELECTED
) {
3325 ld
->ld_ScanNode
= lve
;
3326 ld
->ld_ScanEntry
= lve
->lve_Entry
;
3327 rc
= ( IPTR
)lve
->lve_Entry
;
3333 * Normal first entry.
3335 if ( ld
->ld_Entries
.lvl_First
->lve_Next
) {
3336 ld
->ld_ScanNode
= ld
->ld_Entries
.lvl_First
;
3337 ld
->ld_ScanEntry
= ld
->ld_ScanNode
->lve_Entry
;
3338 rc
= ( IPTR
)ld
->ld_ScanEntry
;
3348 if ( ld
->ld_Total
) {
3352 if ( lvg
->lvmg_Flags
& LVGEF_SELECTED
) {
3356 for ( lve
= ld
->ld_Entries
.lvl_Last
; ; lve
= lve
->lve_Prev
) {
3360 if ( lve
->lve_Flags
& LVEF_SELECTED
) {
3361 ld
->ld_ScanNode
= lve
;
3362 ld
->ld_ScanEntry
= lve
->lve_Entry
;
3363 rc
= ( IPTR
)lve
->lve_Entry
;
3369 if ( lve
== ld
->ld_Entries
.lvl_First
)
3374 * Normal last entry.
3376 if ( ld
->ld_Entries
.lvl_First
->lve_Next
) {
3377 ld
->ld_ScanNode
= ld
->ld_Entries
.lvl_Last
;
3378 ld
->ld_ScanEntry
= ld
->ld_ScanNode
->lve_Entry
;
3379 rc
= ( IPTR
)ld
->ld_ScanEntry
;
3389 if (( lve
= FindEntryDataF( ld
, lvg
->lvmg_Previous
))) {
3391 * Is there a next one?
3393 if ( lve
!= ld
->ld_Entries
.lvl_Last
) {
3397 if ( lvg
->lvmg_Flags
& LVGEF_SELECTED
) {
3401 for ( lve
= lve
->lve_Next
; lve
->lve_Next
; lve
= lve
->lve_Next
) {
3405 if ( lve
->lve_Flags
& LVEF_SELECTED
) {
3406 ld
->ld_ScanNode
= lve
;
3407 ld
->ld_ScanEntry
= lve
->lve_Entry
;
3408 rc
= ( IPTR
)lve
->lve_Entry
;
3414 * Normal next entry.
3416 ld
->ld_ScanNode
= lve
->lve_Next
;
3417 ld
->ld_ScanEntry
= lve
->lve_Next
->lve_Entry
;
3418 rc
= ( IPTR
)ld
->ld_ScanEntry
;
3428 if (( lve
= FindEntryDataF( ld
, lvg
->lvmg_Previous
))) {
3430 * Is there a previous one?
3432 if ( lve
!= ld
->ld_Entries
.lvl_First
) {
3436 if ( lvg
->lvmg_Flags
& LVGEF_SELECTED
) {
3440 for ( lve
= lve
->lve_Prev
; ; lve
= lve
->lve_Prev
) {
3444 if ( lve
->lve_Flags
& LVEF_SELECTED
) {
3445 ld
->ld_ScanNode
= lve
;
3446 ld
->ld_ScanEntry
= lve
->lve_Entry
;
3447 rc
= ( IPTR
)lve
->lve_Entry
;
3453 if ( lve
== ld
->ld_Entries
.lvl_First
)
3458 * Normal previous entry.
3460 ld
->ld_ScanNode
= lve
->lve_Prev
;
3461 ld
->ld_ScanEntry
= lve
->lve_Prev
->lve_Entry
;
3462 rc
= ( IPTR
)ld
->ld_ScanEntry
;
3470 * Were not busy anymore.
3472 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3480 * Remove an entry from the list.
3482 STATIC
METHOD(ListClassRemEntry
, struct lvmRemEntry
*, lvmr
)
3484 LD
*ld
= INST_DATA(cl
, obj
);
3486 struct lvResource lvr
;
3492 ld
->ld_Flags
|= LDF_LIST_BUSY
;
3495 * Find the entry node.
3497 if ((lve
= FindEntryData(ld
, lvmr
->lvmr_Entry
, NULL
)))
3502 Remove(( struct Node
* )lve
);
3505 * The last clicked one?
3507 if ( lve
== ld
->ld_LastActive
) {
3508 ld
->ld_LastActive
= NULL
;
3509 ld
->ld_LastNum
= 0L;
3513 * Send NULL notification when this is
3514 * a single-select listview and the entry
3517 if (( ! ( ld
->ld_Flags
& LDF_MULTI_SELECT
)) && ( lve
->lve_Flags
& LVEF_SELECTED
))
3518 DoNotifyMethod( obj
, lvmr
->lvmr_GInfo
, 0L, GA_ID
, GADGET( obj
)->GadgetID
, LISTV_Entry
, NULL
, TAG_END
);
3523 if ( ld
->ld_Resource
) {
3527 lvr
.lvr_Command
= LVRC_KILL
;
3528 lvr
.lvr_Entry
= lve
->lve_Entry
;
3533 rc
= ( ULONG
)BGUI_CallHookPkt(( void * )ld
->ld_Resource
, ( void * )obj
, ( void * )&lvr
);
3536 * Simple de-allocation
3538 BGUI_FreePoolMem( lve
->lve_Entry
);
3544 BGUI_FreePoolMem( lve
);
3554 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3559 DoRenderMethod( obj
, lvmr
->lvmr_GInfo
, GREDRAW_REDRAW
);
3561 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3569 * Remove the selected entry from the list and
3570 * select the next/previous one.
3572 METHOD(ListClassRemSelected
, struct lvmCommand
*, lvmc
)
3574 LD
*ld
= INST_DATA(cl
, obj
);
3575 LVE
*lve
, *sel
= NULL
;
3579 * Scan the selected entry.
3581 while (FirstSelected(obj
))
3584 * Pick up it's node.
3586 lve
= ld
->ld_ScanNode
;
3589 * Was it the last one?
3591 if (lve
== ld
->ld_Entries
.lvl_Last
)
3594 * Also the first one?
3596 if (lve
!= ld
->ld_Entries
.lvl_First
)
3599 * No. Deselect entry and select
3602 lve
->lve_Flags
&= ~LVEF_SELECTED
;
3603 sel
= lve
->lve_Prev
;
3606 * Setup selection data.
3608 if (lve
== ld
->ld_LastActive
)
3610 ld
->ld_LastActive
= sel
;
3622 * Deselect entry and select it's successor.
3624 lve
->lve_Flags
&= ~LVEF_SELECTED
;
3625 sel
= lve
->lve_Next
;
3628 * Setup selection data.
3630 if (lve
== ld
->ld_LastActive
)
3631 ld
->ld_LastActive
= sel
;
3637 AsmDoMethod(obj
, LVM_REMENTRY
, NULL
, lve
->lve_Entry
);
3646 sel
->lve_Flags
|= (LVEF_SELECTED
| LVEF_REFRESH
);
3647 DoNotifyMethod(obj
, lvmc
->lvmc_GInfo
, 0L, GA_ID
, GADGET(obj
)->GadgetID
, LISTV_Entry
, sel
->lve_Entry
, TAG_END
);
3651 AsmDoMethod(obj
, LVM_REFRESH
, lvmc
->lvmc_GInfo
);
3659 * Refresh the listview.
3661 METHOD(ListClassRefresh
, struct lvmCommand
*, lvmc
)
3663 return DoRenderMethod(obj
, lvmc
->lvmc_GInfo
, GREDRAW_REDRAW
);
3669 * Redraw the listview entries.
3671 METHOD(ListClassRedraw
, struct lvmCommand
*, lvmc
)
3673 LD
*ld
= INST_DATA(cl
, obj
);
3675 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3676 return DoRenderMethod(obj
, lvmc
->lvmc_GInfo
, GREDRAW_UPDATE
);
3680 /// LVM_REDRAWSINGLE
3681 METHOD(ListClassRedrawSingle
, struct lvmRedrawSingle
*, lvrs
)
3683 LD
*ld
= INST_DATA(cl
, obj
);
3687 if (!(lvrs
->lvrs_Flags
& LVRF_ALL_COLUMNS
))
3689 ld
->ld_OneColumn
= lvrs
->lvrs_Column
;
3690 ld
->ld_Flags
|= LDF_ONE_COLUMN
;
3693 if (!(lvrs
->lvrs_Flags
& LVRF_ALL_ENTRIES
))
3695 if ((lve
= FindEntryDataF(ld
, lvrs
->lvrs_Entry
)))
3696 lve
->lve_Flags
|= LVEF_REFRESH
;
3700 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3702 rc
= DoRenderMethod(obj
, lvrs
->lvrs_GInfo
, GREDRAW_UPDATE
);
3704 ld
->ld_Flags
&= ~LDF_ONE_COLUMN
;
3714 STATIC
METHOD(ListClassSort
, struct lvmCommand
*, lvmc
)
3716 LD
*ld
= ( LD
* )INST_DATA( cl
, obj
);
3721 * Do we have entries?
3723 if ( ld
->ld_Total
) {
3727 ld
->ld_Flags
|= LDF_LIST_BUSY
;
3730 * Initialize buffer.
3732 NewList(( struct List
* )&buffer
);
3735 * Attach all entries to the buffer.
3737 while (( lve
= ( LVE
* )RemHead(( struct List
* )&ld
->ld_Entries
)))
3738 AddTail(( struct List
* )&buffer
, ( struct Node
* )lve
);
3741 * And put them back again sorted.
3743 while (( lve
= ( LVE
* )RemHead(( struct List
* )&buffer
)))
3744 AddEntryInList( ld
, obj
, lve
, LVAP_SORTED
);
3747 * Were not busy anymore.
3749 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3754 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3755 DoRenderMethod( obj
, lvmc
->lvmc_GInfo
, GREDRAW_UPDATE
);
3761 /// LVM_LOCK, LVM_UNLOCK
3763 * (Un)lock the list.
3765 STATIC
METHOD(ListClassLock
, struct lvmCommand
*, lvmc
)
3767 LD
*ld
= INST_DATA(cl
, obj
);
3769 switch (lvmc
->MethodID
)
3772 ld
->ld_Flags
|= LDF_LIST_BUSY
;
3775 case LVM_UNLOCKLIST
:
3776 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3777 DoRenderMethod(obj
, lvmc
->lvmc_GInfo
, GREDRAW_REDRAW
);
3789 STATIC
METHOD(ListClassMove
, struct lvmMove
*, lvm
)
3791 LD
*ld
= ( LD
* )INST_DATA( cl
, obj
);
3793 ULONG rc
= 0L, num
= 0L, cpos
= 0;
3796 * Look up the entry.
3798 if ( ! lvm
->lvmm_Entry
) lve
= ld
->ld_LastActive
;
3799 else lve
= FindEntryData( ld
, lvm
->lvmm_Entry
, &cpos
);
3805 ld
->ld_Flags
|= LDF_LIST_BUSY
;
3810 switch ( lvm
->lvmm_Direction
) {
3814 * Already at the top?
3816 if ( lve
!= ld
->ld_Entries
.lvl_First
) {
3818 * Pick up new predeccessor.
3820 tmp
= lve
->lve_Prev
->lve_Prev
;
3831 * Already at the bottom?
3833 if ( lve
!= ld
->ld_Entries
.lvl_Last
) {
3835 * Pick up new predeccessor.
3837 tmp
= lve
->lve_Next
;
3844 Remove(( struct Node
* )lve
);
3847 * Insert it into it's new spot.
3849 Insert(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
, ( struct Node
* )tmp
);
3856 * Already at the top?
3858 if ( lve
!= ld
->ld_Entries
.lvl_First
) {
3862 Remove(( struct Node
* )lve
);
3865 * Insert it into it's new spot.
3867 AddHead(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
);
3870 * The number is known.
3874 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3881 * Already at the bottom?
3883 if ( lve
!= ld
->ld_Entries
.lvl_Last
) {
3887 Remove(( struct Node
* )lve
);
3890 * Insert it into it's new spot.
3892 AddTail(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
);
3895 * The number is known.
3897 num
= ld
->ld_Total
- 1;
3899 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3906 * Current position changed?
3908 if ( cpos
!= lvm
->lvmm_NewPos
) {
3912 if ( lvm
->lvmm_NewPos
== 0 ) {
3913 Remove(( struct Node
* )lve
);
3914 AddHead(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
);
3916 } else if ( lvm
->lvmm_NewPos
>= ld
->ld_Total
) {
3917 Remove(( struct Node
* )lve
);
3918 AddTail(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
);
3919 num
= ld
->ld_Total
- 1;
3922 * Not at the start and not at the end. Find the predecessor
3923 * of the place we drop the this node.
3925 tmp
= FindNodeQuick( ld
, lvm
->lvmm_NewPos
- 1 );
3928 * If we are our precedecessor ourselves
3929 * we take the one before us.
3931 if ( tmp
== lve
) tmp
= tmp
->lve_Prev
;
3934 * Remove the node from it's current location
3935 * and insert back in it's new place.
3937 Remove(( struct Node
* )lve
);
3938 Insert(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
, ( struct Node
* )tmp
);
3941 * The number is known.
3943 num
= lvm
->lvmm_NewPos
;
3946 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3958 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
3961 * Find out it's number.
3963 for ( tmp
= ld
->ld_Entries
.lvl_First
; tmp
->lve_Next
; tmp
= tmp
->lve_Next
, num
++ ) {
3972 if (lve
->lve_Flags
& LVEF_SELECTED
)
3974 * Setup it's number.
3976 ld
->ld_LastNum
= num
;
3979 * Make the moved entry visible.
3981 ld
->ld_Flags
|= LDF_REFRESH_ALL
;
3982 DoSetMethod( obj
, lvm
->lvmm_GInfo
, LISTV_MakeVisible
, num
, TAG_END
);
3985 * Notify and setup the new position.
3987 DoNotifyMethod( obj
, lvm
->lvmm_GInfo
, 0L, GA_ID
, GADGET( obj
)->GadgetID
, LISTV_NewPosition
, num
, TAG_END
);
3988 ld
->ld_NewPos
= num
;
3997 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
4007 STATIC
METHOD(ListClassReplace
, struct lvmReplace
*, lvmr
)
4009 LD
*ld
= ( LD
* )INST_DATA( cl
, obj
);
4011 struct lvResource lvr
;
4018 if (( ! lvmr
->lvmr_OldEntry
) || ( ! lvmr
->lvmr_NewEntry
))
4024 ld
->ld_Flags
|= LDF_LIST_BUSY
;
4027 * Find the old entry.
4029 if ((lvo
= FindEntryData(ld
, lvmr
->lvmr_OldEntry
, NULL
)))
4032 * Create the new entry.
4034 if ( ld
->ld_Resource
) {
4038 lvr
.lvr_Command
= LVRC_MAKE
;
4039 lvr
.lvr_Entry
= lvmr
->lvmr_NewEntry
;
4044 if (( newdata
= ( APTR
)BGUI_CallHookPkt(( void * )ld
->ld_Resource
, ( void * )obj
, ( void * )&lvr
))) {
4046 * Free the old entry and setup the new one.
4048 lvr
.lvr_Command
= LVRC_KILL
;
4049 lvr
.lvr_Entry
= lvmr
->lvmr_OldEntry
;
4050 BGUI_CallHookPkt(( void * )ld
->ld_Resource
, ( void * )obj
, ( void * )&lvr
);
4051 lvo
->lve_Entry
= newdata
;
4052 lvo
->lve_Flags
|= LVEF_REFRESH
;
4053 rc
= ( IPTR
)newdata
;
4057 * Allocate a string copy of the new data.
4059 if (( newdata
= ( APTR
)BGUI_AllocPoolMem( strlen(( UBYTE
* )lvmr
->lvmr_NewEntry
) + 1 ))) {
4063 strcpy(( UBYTE
* )newdata
, ( UBYTE
* )lvmr
->lvmr_NewEntry
);
4066 * Free the old entry, and setup the new one.
4068 BGUI_FreePoolMem( lvmr
->lvmr_OldEntry
);
4069 lvo
->lve_Entry
= newdata
;
4070 lvo
->lve_Flags
|= LVEF_REFRESH
;
4071 rc
= ( IPTR
)newdata
;
4077 * Were not busy anymore.
4079 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
4081 if ( rc
) DoRenderMethod( obj
, lvmr
->lvmr_GInfo
, GREDRAW_UPDATE
);
4087 /// LVM_SETCOLUMNATTRS
4089 METHOD(ListClassSetColumnAttrs
, struct lvmColumnAttrs
*, lvca
)
4091 LD
*ld
= INST_DATA(cl
, obj
);
4094 rc
= BGUI_PackStructureTags(&ld
->ld_CD
[lvca
->lvca_Column
], ColumnPackTable
, (struct TagItem
*)&lvca
->lvca_AttrList
);
4096 if (rc
) AsmDoMethod(obj
, LVM_REDRAW
, lvca
->lvca_GInfo
);
4102 /// LVM_GETCOLUMNATTRS
4104 METHOD(ListClassGetColumnAttrs
, struct lvmColumnAttrs
*, lvca
)
4106 LD
*ld
= INST_DATA(cl
, obj
);
4108 return BGUI_UnpackStructureTags(&ld
->ld_CD
[lvca
->lvca_Column
], ColumnPackTable
, (struct TagItem
*)&lvca
->lvca_AttrList
);
4114 * Query if we accept data from the dragged object. We only accept when:
4116 * A) The querying object is us.
4117 * B) We are in LISTV_ShowDropSpot mode.
4118 * C) The mouse is located inside the list view area.
4120 * All other instances are refused.
4122 METHOD(ListClassDragQuery
, struct bmDragPoint
*, bmdp
)
4124 LD
*ld
= INST_DATA( cl
, obj
);
4126 if (bmdp
->bmdp_Source
== obj
&& ld
->ld_Flags
& LDF_SHOWDROPSPOT
)
4128 if (bmdp
->bmdp_Mouse
.X
>= 0 &&
4129 bmdp
->bmdp_Mouse
.Y
>= 0 &&
4130 bmdp
->bmdp_Mouse
.X
< ld
->ld_InnerBox
.Width
&&
4131 bmdp
->bmdp_Mouse
.Y
< ld
->ld_InnerBox
.Height
)
4140 * Show us being the active drop object.
4142 METHOD(ListClassDragActive
, struct bmDragMsg
*, bmdm
)
4144 LD
*ld
= INST_DATA(cl
, obj
);
4145 struct BaseInfo
*bi
;
4147 ld
->ld_DropSpot
=ld
->ld_DrawSpot
= ~0;
4150 * Drop anywhere or do we have to mark the spot?
4152 if ((!(ld
->ld_Flags
& LDF_SHOWDROPSPOT
)) || (!ld
->ld_Entries
.lvl_First
->lve_Next
))
4155 * Anywhere or the list is empty. Simply place a dotted line around the view area.
4158 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, bmdm
->bmdm_GInfo
, BI_RastPort
, NULL
, TAG_DONE
)))
4160 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, bmdm
->bmdm_GInfo
, BI_RastPort
, NULL
, TAG_DONE
)))
4163 ld
->ld_Flags
|= LDF_MOVE_DROPBOX
;
4167 DottedBox(bi
, &ld
->ld_InnerBox
);
4175 /// BASE_DRAGINACTIVE
4179 STATIC
METHOD(ListClassDragInactive
, struct bmDragMsg
*, bmdm
)
4181 LD
*ld
= INST_DATA(cl
, obj
);
4186 if (ld
->ld_LineBuffer
)
4188 BGUI_FreeRPortBitMap(ld
->ld_LineBuffer
);
4189 ld
->ld_LineBuffer
= NULL
;
4191 ld
->ld_DropSpot
= ~0;
4192 ld
->ld_Flags
&= ~LDF_MOVE_DROPBOX
;
4194 return AsmDoSuperMethodA(cl
, obj
, (Msg
)bmdm
);
4201 * Update drop position.
4203 METHOD(ListClassDragUpdate
, struct bmDragPoint
*, bmdp
)
4205 LD
*ld
= INST_DATA(cl
, obj
);
4207 struct GadgetInfo
*gi
= bmdp
->bmdp_GInfo
;
4208 struct BaseInfo
*bi
;
4210 int dpos
, otop
= ld
->ld_Top
, ntop
= otop
;
4212 int x
= bmdp
->bmdp_Mouse
.X
;
4213 int y
= bmdp
->bmdp_Mouse
.Y
;
4216 if (ld
->ld_Flags
& LDF_MOVE_DROPBOX
)
4219 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
4221 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
4224 DottedBox(bi
, &ld
->ld_InnerBox
);
4230 * Keep track of the drop position?
4232 if (ld
->ld_Flags
& LDF_SHOWDROPSPOT
&& ld
->ld_Entries
.lvl_First
->lve_Next
)
4235 * Reject when we are out of the list bounds.
4237 if ((x
< 0) || (x
>= ld
->ld_InnerBox
.Width
))
4240 * We deactivate when the mouse has left us out of the hitbox.
4242 ld
->ld_DropSpot
= ld
->ld_DrawSpot
= ~0;
4247 * Make the y position relative to the window.
4249 Get_SuperAttr(cl
, obj
, BT_HitBox
, (IPTR
*)&ib
);
4250 y
+= ib
->Top
+ (ld
->ld_EntryHeight
>> 1);
4253 * Get the entry under the mouse.
4255 dpos
= MouseOverEntry(ld
, y
);
4258 * New position above or below the
4265 else if (dpos
> (ntop
+ ld
->ld_Visible
))
4267 dpos
= ++ntop
+ ld
->ld_Visible
;
4270 if (ntop
> ld
->ld_Total
- ld
->ld_Visible
)
4271 ntop
= ld
->ld_Total
- ld
->ld_Visible
;
4272 if (ntop
< 0) ntop
= 0;
4274 if (dpos
< 0) dpos
= 0;
4275 if (dpos
> ld
->ld_Total
) dpos
= ld
->ld_Total
;
4280 if (dpos
!= ld
->ld_DropSpot
)
4283 * Yes. Get RastPort.
4287 x1
= ld
->ld_ListArea
.Left
;
4288 y1
= ld
->ld_ListArea
.Top
;
4289 w
= ld
->ld_ListArea
.Width
;
4290 h
= ld
->ld_ListArea
.Height
;
4293 * Re-render the current entry.
4295 if ((ld
->ld_DrawSpot
!= (UWORD
)~0) && ld
->ld_LineBuffer
)
4298 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
4300 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
4304 * Fix line at the old position.
4306 ClipBlit(ld
->ld_LineBuffer
, 0, 0, bi
->bi_RPort
, x1
, ld
->ld_DrawSpot
, w
, 1, 0xC0);
4312 * Scroll if necessary.
4316 DoSetMethod(obj
, gi
, LISTV_Top
, ntop
, TAG_DONE
);
4320 * Mark new position.
4322 ld
->ld_DropSpot
= dpos
;
4327 y
= range((dpos
- ld
->ld_Top
) * ld
->ld_EntryHeight
, 0, h
- 1) + y1
;
4329 ld
->ld_DrawSpot
= y
;
4332 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
4334 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, NULL
, TAG_DONE
)))
4337 if (!ld
->ld_LineBuffer
) ld
->ld_LineBuffer
= BGUI_CreateRPortBitMap(bi
->bi_RPort
, w
, 1, 0);
4339 if (ld
->ld_LineBuffer
)
4342 * Copy the old line to a buffer.
4344 ClipBlit(bi
->bi_RPort
, x1
, y
, ld
->ld_LineBuffer
, 0, 0, w
, 1, 0xC0);
4347 * Render line at the new position.
4349 SetDashedLine(bi
, 0);
4350 HLine(bi
->bi_RPort
, x1
, y
, x1
+ w
- 1);
4360 * Reject when we are out of the list bounds.
4362 if ((x
< 0) || (x
>= ld
->ld_InnerBox
.Width
) ||
4363 (y
< 0) || (y
>= ld
->ld_InnerBox
.Height
))
4366 * We deactivate when the mouse has left us out of the hitbox.
4371 return BUR_CONTINUE
;
4377 * We have been dropped upon.
4379 STATIC
METHOD(ListClassDropped
, struct bmDropped
*, bmd
)
4381 LD
*ld
= ( LD
* )INST_DATA( cl
, obj
);
4382 struct MinList buffer
;
4383 LVE
*lve
, *tmp
, *pred
= NULL
;
4384 ULONG spot
= ld
->ld_DropSpot
, pos
= 0;
4389 * Initialize buffer list.
4391 NewList(( struct List
* )&buffer
);
4396 ld
->ld_Flags
|= LDF_LIST_BUSY
;
4399 * Were we dropped in the list?
4403 * Find the drop-position node.
4407 pred
= ld
->ld_Entries
.lvl_First
;
4409 * We do make this the predecessor
4412 if ( pred
->lve_Flags
& LVEF_SELECTED
)
4414 } else if ( spot
>= ld
->ld_Total
) {
4415 pos
= ld
->ld_Total
- 1;
4416 pred
= ld
->ld_Entries
.lvl_Last
;
4418 pred
= FindNodeQuick( ld
, spot
- 1 );
4419 if ( spot
> ld
->ld_LastNum
) pos
= spot
- 1;
4424 * Now we have to scan back from the drop
4425 * position to find the first not selected
4429 while ( pred
->lve_Flags
& LVEF_SELECTED
) {
4431 * Get previous entry.
4433 pred
= pred
->lve_Prev
;
4436 * Is it the first one and still selected?
4438 if ( pred
== ld
->ld_Entries
.lvl_First
&& pred
->lve_Flags
& LVEF_SELECTED
) {
4447 * Remove all selected entries and append them to the buffer.
4449 lve
= ld
->ld_Entries
.lvl_First
;
4452 * Clear the last-active data.
4454 ld
->ld_LastActive
= NULL
;
4457 while ( lve
->lve_Next
) {
4459 * Is this a selected entry?
4461 if ( lve
->lve_Flags
& LVEF_SELECTED
) {
4465 tmp
= lve
->lve_Next
;
4468 * Remove from the list and
4469 * append it to the buffer.
4471 Remove(( struct Node
* )lve
);
4472 AddTail(( struct List
* )&buffer
, ( struct Node
* )lve
);
4475 * Make the successor current.
4482 lve
= lve
->lve_Next
;
4486 * Move 'm back into their new position.
4488 while (( lve
= ( LVE
* )RemHead(( struct List
* )&buffer
))) {
4489 if ( ! ld
->ld_LastActive
) {
4490 ld
->ld_LastActive
= lve
;
4491 ld
->ld_LastNum
= pos
;
4493 if ( ! pred
) AddHead(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
);
4494 else Insert(( struct List
* )&ld
->ld_Entries
, ( struct Node
* )lve
, ( struct Node
* )pred
);
4499 * We are not busy anymore.
4501 ld
->ld_Flags
&= ~LDF_LIST_BUSY
;
4502 ld
->ld_DropSpot
= ~0;
4510 * Create a rastport in which the selected entries(s) are rendered.
4512 METHOD(ListClassGetObject
, struct bmGetDragObject
*, bmgo
)
4514 LD
*ld
= INST_DATA(cl
, obj
);
4515 struct GadgetInfo
*gi
= bmgo
->bmgo_GInfo
;
4516 struct RastPort
*drag_rp
, *rp
= &gi
->gi_Screen
->RastPort
;
4519 ULONG rc
= 0, num
, i
= 0;
4520 int depth
= gi
->gi_DrInfo
->dri_Depth
;
4521 struct BaseInfo
*bi
;
4523 int lx
= ld
->ld_ListArea
.Left
;
4524 //int ly = ld->ld_ListArea.Top;
4525 int lw
= ld
->ld_ListArea
.Width
;
4526 int lh
= ld
->ld_ListArea
.Height
;
4527 int eh
= ld
->ld_EntryHeight
;
4528 //int mx = gi->gi_Window->MouseX;
4529 int my
= gi
->gi_Window
->MouseY
;
4532 * Do we have any selected entries?
4534 if ((entry
= (APTR
)FirstSelected(obj
)))
4537 * Count the number of selected entries.
4539 for (num
= 0; entry
&& (num
<= 10); num
++)
4541 entry
= (APTR
)NextSelected(obj
, entry
);
4545 * Less than the maximum?
4550 * Allocate the rastport.
4552 if ((drag_rp
= BGUI_CreateRPortBitMap(rp
, lw
, num
* lh
, depth
)))
4555 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, drag_rp
, TAG_DONE
)))
4557 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, drag_rp
, TAG_DONE
)))
4560 BSetFont(bi
, ld
->ld_Font
);
4561 ColumnSeparators(ld
, bi
, 0, 0, num
* ld
->ld_EntryHeight
);
4566 entry
= (APTR
)FirstSelected(obj
);
4569 RenderEntry(obj
, ld
, bi
, ld
->ld_ScanNode
, REL_ZERO
| i
++);
4570 } while ((entry
= (APTR
)NextSelected(obj
, entry
)));
4574 * Setup the rastport so we can
4575 * deallocate it later.
4577 ld
->ld_DragRP
= drag_rp
;
4582 bmgo
->bmgo_Bounds
->Left
= lx
;
4583 bmgo
->bmgo_Bounds
->Top
= my
- ((num
* eh
) >> 1);
4584 bmgo
->bmgo_Bounds
->Width
= lw
;
4585 bmgo
->bmgo_Bounds
->Height
= num
* eh
;
4588 * Return a pointer to the bitmap.
4590 rc
= (IPTR
)drag_rp
->BitMap
;
4592 if(bi
) FreeBaseInfo(bi
);
4599 * More than 10 entries is a special case.
4601 if ((drag_rp
= BGUI_CreateRPortBitMap(rp
, lw
, 3 * eh
, depth
)))
4604 if ((bi
= AllocBaseInfoDebug(__FILE__
,__LINE__
,BI_GadgetInfo
, gi
, BI_RastPort
, drag_rp
, TAG_DONE
)))
4606 if ((bi
= AllocBaseInfo(BI_GadgetInfo
, gi
, BI_RastPort
, drag_rp
, TAG_DONE
)))
4609 BSetFont(bi
, ld
->ld_Font
);
4610 ColumnSeparators(ld
, bi
, 0, 0, 3 * ld
->ld_EntryHeight
);
4613 * Render the first entry...
4616 RenderEntry(obj
, ld
, bi
, ld
->ld_ScanNode
, REL_ZERO
| 0);
4619 * Setup rendering bounds.
4627 * Jam special text...
4629 RenderText(bi
, "\33d3\33D5--->", &box
);
4632 * Render the last entry...
4635 RenderEntry(obj
, ld
, bi
, ld
->ld_ScanNode
, REL_ZERO
| 2);
4637 FreeBaseInfo(bi
); bi
=NULL
;
4651 * Free the dragged object.
4653 STATIC
METHOD(ListClassFreeObject
, struct bmFreeDragObject
*, bmfo
)
4655 LD
*ld
= INST_DATA( cl
, obj
);
4658 * Simply deallocate the bitmap and rastport.
4660 BGUI_FreeRPortBitMap( ld
->ld_DragRP
);
4661 ld
->ld_DragRP
= NULL
;
4668 /// Class initialization.
4672 STATIC DPFUNC ClassFunc
[] = {
4673 { BASE_RENDER
, ListClassRender
, },
4674 { BASE_LAYOUT
, ListClassLayout
, },
4675 { BASE_DIMENSIONS
, ListClassDimensions
, },
4677 { OM_NEW
, ListClassNew
, },
4678 { OM_SET
, ListClassSetUpdate
, },
4679 { OM_UPDATE
, ListClassSetUpdate
, },
4680 { OM_GET
, ListClassGet
, },
4681 { OM_DISPOSE
, ListClassDispose
, },
4682 { GM_HITTEST
, ListClassHitTest
, },
4683 { GM_GOACTIVE
, ListClassGoActive
, },
4684 { GM_HANDLEINPUT
, ListClassHandleInput
, },
4685 { GM_GOINACTIVE
, ListClassGoInActive
, },
4686 { WM_KEYACTIVE
, ListClassKeyActive
, },
4687 { LVM_ADDENTRIES
, ListClassAddEntries
, },
4688 { LVM_INSERTENTRIES
, ListClassInsertEntries
, },
4689 { LVM_ADDSINGLE
, ListClassAddSingle
, },
4690 { LVM_INSERTSINGLE
, ListClassInsertSingle
, },
4691 { LVM_CLEAR
, ListClassClear
, },
4692 { LVM_FIRSTENTRY
, ListClassGetEntry
, },
4693 { LVM_LASTENTRY
, ListClassGetEntry
, },
4694 { LVM_NEXTENTRY
, ListClassGetEntry
, },
4695 { LVM_PREVENTRY
, ListClassGetEntry
, },
4696 { LVM_REMENTRY
, ListClassRemEntry
, },
4697 { LVM_REFRESH
, ListClassRefresh
, },
4698 { LVM_REDRAW
, ListClassRedraw
, },
4699 { LVM_REDRAWSINGLE
, ListClassRedrawSingle
, },
4700 { LVM_SORT
, ListClassSort
, },
4701 { LVM_LOCKLIST
, ListClassLock
, },
4702 { LVM_UNLOCKLIST
, ListClassLock
, },
4703 { LVM_REMSELECTED
, ListClassRemSelected
, },
4704 { LVM_MOVE
, ListClassMove
, },
4705 { LVM_REPLACE
, ListClassReplace
, },
4706 { LVM_SETCOLUMNATTRS
, ListClassSetColumnAttrs
, },
4707 { LVM_GETCOLUMNATTRS
, ListClassGetColumnAttrs
, },
4708 { BASE_DRAGQUERY
, ListClassDragQuery
, },
4709 { BASE_DRAGACTIVE
, ListClassDragActive
, },
4710 { BASE_DRAGINACTIVE
, ListClassDragInactive
, },
4711 { BASE_DRAGUPDATE
, ListClassDragUpdate
, },
4712 { BASE_DROPPED
, ListClassDropped
, },
4713 { BASE_GETDRAGOBJECT
, ListClassGetObject
, },
4714 { BASE_FREEDRAGOBJECT
, ListClassFreeObject
, },
4719 * Simple class initialization.
4721 makeproto Class
*InitListClass(void)
4723 return BGUI_MakeClass(CLASS_SuperClassBGUI
, BGUI_BASE_GADGET
,
4724 CLASS_ObjectSize
, sizeof(LD
),
4725 CLASS_DFTable
, ClassFunc
,