muimaster.library: Compiler delint
[AROS.git] / workbench / libs / muimaster / classes / listview.c
blob0aa797a59ac149a696fc2221ceeebf28f56cfe12
1 /*
2 Copyright © 2002-2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
8 #include <graphics/gfx.h>
9 #include <graphics/view.h>
10 #include <devices/rawkeycodes.h>
11 #include <clib/alib_protos.h>
12 #include <proto/exec.h>
13 #include <proto/graphics.h>
14 #include <proto/utility.h>
15 #include <proto/intuition.h>
16 #include <proto/muimaster.h>
18 #include "mui.h"
19 #include "muimaster_intern.h"
20 #include "support.h"
21 #include "window.h"
22 #include "list.h"
23 #include "prefs.h"
25 extern struct Library *MUIMasterBase;
27 struct MUI_ListviewData
29 Object *list, *group, *vert;
30 struct Hook *layout_hook;
31 struct Hook hook;
32 struct Hook selfnotify_hook;
33 BOOL noforward;
34 BOOL read_only;
35 IPTR multiselect;
36 struct MUI_EventHandlerNode ehn;
38 int mouse_click; /* see below if mouse is held down */
39 BOOL range_select;
41 /* double click */
42 ULONG last_secs;
43 ULONG last_mics;
44 ULONG last_active;
45 BOOL doubleclick;
47 /* clicked column */
48 LONG click_column;
49 LONG def_click_column;
51 /* user prefs */
52 ListviewMulti prefs_multi;
55 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
56 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
58 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely,
59 UWORD qual);
61 ULONG Listview_Layout_Function(struct Hook *hook, Object *obj,
62 struct MUI_LayoutMsg *lm)
64 struct MUI_ListviewData *data = (struct MUI_ListviewData *)hook->h_Data;
66 switch (lm->lm_Type)
68 case MUILM_MINMAX:
70 /* Calculate the minmax dimension of the group,
71 ** We only have a fixed number of children, so we need
72 ** no NextObject()
74 lm->lm_MinMax.MinWidth =
75 _minwidth(data->list) + _minwidth(data->vert);
76 lm->lm_MinMax.DefWidth =
77 _defwidth(data->list) + _defwidth(data->vert);
78 lm->lm_MinMax.MaxWidth =
79 _maxwidth(data->list) + _maxwidth(data->vert);
80 lm->lm_MinMax.MaxWidth =
81 MIN(lm->lm_MinMax.MaxWidth, MUI_MAXMAX);
83 lm->lm_MinMax.MinHeight =
84 MAX(_minheight(data->list), _minheight(data->vert));
85 lm->lm_MinMax.DefHeight =
86 MAX(_defheight(data->list), lm->lm_MinMax.MinHeight);
87 lm->lm_MinMax.MaxHeight =
88 MIN(_maxheight(data->list), _maxheight(data->vert));
89 lm->lm_MinMax.MaxHeight =
90 MIN(lm->lm_MinMax.MaxHeight, MUI_MAXMAX);
91 return 0;
94 case MUILM_LAYOUT:
96 /* Now place the objects between
97 * (0, 0, lm->lm_Layout.Width - 1, lm->lm_Layout.Height - 1)
100 LONG vert_width = _minwidth(data->vert);
101 LONG lay_width = lm->lm_Layout.Width;
102 LONG lay_height = lm->lm_Layout.Height;
103 LONG cont_width;
104 LONG cont_height;
106 /* We need all scrollbars and the button */
107 set(data->vert, MUIA_ShowMe, TRUE);
108 /* We could also overload MUIM_Show... */
109 cont_width = lay_width - vert_width;
110 cont_height = lay_height;
112 MUI_Layout(data->vert, cont_width, 0, vert_width, cont_height,
115 /* Layout the group a second time, note that setting _mwidth() and
116 _mheight() should be enough, or we invent a new flag */
117 MUI_Layout(data->list, 0, 0, cont_width, cont_height, 0);
118 return 1;
121 return 0;
124 #define PROP_VERT_FIRST 1
125 #define LIST_VERT_FIRST 4
126 #define LIST_VERT_VISIBLE 5
127 #define LIST_VERT_ENTRIES 6
129 ULONG Listview_Function(struct Hook *hook, APTR dummyobj, void **msg)
131 struct MUI_ListviewData *data = (struct MUI_ListviewData *)hook->h_Data;
132 SIPTR type = (SIPTR) msg[0];
133 SIPTR val = (SIPTR) msg[1];
135 D(bug("[ListView] List 0x%p, Event %d, value %ld\n", data->list, type,
136 val));
138 switch (type)
140 case PROP_VERT_FIRST:
141 get(data->vert, MUIA_Prop_First, &val);
142 nnset(data->list, MUIA_List_VertProp_First, val);
143 break;
145 case LIST_VERT_FIRST:
146 nnset(data->vert, MUIA_Prop_First, val);
147 break;
148 case LIST_VERT_VISIBLE:
149 nnset(data->vert, MUIA_Prop_Visible, val);
150 break;
151 case LIST_VERT_ENTRIES:
152 nnset(data->vert, MUIA_Prop_Entries, val);
153 break;
155 return 0;
158 ULONG SelfNotify_Function(struct Hook *hook, APTR obj, void **msg)
160 struct MUI_ListviewData *data = (struct MUI_ListviewData *)hook->h_Data;
161 SIPTR attribute = (SIPTR) msg[0];
162 SIPTR value = (SIPTR) msg[1];
164 /* This allows avoiding notify loops */
165 data->noforward = TRUE;
166 SetAttrs(obj, MUIA_Group_Forward, FALSE, attribute, value, TAG_DONE);
167 data->noforward = FALSE;
169 return 0;
172 /**************************************************************************
173 OM_NEW
174 **************************************************************************/
175 IPTR Listview__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
177 struct MUI_ListviewData *data;
178 struct TagItem *tag, *tags;
179 struct Hook *layout_hook;
180 Object *group, *vert;
181 Object *list =
182 (Object *) GetTagData(MUIA_Listview_List, (IPTR) NULL,
183 msg->ops_AttrList);
184 IPTR cyclechain =
185 (IPTR) GetTagData(MUIA_CycleChain, (IPTR) 0, msg->ops_AttrList);
186 LONG entries = 0, first = 0, visible = 0;
188 if (!list)
189 return (IPTR) NULL;
191 layout_hook = mui_alloc_struct(struct Hook);
192 if (!layout_hook)
193 return (IPTR) NULL;
195 layout_hook->h_Entry = HookEntry;
196 layout_hook->h_SubEntry = (HOOKFUNC) Listview_Layout_Function;
198 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
199 MUIA_Group_Horiz, FALSE,
200 MUIA_CycleChain, cyclechain,
201 MUIA_InnerLeft, 0,
202 MUIA_InnerRight, 0,
203 Child, (IPTR) (group = GroupObject,
204 MUIA_InnerLeft, 0,
205 MUIA_InnerRight, 0,
206 MUIA_Group_LayoutHook, (IPTR) layout_hook,
207 Child, (IPTR) list,
208 Child, (IPTR) (vert =
209 ScrollbarObject, MUIA_Group_Horiz, FALSE, End), End),
210 TAG_DONE);
212 if (!obj)
214 mui_free(layout_hook);
215 return (IPTR) NULL;
218 data = INST_DATA(cl, obj);
219 layout_hook->h_Data = data;
220 data->list = list;
221 data->vert = vert;
222 data->group = group;
223 data->layout_hook = layout_hook;
225 data->hook.h_Entry = HookEntry;
226 data->hook.h_SubEntry = (HOOKFUNC) Listview_Function;
227 data->hook.h_Data = data;
229 data->selfnotify_hook.h_Entry = HookEntry;
230 data->selfnotify_hook.h_SubEntry = (HOOKFUNC) SelfNotify_Function;
231 data->selfnotify_hook.h_Data = data;
232 data->noforward = FALSE;
234 data->last_active = -1;
236 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
237 data->ehn.ehn_Priority = 0;
238 data->ehn.ehn_Flags = 0;
239 data->ehn.ehn_Object = obj;
240 data->ehn.ehn_Class = cl;
242 /* parse initial taglist */
243 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
245 switch (tag->ti_Tag)
247 case MUIA_Listview_DoubleClick:
248 data->doubleclick = tag->ti_Data != 0;
249 break;
250 case MUIA_Listview_Input:
251 data->read_only = !tag->ti_Data;
252 break;
253 case MUIA_Listview_MultiSelect:
254 data->multiselect = tag->ti_Data;
255 break;
259 get(list, MUIA_List_VertProp_First, &first);
260 get(list, MUIA_List_VertProp_Visible, &visible);
261 get(list, MUIA_List_VertProp_Entries, &entries);
263 D(bug
264 ("[ListView 0x%p] List 0x%p, First %ld, Visible %ld, Entries %ld\n",
265 obj, list, first, visible, entries));
267 SetAttrs(data->vert,
268 MUIA_Prop_First, first,
269 MUIA_Prop_Visible, visible, MUIA_Prop_Entries, entries, TAG_DONE);
271 DoMethod(vert, MUIM_Notify, MUIA_Prop_First, MUIV_EveryTime, (IPTR) obj,
272 4, MUIM_CallHook, (IPTR) &data->hook, PROP_VERT_FIRST,
273 MUIV_TriggerValue);
274 DoMethod(list, MUIM_Notify, MUIA_List_VertProp_First, MUIV_EveryTime,
275 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook, LIST_VERT_FIRST,
276 MUIV_TriggerValue);
277 DoMethod(list, MUIM_Notify, MUIA_List_VertProp_Visible, MUIV_EveryTime,
278 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook,
279 LIST_VERT_VISIBLE, MUIV_TriggerValue);
280 DoMethod(list, MUIM_Notify, MUIA_List_VertProp_Entries, MUIV_EveryTime,
281 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook,
282 LIST_VERT_ENTRIES, MUIV_TriggerValue);
283 DoMethod(list, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
284 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->selfnotify_hook,
285 MUIA_List_Active, MUIV_TriggerValue);
287 return (IPTR) obj;
290 /**************************************************************************
291 OM_DISPOSE
292 **************************************************************************/
293 IPTR Listview__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
295 struct MUI_ListviewData *data = INST_DATA(cl, obj);
297 mui_free(data->layout_hook); /* is always here */
298 return DoSuperMethodA(cl, obj, msg);
301 /**************************************************************************
302 OM_SET
303 **************************************************************************/
304 void Listview__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
306 struct TagItem *tag, *tags;
307 IPTR no_notify = GetTagData(MUIA_NoNotify, FALSE, msg->ops_AttrList);
308 struct MUI_ListviewData *data = INST_DATA(cl, obj);
310 if (data->noforward)
312 DoSuperMethodA(cl, obj, (Msg) msg);
313 return;
316 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
318 switch (tag->ti_Tag)
320 case MUIA_List_CompareHook:
321 case MUIA_List_ConstructHook:
322 case MUIA_List_DestructHook:
323 case MUIA_List_DisplayHook:
324 case MUIA_List_VertProp_First:
325 case MUIA_List_Format:
326 case MUIA_List_VertProp_Entries:
327 case MUIA_List_VertProp_Visible:
328 case MUIA_List_Active:
329 case MUIA_List_First:
330 case MUIA_List_Visible:
331 case MUIA_List_Entries:
332 case MUIA_List_Quiet:
333 SetAttrs(data->list, MUIA_NoNotify, no_notify, tag->ti_Tag,
334 tag->ti_Data, TAG_DONE);
335 break;
336 case MUIA_Listview_DoubleClick:
337 data->doubleclick = tag->ti_Data != 0;
338 break;
343 /**************************************************************************
344 OM_GET
345 **************************************************************************/
346 IPTR Listview__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
348 /* small macro to simplify return value storage */
349 #define STORE *(msg->opg_Storage)
350 struct MUI_ListviewData *data = INST_DATA(cl, obj);
352 switch (msg->opg_AttrID)
354 case MUIA_List_CompareHook:
355 case MUIA_List_ConstructHook:
356 case MUIA_List_DestructHook:
357 case MUIA_List_DisplayHook:
358 case MUIA_List_VertProp_First:
359 case MUIA_List_Format:
360 case MUIA_List_VertProp_Entries:
361 case MUIA_List_VertProp_Visible:
362 case MUIA_List_Active:
363 case MUIA_List_First:
364 case MUIA_List_Visible:
365 case MUIA_List_Entries:
366 case MUIA_List_Quiet:
367 return GetAttr(msg->opg_AttrID, data->list, msg->opg_Storage);
368 case MUIA_Listview_DoubleClick:
369 STORE = data->doubleclick;
370 return 1;
371 case MUIA_Listview_ClickColumn:
372 STORE = data->click_column;
373 return 1;
374 case MUIA_Listview_List:
375 STORE = (IPTR) data->list;
376 return 1;
379 return DoSuperMethodA(cl, obj, (Msg) msg);
380 #undef STORE
383 /**************************************************************************
384 MUIM_Setup
385 **************************************************************************/
386 IPTR Listview__MUIM_Setup(struct IClass *cl, Object *obj,
387 struct MUIP_Setup *msg)
389 struct MUI_ListviewData *data = INST_DATA(cl, obj);
391 if (!DoSuperMethodA(cl, obj, (Msg) msg))
392 return 0;
394 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
395 if (data->multiselect == MUIV_Listview_MultiSelect_Default)
397 if (data->prefs_multi == LISTVIEW_MULTI_SHIFTED)
398 data->multiselect = MUIV_Listview_MultiSelect_Shifted;
399 else
400 data->multiselect = MUIV_Listview_MultiSelect_Always;
403 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) &data->ehn);
405 return 1;
408 /**************************************************************************
409 MUIM_Cleanup
410 **************************************************************************/
411 IPTR Listview__MUIM_Cleanup(struct IClass *cl, Object *obj,
412 struct MUIP_Cleanup *msg)
414 struct MUI_ListviewData *data = INST_DATA(cl, obj);
416 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) &data->ehn);
417 data->mouse_click = 0;
419 return DoSuperMethodA(cl, obj, (Msg) msg);
422 /**************************************************************************
423 MUIM_HandleEvent
424 **************************************************************************/
425 IPTR Listview__MUIM_HandleEvent(struct IClass *cl, Object *obj,
426 struct MUIP_HandleEvent *msg)
428 struct MUI_ListviewData *data = INST_DATA(cl, obj);
429 Object *list = data->list;
430 struct MUI_List_TestPos_Result pos;
431 LONG seltype, new_active = 0;
432 IPTR result = 0;
433 BOOL select = FALSE, multiselect = FALSE, clear = FALSE;
435 if (msg->imsg)
437 DoMethod(list, MUIM_List_TestPos, msg->imsg->MouseX,
438 msg->imsg->MouseY, (IPTR) &pos);
440 switch (msg->imsg->Class)
442 case IDCMP_MOUSEBUTTONS:
443 if (msg->imsg->Code == SELECTDOWN)
445 if (_isinobject(list, msg->imsg->MouseX, msg->imsg->MouseY))
447 data->mouse_click = MOUSE_CLICK_ENTRY;
449 new_active = pos.entry;
451 select = TRUE;
452 clear =
453 data->multiselect == MUIV_Listview_MultiSelect_None
454 || (data->multiselect
455 == MUIV_Listview_MultiSelect_Shifted
456 && (msg->imsg->Qualifier
457 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0);
458 seltype = clear ?
459 MUIV_List_Select_On: MUIV_List_Select_Toggle;
460 data->range_select = FALSE;
462 /* Handle MUIA_Listview_ClickColumn */
463 data->click_column = pos.column;
465 if (data->last_active == pos.entry
466 && DoubleClick(data->last_secs, data->last_mics,
467 msg->imsg->Seconds, msg->imsg->Micros))
469 set(obj, MUIA_Listview_DoubleClick, TRUE);
470 data->last_active = -1;
471 data->last_secs = data->last_mics = 0;
473 else
475 data->last_active = pos.entry;
476 data->last_secs = msg->imsg->Seconds;
477 data->last_mics = msg->imsg->Micros;
481 else
483 if (_isinobject(list, msg->imsg->MouseX, msg->imsg->MouseY))
485 data->range_select = FALSE;
486 result = MUI_EventHandlerRC_Eat;
489 if (msg->imsg->Code == SELECTUP && data->mouse_click)
491 set(_win(obj), MUIA_Window_ActiveObject, (IPTR)obj);
492 data->mouse_click = 0;
495 break;
497 case IDCMP_RAWKEY:
498 if (XGET(_win(obj), MUIA_Window_ActiveObject) == (IPTR)obj)
500 switch (msg->imsg->Code)
502 case RAWKEY_UP:
503 new_active = MUIV_List_Active_Up;
504 select = clear =
505 data->multiselect == MUIV_Listview_MultiSelect_None;
506 seltype = MUIV_List_Select_On;
507 break;
509 case RAWKEY_DOWN:
510 new_active = MUIV_List_Active_Down;
511 select = clear =
512 data->multiselect == MUIV_Listview_MultiSelect_None;
513 seltype = MUIV_List_Select_On;
514 break;
516 case RAWKEY_SPACE:
517 if (data->multiselect != MUIV_Listview_MultiSelect_None)
519 select = TRUE;
520 multiselect = TRUE;
521 seltype = MUIV_List_Select_Toggle;
522 data->click_column = data->def_click_column;
524 break;
526 case RAWKEY_NM_WHEEL_UP:
527 DoWheelMove(cl, obj, -1, msg->imsg->Qualifier);
528 break;
530 case RAWKEY_NM_WHEEL_DOWN:
531 DoWheelMove(cl, obj, 1, msg->imsg->Qualifier);
532 break;
534 result = MUI_EventHandlerRC_Eat;
536 break;
539 if (select)
541 multiselect = multiselect ||
542 data->multiselect == MUIV_Listview_MultiSelect_Always
543 || (data->multiselect == MUIV_Listview_MultiSelect_Shifted
544 && (msg->imsg->Qualifier
545 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0);
547 if (clear)
549 DoMethod(list, MUIM_List_Select, multiselect ?
550 MUIV_List_Select_All : MUIV_List_Select_Active,
551 MUIV_List_Select_Off, NULL);
554 if (new_active != XGET(list, MUIA_List_Active))
555 set(list, MUIA_List_Active, new_active);
557 DoMethod(list, MUIM_List_Select,
558 MUIV_List_Select_Active,
559 seltype, NULL);
563 return result;
566 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely,
567 UWORD qual)
569 struct MUI_ListviewData *data = INST_DATA(cl, obj);
570 LONG new, first, entries, visible;
572 new = first = XGET(data->list, MUIA_List_First);
573 entries = XGET(data->list, MUIA_List_Entries);
574 visible = XGET(data->list, MUIA_List_Visible);
576 if (qual & IEQUALIFIER_CONTROL)
578 if (wheely < 0)
579 new = 0;
580 if (wheely > 0)
581 new = entries;
583 else if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
585 new += wheely * visible;
587 else
589 new += wheely * 3;
592 if (new > entries - visible)
594 new = entries - visible;
597 if (new < 0)
599 new = 0;
602 if (new != first)
604 set(data->list, MUIA_List_First, new);
608 BOOPSI_DISPATCHER(IPTR, Listview_Dispatcher, cl, obj, msg)
610 switch (msg->MethodID)
612 case OM_SET:
613 Listview__OM_SET(cl, obj, (struct opSet *)msg);
614 break;
615 case OM_GET:
616 return Listview__OM_GET(cl, obj, (struct opGet *)msg);
617 case OM_NEW:
618 return Listview__OM_NEW(cl, obj, (struct opSet *)msg);
619 case OM_DISPOSE:
620 return Listview__OM_DISPOSE(cl, obj, msg);
621 case MUIM_Setup:
622 return Listview__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
623 case MUIM_Cleanup:
624 return Listview__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
625 case MUIM_HandleEvent:
626 return Listview__MUIM_HandleEvent(cl, obj,
627 (struct MUIP_HandleEvent *)msg);
628 case MUIM_List_Clear:
629 case MUIM_List_CreateImage:
630 case MUIM_List_DeleteImage:
631 case MUIM_List_Exchange:
632 case MUIM_List_GetEntry:
633 case MUIM_List_Insert:
634 case MUIM_List_InsertSingle:
635 case MUIM_List_Jump:
636 case MUIM_List_NextSelected:
637 case MUIM_List_Redraw:
638 case MUIM_List_Remove:
639 case MUIM_List_Select:
640 case MUIM_List_Sort:
641 case MUIM_List_TestPos:
643 struct MUI_ListviewData *data = INST_DATA(cl, obj);
645 return DoMethodA(data->list, msg);
650 return DoSuperMethodA(cl, obj, msg);
652 BOOPSI_DISPATCHER_END
655 * Class descriptor.
657 const struct __MUIBuiltinClass _MUI_Listview_desc =
659 MUIC_Listview,
660 MUIC_Group,
661 sizeof(struct MUI_ListviewData),
662 (void *) Listview_Dispatcher