Some compiler warnings removed.
[cake.git] / workbench / classes / datatypes / amigaguide / navigator.c
blobd42b3f91d194d43651182b265d3d27c610ff46d1
1 /*
2 ** $PROJECT: amigaguide.datatype
3 **
4 ** $VER: navigator.c 50.1 (07.06.03)
5 **
6 ** $AUTHOR: Stefan Ruppert <stefan@ruppert-it.de>
7 **
8 */
10 /* ------------------------------- includes ------------------------------- */
12 #include <intuition/imageclass.h>
13 #include <graphics/gfxmacros.h>
15 /* no debugging output for navigation bar */
16 #undef DEBUG
17 #include "classbase.h"
19 #include "navigator.h"
21 #undef INSTDATA
22 #define INSTDATA struct NavigatorData *data = INST_DATA(cl,obj)
25 /* ----------------------------- definitions ------------------------------ */
27 struct NavigatorData
29 struct NavigatorButton *nd_Buttons;
30 Object *nd_Target;
31 struct Region *nd_Region;
32 UWORD nd_DomainWidth;
33 UWORD nd_MaxWidth;
34 WORD nd_Width;
35 WORD nd_XDistance;
36 UBYTE nd_NumButtons;
37 UBYTE nd_Height;
38 BYTE nd_Pressed;
39 BYTE nd_Selected;
41 BOOL nd_Updating;
44 #define LBUTTON_UP (IECODE_LBUTTON | IECODE_UP_PREFIX)
45 #define LBUTTON_DOWN (IECODE_LBUTTON)
47 /* number of pixel to add to max text width */
48 #define INNERSPACE 10
50 /* --------------------------- public interface --------------------------- */
52 static ULONG navclass_dispatcher(Class *cl, Object *obj, Msg msg);
54 static ClassCall
55 ULONG dispatcher REGARGS((REG(a0,Class *cl),
56 REG(a2,Object *obj),
57 REG(a1,Msg msg)))
59 MREG(a0, Class *, cl);
60 MREG(a2, Object *, obj);
61 MREG(a1, Msg, msg);
63 return navclass_dispatcher(cl, obj, msg);
65 #ifdef __MORPHOS__
66 static struct EmulLibEntry GATEhook = {
67 TRAP_LIB, 0, (void (*)(void)) dispatcher
69 #endif
72 Class *MakeNavigatorClass(struct ClassBase *cb)
74 Class *cl;
76 if((cl = MakeClass(NULL,"gadgetclass",NULL,sizeof(struct NavigatorData),0)) != NULL)
78 #ifdef __MORPHOS__
79 cl->cl_Dispatcher.h_Entry = (HOOKFUNC) &GATEhook;
80 #else
81 cl->cl_Dispatcher.h_Entry = (HOOKFUNC) dispatcher;
82 #endif
83 cl->cl_UserData = (ULONG) cb;
86 return cl;
88 BOOL FreeNavigatorClass(struct ClassBase *cb, Class *cl)
90 return FreeClass(cl);
93 /* ---------------------------- implementation ---------------------------- */
95 static
96 struct Region *installregion(Class *cl, Object *obj, struct GadgetInfo *ginfo)
98 CLASSBASE;
99 INSTDATA;
100 struct Rectangle rect;
102 if((data->nd_Region = NewRegion()) != NULL)
104 rect.MinX = CAST_GAD(obj)->LeftEdge;
105 rect.MinY = CAST_GAD(obj)->TopEdge;
106 rect.MaxX = rect.MinX + data->nd_DomainWidth;
107 rect.MaxY = rect.MinY + CAST_GAD(obj)->Height;
109 return InstallClipRegionSafe(cb,ginfo, data->nd_Region, &rect);
112 return NULL;
114 static
115 void uninstallregion(Class *cl, Object *obj,
116 struct GadgetInfo *ginfo, struct Region *oldreg)
118 CLASSBASE;
119 struct NavigatorData *data = INST_DATA(cl,obj);
121 UnInstallClipRegionSafe(cb, ginfo, oldreg);
123 if(data->nd_Region != NULL)
124 DisposeRegion(data->nd_Region);
127 static
128 void draw_button(Class *cl, Object *obj, struct GadgetInfo *ginfo,
129 struct RastPort *rp, ULONG idx)
131 INSTDATA;
133 struct TextExtent textext;
134 UWORD *pens = ginfo->gi_DrInfo->dri_Pens;
135 struct NavigatorButton *button = &data->nd_Buttons[idx];
137 ULONG x = (data->nd_Width + data->nd_XDistance) * idx + CAST_GAD(obj)->LeftEdge;
138 ULONG y = CAST_GAD(obj)->TopEdge;
140 ULONG txtoffset;
141 ULONG status;
142 ULONG chrs;
144 chrs = TextFit(rp,button->nb_Text,strlen(button->nb_Text),&textext,NULL,1,data->nd_Width-4,ginfo->gi_DrInfo->dri_Font->tf_YSize+1);
145 txtoffset = (data->nd_Width - textext.te_Width) / 2;
147 if(button->nb_Flags & NBF_DISABLED)
148 status = IDS_DISABLED;
149 else if(button->nb_Flags & NBF_SELECTED)
150 status = IDS_SELECTED;
151 else
152 status = IDS_NORMAL;
154 DrawImageState(rp, CAST_GAD(obj)->GadgetRender,x,y,status,ginfo->gi_DrInfo);
156 SetABPenDrMd(rp,pens[TEXTPEN],0,JAM1);
157 Move(rp,x + txtoffset,y + ginfo->gi_DrInfo->dri_Font->tf_Baseline + 1);
158 Text(rp,button->nb_Text,chrs);
160 if(status == IDS_DISABLED)
162 const UWORD pattern[2] = {0x1111,0x4444};
163 SetAfPt(rp,(UWORD *) &pattern[0],1);
164 RectFill(rp,x+2,y+1,x+data->nd_Width-2,y+rp->TxHeight+1);
165 SetAfPt(rp,NULL,0);
168 button->nb_Flags &= ~(NBF_NEEDRENDERING);
170 static
171 BOOL gi_draw_button(Class *cl, Object *obj,
172 struct GadgetInfo *ginfo,
173 ULONG idx)
175 struct RastPort *rp;
177 if((rp = ObtainGIRPort(ginfo)) != NULL)
179 struct Region *oldreg;
181 oldreg = installregion(cl,obj,ginfo);
183 draw_button(cl,obj,ginfo,rp,idx);
185 uninstallregion(cl,obj,ginfo,oldreg);
187 ReleaseGIRPort(rp);
190 return (BOOL) (rp != NULL);
193 static
194 ULONG om_new(Class *cl, Object *obj, struct opSet *msg)
196 INSTDATA;
197 ULONG rv = 0;
199 CAST_GAD(obj)->Flags |= GFLG_RELSPECIAL;
201 data->nd_Target = (Object *) GetTagData(NA_Target,(ULONG) NULL,CAST_SET(msg)->ops_AttrList);
202 data->nd_XDistance = GetTagData(NA_Distance,10,CAST_SET(msg)->ops_AttrList);
203 data->nd_MaxWidth = 0;
204 data->nd_Pressed = -1;
205 data->nd_Selected = -1;
207 if((data->nd_Buttons = (struct NavigatorButton *)
208 GetTagData(NA_Buttons,(ULONG) NULL,CAST_SET(msg)->ops_AttrList)) != NULL)
210 if((CAST_GAD(obj)->GadgetRender = NewObject(NULL,"frameiclass",
211 IA_FrameType,FRAME_BUTTON,
212 TAG_DONE)) != NULL)
214 rv = (ULONG) obj;
218 return rv;
221 static
222 ULONG om_get(Class *cl, Object *obj, struct opGet *msg)
224 INSTDATA;
226 switch(msg->opg_AttrID)
228 case NVA_Selected:
229 *msg->opg_Storage = data->nd_Selected;
230 break;
231 default:
232 return DoSuperMethodA(cl,obj,(Msg) msg);
234 return 1;
236 static
237 ULONG gm_input(Class *cl, Object *obj, struct gpInput *msg)
239 struct InputEvent *ie = msg->gpi_IEvent;
240 ULONG rv;
242 if(ie->ie_Class == IECLASS_RAWMOUSE)
244 INSTDATA;
246 LONG width = data->nd_Width + data->nd_XDistance;
247 LONG mx = msg->gpi_Mouse.X;
248 LONG my = msg->gpi_Mouse.Y;
249 LONG bt = mx / ((width) ? width : 1);
250 LONG btx = data->nd_Pressed * width;
252 struct NavigatorButton *button = &data->nd_Buttons[bt];
253 BOOL domethod = FALSE;
255 switch(ie->ie_Code)
257 case LBUTTON_UP:
258 if(data->nd_Selected != -1)
260 button->nb_Flags &= ~NBF_SELECTED;
262 gi_draw_button(cl,obj,msg->gpi_GInfo,data->nd_Pressed);
264 domethod = TRUE;
265 data->nd_Selected = -1;
266 #ifndef __AROS__ /* debug output requires sysbase */
267 DB(("should do action for button : %ld\n",data->nd_Pressed));
268 #endif
270 rv = GMR_NOREUSE;
271 break;
272 case LBUTTON_DOWN:
273 data->nd_Pressed = bt;
274 btx = bt * width;
275 default:
276 if(my > 0 && my < data->nd_Height &&
277 mx > btx && mx < btx + data->nd_Width &&
278 bt < data->nd_NumButtons)
280 if(bt != data->nd_Selected && !(data->nd_Buttons[bt].nb_Flags & NBF_DISABLED))
282 button->nb_Flags |= NBF_SELECTED;
283 gi_draw_button(cl,obj,msg->gpi_GInfo,bt);
284 data->nd_Selected = bt;
286 } else if(data->nd_Selected != -1)
288 data->nd_Buttons[data->nd_Pressed].nb_Flags &= ~NBF_SELECTED;
289 gi_draw_button(cl,obj,msg->gpi_GInfo,data->nd_Pressed);
290 data->nd_Selected = -1;
292 rv = GMR_MEACTIVE;
295 if(domethod)
297 NotifyAttrs(obj,msg->gpi_GInfo,0,
298 NA_Command, button->nb_Command,
299 TAG_DONE);
301 } else
302 rv = DoSuperMethodA(cl,obj,(Msg) msg);
304 return rv;
306 static
307 ULONG gm_layout(Class *cl, Object *obj, struct gpLayout *msg)
309 INSTDATA;
311 struct GadgetInfo *ginfo = msg->gpl_GInfo;
312 struct IBox *domain;
314 if(GetAttr(DTA_Domain, data->nd_Target, (ULONG *) &domain))
315 data->nd_DomainWidth = domain->Width - 1;
317 /* change left edge according to master object */
318 CAST_GAD(obj)->TopEdge = CAST_GAD(data->nd_Target)->TopEdge;
319 CAST_GAD(obj)->LeftEdge = CAST_GAD(data->nd_Target)->LeftEdge;
321 DB(("Domain Width : %lx , %ld\n", (ULONG) data->nd_Target, data->nd_DomainWidth));
323 if(msg->gpl_Initial)
325 struct RastPort trp;
326 struct NavigatorButton *buttons = data->nd_Buttons;
327 struct TextFont *font = ginfo->gi_DrInfo->dri_Font;
328 ULONG width;
329 ULONG max = 0;
331 InitRastPort(&trp);
332 SetFont(&trp,font);
334 CAST_GAD(obj)->Height = font->tf_YSize + 3;
335 data->nd_Height = font->tf_YSize + 2;
336 data->nd_NumButtons = 0;
338 while(buttons->nb_Text != NULL)
340 width = TextLength(&trp,buttons->nb_Text,strlen(buttons->nb_Text));
341 if(width > max)
342 max = width;
343 buttons++;
344 data->nd_NumButtons++;
347 data->nd_MaxWidth = max + INNERSPACE;
348 data->nd_Width = data->nd_MaxWidth;
351 data->nd_XDistance = 2;
352 data->nd_Width = (data->nd_DomainWidth - (2 * data->nd_NumButtons)) /
353 ((data->nd_NumButtons == 0) ? 1 : data->nd_NumButtons);
354 if(data->nd_Width < 20)
355 data->nd_Width = 20;
357 SetAttrs(CAST_GAD(obj)->GadgetRender,
358 IA_Width, data->nd_Width,
359 IA_Height, data->nd_Height,
360 TAG_DONE);
362 return 0;
364 static
365 ULONG gm_render(Class *cl, Object *obj, struct gpRender *msg)
367 INSTDATA;
369 struct GadgetInfo *ginfo = msg->gpr_GInfo;
370 struct Region *oldreg;
371 ULONG idx = 0;
373 oldreg = installregion(cl,obj,ginfo);
375 SetFont(msg->gpr_RPort, ginfo->gi_DrInfo->dri_Font);
377 while(idx < data->nd_NumButtons)
379 if(msg->gpr_Redraw == GREDRAW_REDRAW || (data->nd_Buttons[idx].nb_Flags & NBF_NEEDRENDERING))
380 draw_button(cl,obj,ginfo,msg->gpr_RPort,idx);
381 idx++;
384 uninstallregion(cl,obj,ginfo,oldreg);
386 return 0;
388 static
389 ULONG nvm_changestatus(Class *cl,Object *obj,struct npChangeStatus *msg)
391 INSTDATA;
392 struct NavigatorButton *button;
393 ULONG idx = 0;
394 LONG rv = 0;
395 LONG i;
397 for(i = 0; i < msg->np_NumCommands ; i++)
399 #ifndef __AROS__ /* debug output requires sysbase */
400 DB(("change status for %ld\n", msg->np_Commands[i].ns_Command));
401 #endif
403 button = data->nd_Buttons;
404 while(button->nb_Text != NULL)
406 if(button->nb_Command == msg->np_Commands[i].ns_Command)
408 BOOL render = FALSE;
409 LONG status = msg->np_Commands[i].ns_Status;
411 #ifndef __AROS__ /* debug output requires sysbase */
412 DB(("%ld[%ld] flags : %ld , change to %ld\n",
413 msg->np_Commands[i].ns_Command, i, button->nb_Flags, status));
414 #endif
416 if((status & NVS_MASK) == NVS_ENABLE)
418 render = (button->nb_Flags & NBF_DISABLED);
419 button->nb_Flags &= ~NBF_DISABLED;
420 } else if((status & NVS_MASK) == NVS_DISABLE)
422 render = !(button->nb_Flags & NBF_DISABLED);
423 button->nb_Flags |= NBF_DISABLED;
426 #ifndef __AROS__ /* debug output requires sysbase */
427 DB(("render : %ld flags now : %ld\n",
428 render, button->nb_Flags));
429 #endif
431 if(render != FALSE)
433 if((status & NVF_RENDER))
435 if(!gi_draw_button(cl,obj,msg->np_GInfo,idx))
436 ++rv;
437 } else
439 button->nb_Flags |= NBF_NEEDRENDERING;
440 ++rv;
443 #ifndef __AROS__ /* debug output requires sysbase */
444 DB(("nav button need rendering : \"%s\"%s rendered !\n",
445 button->nb_Text, (rv == 1) ? "" : " not"));
446 #endif
448 break;
450 idx++;
451 button++;
455 return rv;
457 static
458 ULONG nvm_changed(Class *cl, Object *obj, Msg msg)
460 INSTDATA;
461 struct NavigatorButton *button = data->nd_Buttons;
462 LONG rv = 0;
464 while(button->nb_Text != NULL)
466 if(button->nb_Flags & NBF_NEEDRENDERING)
467 rv++;
468 button++;
471 return rv;
474 static
475 ULONG navclass_dispatcher(Class *cl, Object *obj, Msg msg)
477 LONG rv = 0;
479 switch(msg->MethodID)
481 case OM_NEW:
482 if((rv = DoSuperMethodA(cl,obj,msg)) != 0)
484 Object *newobj = (Object *) rv;
486 if((rv = om_new(cl, newobj, CAST_SET(msg))) == (ULONG) NULL)
487 CoerceMethod(cl, newobj, OM_DISPOSE);
489 break;
490 case OM_DISPOSE:
491 DisposeObject(CAST_GAD(obj)->GadgetRender);
492 rv = DoSuperMethodA(cl, obj, msg);
493 break;
494 case OM_GET:
495 rv = om_get(cl, obj, (struct opGet *) msg);
496 break;
497 case GM_GOACTIVE:
498 case GM_HANDLEINPUT:
499 rv = gm_input(cl, obj, (struct gpInput *) msg);
500 break;
501 case GM_LAYOUT:
502 rv = gm_layout(cl, obj, (struct gpLayout *) msg);
503 break;
504 case GM_RENDER:
505 rv = gm_render(cl, obj, (struct gpRender *) msg);
506 break;
507 case NVM_CHANGESTATUS:
508 rv = nvm_changestatus(cl, obj, (struct npChangeStatus *) msg);
509 break;
510 case NVM_CHANGED:
511 rv = nvm_changed(cl, obj, msg);
512 break;
513 default:
514 rv = DoSuperMethodA(cl, obj, msg);
517 return rv;