Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / muimaster / classes / menuitem.c
blob765719bc93426cbf5d4ee3da985da2b95c4f590d
1 /*
2 Copyright © 2002-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/memory.h>
7 #include <intuition/icclass.h>
8 #include <intuition/gadgetclass.h>
9 #include <libraries/gadtools.h>
10 #include <clib/alib_protos.h>
11 #include <proto/exec.h>
12 #include <proto/intuition.h>
13 #include <proto/utility.h>
14 #include <proto/muimaster.h>
16 /* #define MYDEBUG 1 */
17 #include "debug.h"
18 #include "mui.h"
19 #include "muimaster_intern.h"
20 #include "support.h"
22 extern struct Library *MUIMasterBase;
24 #define MENUF_CHECKED (1<<0)
25 #define MENUF_CHECKIT (1<<1)
26 #define MENUF_COMMANDSTRING (1<<2)
27 #define MENUF_ENABLED (1<<3)
28 #define MENUF_TOGGLE (1<<4)
30 struct MUI_MenuitemData
32 ULONG flags;
33 ULONG exclude;
35 char *shortcut;
36 char *title;
38 struct NewMenu *newmenu;
40 struct MenuItem *trigger;
43 static int Menuitem_GetTotalChildren(Object *obj)
45 Object *cstate;
46 Object *child;
47 struct MinList *ChildList;
48 int num = 0;
50 get(obj, MUIA_Family_List, &ChildList);
51 cstate = (Object *)ChildList->mlh_Head;
52 while ((child = NextObject(&cstate)))
54 num++;
55 num += Menuitem_GetTotalChildren(child);
57 return num;
60 static int Menuitem_FillNewMenu(Object *obj, struct NewMenu *menu, int depth)
62 Object *cstate;
63 Object *child;
64 struct MinList *ChildList;
65 int num = 0;
67 if (depth > 2) return 0;
69 get(obj, MUIA_Family_List, &ChildList);
70 cstate = (Object *)ChildList->mlh_Head;
71 while ((child = NextObject(&cstate)))
73 int entries;
74 ULONG checkit = 0, checked = 0, toggle = 0, enabled = 0;
76 get(child, MUIA_Menuitem_Title, &menu->nm_Label);
77 get(child, MUIA_Menuitem_Shortcut, &menu->nm_CommKey);
78 get(child, MUIA_Menuitem_Checkit, &checkit);
79 get(child, MUIA_Menuitem_Checked, &checked);
80 get(child, MUIA_Menuitem_Toggle, &toggle);
81 get(child, MUIA_Menuitem_Enabled, &enabled);
82 if (checkit) menu->nm_Flags |= CHECKIT;
83 if (checked) menu->nm_Flags |= CHECKED;
84 if (toggle) menu->nm_Flags |= MENUTOGGLE;
85 get(child, MUIA_Menuitem_Exclude, &menu->nm_MutualExclude);
87 if (depth == 0)
89 menu->nm_Type = NM_TITLE;
90 if ( ! enabled) menu->nm_Flags |= NM_MENUDISABLED;
92 else if (depth == 1)
94 menu->nm_Type = NM_ITEM;
95 if ( ! enabled) menu->nm_Flags |= NM_ITEMDISABLED;
97 else if (depth == 2)
99 menu->nm_Type = NM_SUB;
100 if ( ! enabled) menu->nm_Flags |= NM_ITEMDISABLED;
103 menu->nm_UserData = child;
105 menu++;
106 num++;
107 entries = Menuitem_FillNewMenu(child,menu,depth+1);
109 menu += entries;
110 num += entries;
112 return num;
115 /**************************************************************************
117 **************************************************************************/
118 static struct NewMenu *Menuitem_BuildNewMenu(struct MUI_MenuitemData *data, Object *obj)
120 int entries = Menuitem_GetTotalChildren(obj);
121 if (data->newmenu) FreeVec(data->newmenu);
122 data->newmenu = NULL;
123 if (!entries) return NULL;
125 if ((data->newmenu = (struct NewMenu*)AllocVec((entries+1)*sizeof(struct NewMenu),MEMF_CLEAR)))
127 Menuitem_FillNewMenu(obj,data->newmenu,0);
129 return data->newmenu;
132 /**************************************************************************
133 OM_NEW
134 **************************************************************************/
135 IPTR Menuitem__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
137 struct MUI_MenuitemData *data;
138 struct TagItem *tags,*tag;
140 obj = (Object *)DoSuperMethodA(cl, obj, (Msg)msg); /* We need no tags */
141 if (!obj) return 0;
143 data = INST_DATA(cl, obj);
145 data->flags = MENUF_ENABLED;
147 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags)); )
149 switch (tag->ti_Tag)
151 case MUIA_Menuitem_Checked:
152 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_CHECKED);
153 break;
155 case MUIA_Menuitem_Checkit:
156 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_CHECKIT);
157 break;
159 case MUIA_Menuitem_CommandString:
160 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_COMMANDSTRING);
161 break;
163 case MUIA_Menu_Enabled:
164 case MUIA_Menuitem_Enabled:
165 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_ENABLED);
166 break;
168 case MUIA_Menuitem_Toggle:
169 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_TOGGLE);
170 break;
172 case MUIA_Menuitem_Exclude:
173 data->exclude = tag->ti_Data;
174 break;
176 case MUIA_Menuitem_Shortcut:
177 data->shortcut = (char*)tag->ti_Data;
178 break;
180 case MUIA_Menu_Title:
181 case MUIA_Menuitem_Title:
182 data->title = (char*)tag->ti_Data;
183 break;
187 return (IPTR)obj;
190 /**************************************************************************
191 OM_SET
192 **************************************************************************/
193 IPTR Menuitem__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
195 struct MUI_MenuitemData *data;
196 struct TagItem *tags,*tag;
198 data = INST_DATA(cl, obj);
200 BOOL rebuild = FALSE;
202 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags)); )
204 switch (tag->ti_Tag)
206 case MUIA_Menuitem_Checked:
207 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_CHECKED);
208 if (data->exclude && (data->flags & MENUF_CHECKED))
210 Object *parent;
211 get(obj, MUIA_Parent, &parent);
213 if (parent)
215 Object *child;
216 Object *cstate;
217 struct MinList *ChildList;
218 ULONG i = 1;
220 get(parent, MUIA_Family_List, &ChildList);
221 cstate = (Object *)ChildList->mlh_Head;
222 while ((child = NextObject(&cstate)))
224 if ((i & data->exclude) && (child != obj))
226 IPTR checkit, checked;
228 get(child, MUIA_Menuitem_Checkit, &checkit);
229 get(child, MUIA_Menuitem_Checked, &checked);
231 if (checkit && checked)
233 set(child, MUIA_Menuitem_Checked, FALSE);
237 i <<= 1;
242 rebuild = TRUE;
243 break;
245 case MUIA_Menuitem_Checkit:
246 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_CHECKIT);
247 rebuild = TRUE;
248 break;
250 case MUIA_Menuitem_CommandString:
251 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_COMMANDSTRING);
252 rebuild = TRUE;
253 break;
255 case MUIA_Menu_Enabled:
256 case MUIA_Menuitem_Enabled:
257 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_ENABLED);
258 tag->ti_Tag = TAG_IGNORE;
259 rebuild = TRUE;
260 break;
262 case MUIA_Menuitem_Toggle:
263 _handle_bool_tag(data->flags, tag->ti_Data, MENUF_TOGGLE);
264 rebuild = TRUE;
265 break;
267 case MUIA_Menuitem_Exclude:
268 data->exclude = tag->ti_Data;
269 rebuild = TRUE;
270 break;
272 case MUIA_Menuitem_Shortcut:
273 data->shortcut = (char*)tag->ti_Data;
274 rebuild = TRUE;
275 break;
277 case MUIA_Menu_Title:
278 case MUIA_Menuitem_Title:
279 data->title = (char*)tag->ti_Data;
280 tag->ti_Tag = TAG_IGNORE;
281 rebuild = TRUE;
282 break;
284 case MUIA_Menuitem_Trigger:
285 data->trigger = (struct MenuItem*)tag->ti_Data;
286 rebuild = TRUE;
287 break;
291 if (rebuild)
295 muiNotifyData(obj) &&
296 muiNotifyData(obj)->mnd_GlobalInfo &&
297 muiNotifyData(obj)->mnd_GlobalInfo->mgi_ApplicationObject
300 DoMethod(_app(obj), MUIM_Application_UpdateMenus);
304 return DoSuperMethodA(cl,obj,(Msg)msg);
307 /**************************************************************************
308 OM_GET
309 **************************************************************************/
310 #define STORE *(msg->opg_Storage)
311 IPTR Menuitem__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
313 struct MUI_MenuitemData *data = INST_DATA(cl, obj);
315 switch (msg->opg_AttrID)
317 case MUIA_Menuitem_Checked:
318 STORE = ((data->flags & MENUF_CHECKED) != 0);
319 return 1;
321 case MUIA_Menuitem_Checkit:
322 STORE = ((data->flags & MENUF_CHECKIT) != 0);
323 return 1;
325 case MUIA_Menuitem_CommandString:
326 STORE = ((data->flags & MENUF_COMMANDSTRING) != 0);
327 return 1;
329 case MUIA_Menu_Enabled:
330 case MUIA_Menuitem_Enabled:
331 STORE = ((data->flags & MENUF_ENABLED) != 0);
332 return 1;
334 case MUIA_Menuitem_Toggle:
335 STORE = ((data->flags & MENUF_TOGGLE) != 0);
336 return 1;
338 case MUIA_Menuitem_Exclude:
339 STORE = data->exclude;
340 return 1;
342 case MUIA_Menuitem_Shortcut:
343 STORE = (IPTR)data->shortcut;
344 return 1;
346 case MUIA_Menu_Title:
347 case MUIA_Menuitem_Title:
348 STORE = (IPTR)data->title;
349 return 1;
351 case MUIA_Menuitem_NewMenu:
352 Menuitem_BuildNewMenu(data,obj);
353 STORE = (IPTR)data->newmenu;
354 return 1;
356 case MUIA_Menuitem_Trigger:
357 STORE = (IPTR)data->trigger;
358 return 1;
361 return DoSuperMethodA(cl,obj,(Msg)msg);
363 #undef STORE
366 /**************************************************************************
367 OM_DISPOSE
368 **************************************************************************/
369 IPTR Menuitem__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
371 struct MUI_MenuitemData *data = INST_DATA(cl, obj);
373 FreeVec(data->newmenu);
375 return DoSuperMethodA(cl, obj, msg);
379 /**************************************************************************
380 MUIM_ConnectParent
381 **************************************************************************/
382 IPTR Menuitem__MUIM_ConnectParent(struct IClass *cl, Object *obj, struct MUIP_ConnectParent *msg)
384 Object *cstate;
385 Object *child;
386 struct MinList *ChildList;
388 D(bug("Menuitem_ConnectParent(%p) %s\n", obj, OCLASS(obj)->cl_ID));
390 DoSuperMethodA(cl,obj,(Msg)msg);
392 muiNotifyData(obj)->mnd_ParentObject = msg->parent;
394 get(obj, MUIA_Family_List, &ChildList);
395 cstate = (Object *)ChildList->mlh_Head;
396 while ((child = NextObject(&cstate)))
398 DoMethod(child, MUIM_ConnectParent, (IPTR)obj);
400 return TRUE;
403 /**************************************************************************
404 MUIM_DisconnectParent
405 **************************************************************************/
406 IPTR Menuitem__MUIM_DisconnectParent(struct IClass *cl, Object *obj, struct MUIP_ConnectParent *msg)
408 Object *cstate;
409 Object *child;
410 struct MinList *ChildList;
412 D(bug("Menuitem_DisconnectParent(%p) %s\n", obj, OCLASS(obj)->cl_ID));
414 get(obj, MUIA_Family_List, &ChildList);
415 cstate = (Object *)ChildList->mlh_Head;
416 while ((child = NextObject(&cstate)))
418 DoMethodA(child, (Msg)msg);
420 muiNotifyData(obj)->mnd_ParentObject = NULL;
421 DoSuperMethodA(cl,obj,(Msg)msg);
422 return TRUE;
425 BOOPSI_DISPATCHER(IPTR, Menuitem_Dispatcher, cl, obj, msg)
427 switch (msg->MethodID)
429 case OM_NEW: return Menuitem__OM_NEW(cl, obj, (struct opSet *) msg);
430 case OM_DISPOSE: return Menuitem__OM_DISPOSE(cl, obj, msg);
431 case OM_SET: return Menuitem__OM_SET(cl, obj, (struct opSet *) msg);
432 case OM_GET: return Menuitem__OM_GET(cl, obj, (struct opGet *) msg);
433 case MUIM_ConnectParent: return Menuitem__MUIM_ConnectParent(cl, obj, (APTR)msg);
434 case MUIM_DisconnectParent: return Menuitem__MUIM_DisconnectParent(cl, obj, (APTR)msg);
436 return DoSuperMethodA(cl, obj, msg);
438 BOOPSI_DISPATCHER_END
442 * Class descriptor.
444 const struct __MUIBuiltinClass _MUI_Menuitem_desc = {
445 MUIC_Menuitem,
446 MUIC_Family,
447 sizeof(struct MUI_MenuitemData),
448 (void*)Menuitem_Dispatcher
452 * Class descriptor.- this class is the same like menuitem
454 const struct __MUIBuiltinClass _MUI_Menu_desc = {
455 MUIC_Menu,
456 MUIC_Family,
457 sizeof(struct MUI_MenuitemData),
458 (void*)Menuitem_Dispatcher
462 * Class descriptor.- this class is the same like menuitem
464 const struct __MUIBuiltinClass _MUI_Menustrip_desc = {
465 MUIC_Menustrip,
466 MUIC_Family,
467 sizeof(struct MUI_MenuitemData),
468 (void*)Menuitem_Dispatcher