2 ** $PROJECT: amigaguide.datatype
4 ** $VER: navigator.c 50.1 (07.06.03)
6 ** $AUTHOR: Stefan Ruppert <stefan@ruppert-it.de>
10 /* ------------------------------- includes ------------------------------- */
12 #include <intuition/imageclass.h>
13 #include <graphics/gfxmacros.h>
15 /* no debugging output for navigation bar */
17 #include "classbase.h"
19 #include "navigator.h"
22 #define INSTDATA struct NavigatorData *data = INST_DATA(cl,obj)
25 /* ----------------------------- definitions ------------------------------ */
29 struct NavigatorButton
*nd_Buttons
;
31 struct Region
*nd_Region
;
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 */
50 /* --------------------------- public interface --------------------------- */
52 static ULONG
navclass_dispatcher(Class
*cl
, Object
*obj
, Msg msg
);
55 ULONG dispatcher
REGARGS((REG(a0
,Class
*cl
),
59 MREG(a0
, Class
*, cl
);
60 MREG(a2
, Object
*, obj
);
63 return navclass_dispatcher(cl
, obj
, msg
);
66 static struct EmulLibEntry GATEhook
= {
67 TRAP_LIB
, 0, (void (*)(void)) dispatcher
72 Class
*MakeNavigatorClass(struct ClassBase
*cb
)
76 if((cl
= MakeClass(NULL
,"gadgetclass",NULL
,sizeof(struct NavigatorData
),0)) != NULL
)
79 cl
->cl_Dispatcher
.h_Entry
= (HOOKFUNC
) &GATEhook
;
81 cl
->cl_Dispatcher
.h_Entry
= (HOOKFUNC
) dispatcher
;
83 cl
->cl_UserData
= (ULONG
) cb
;
88 BOOL
FreeNavigatorClass(struct ClassBase
*cb
, Class
*cl
)
93 /* ---------------------------- implementation ---------------------------- */
96 struct Region
*installregion(Class
*cl
, Object
*obj
, struct GadgetInfo
*ginfo
)
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
);
115 void uninstallregion(Class
*cl
, Object
*obj
,
116 struct GadgetInfo
*ginfo
, struct Region
*oldreg
)
119 struct NavigatorData
*data
= INST_DATA(cl
,obj
);
121 UnInstallClipRegionSafe(cb
, ginfo
, oldreg
);
123 if(data
->nd_Region
!= NULL
)
124 DisposeRegion(data
->nd_Region
);
128 void draw_button(Class
*cl
, Object
*obj
, struct GadgetInfo
*ginfo
,
129 struct RastPort
*rp
, ULONG idx
)
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
;
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
;
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);
168 button
->nb_Flags
&= ~(NBF_NEEDRENDERING
);
171 BOOL
gi_draw_button(Class
*cl
, Object
*obj
,
172 struct GadgetInfo
*ginfo
,
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
);
190 return (BOOL
) (rp
!= NULL
);
194 ULONG
om_new(Class
*cl
, Object
*obj
, struct opSet
*msg
)
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
,
222 ULONG
om_get(Class
*cl
, Object
*obj
, struct opGet
*msg
)
226 switch(msg
->opg_AttrID
)
229 *msg
->opg_Storage
= data
->nd_Selected
;
232 return DoSuperMethodA(cl
,obj
,(Msg
) msg
);
237 ULONG
gm_input(Class
*cl
, Object
*obj
, struct gpInput
*msg
)
239 struct InputEvent
*ie
= msg
->gpi_IEvent
;
242 if(ie
->ie_Class
== IECLASS_RAWMOUSE
)
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
;
258 if(data
->nd_Selected
!= -1)
260 button
->nb_Flags
&= ~NBF_SELECTED
;
262 gi_draw_button(cl
,obj
,msg
->gpi_GInfo
,data
->nd_Pressed
);
265 data
->nd_Selected
= -1;
266 #ifndef __AROS__ /* debug output requires sysbase */
267 DB(("should do action for button : %ld\n",data
->nd_Pressed
));
273 data
->nd_Pressed
= bt
;
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;
297 NotifyAttrs(obj
,msg
->gpi_GInfo
,0,
298 NA_Command
, button
->nb_Command
,
302 rv
= DoSuperMethodA(cl
,obj
,(Msg
) msg
);
307 ULONG
gm_layout(Class
*cl
, Object
*obj
, struct gpLayout
*msg
)
311 struct GadgetInfo
*ginfo
= msg
->gpl_GInfo
;
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
));
326 struct NavigatorButton
*buttons
= data
->nd_Buttons
;
327 struct TextFont
*font
= ginfo
->gi_DrInfo
->dri_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
));
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)
357 SetAttrs(CAST_GAD(obj
)->GadgetRender
,
358 IA_Width
, data
->nd_Width
,
359 IA_Height
, data
->nd_Height
,
365 ULONG
gm_render(Class
*cl
, Object
*obj
, struct gpRender
*msg
)
369 struct GadgetInfo
*ginfo
= msg
->gpr_GInfo
;
370 struct Region
*oldreg
;
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
);
384 uninstallregion(cl
,obj
,ginfo
,oldreg
);
389 ULONG
nvm_changestatus(Class
*cl
,Object
*obj
,struct npChangeStatus
*msg
)
392 struct NavigatorButton
*button
;
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
));
403 button
= data
->nd_Buttons
;
404 while(button
->nb_Text
!= NULL
)
406 if(button
->nb_Command
== msg
->np_Commands
[i
].ns_Command
)
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
));
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
));
433 if((status
& NVF_RENDER
))
435 if(!gi_draw_button(cl
,obj
,msg
->np_GInfo
,idx
))
439 button
->nb_Flags
|= NBF_NEEDRENDERING
;
443 #ifndef __AROS__ /* debug output requires sysbase */
444 DB(("nav button need rendering : \"%s\"%s rendered !\n",
445 button
->nb_Text
, (rv
== 1) ? "" : " not"));
458 ULONG
nvm_changed(Class
*cl
, Object
*obj
, Msg msg
)
461 struct NavigatorButton
*button
= data
->nd_Buttons
;
464 while(button
->nb_Text
!= NULL
)
466 if(button
->nb_Flags
& NBF_NEEDRENDERING
)
475 ULONG
navclass_dispatcher(Class
*cl
, Object
*obj
, Msg msg
)
479 switch(msg
->MethodID
)
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
);
491 DisposeObject(CAST_GAD(obj
)->GadgetRender
);
492 rv
= DoSuperMethodA(cl
, obj
, msg
);
495 rv
= om_get(cl
, obj
, (struct opGet
*) msg
);
499 rv
= gm_input(cl
, obj
, (struct gpInput
*) msg
);
502 rv
= gm_layout(cl
, obj
, (struct gpLayout
*) msg
);
505 rv
= gm_render(cl
, obj
, (struct gpRender
*) msg
);
507 case NVM_CHANGESTATUS
:
508 rv
= nvm_changestatus(cl
, obj
, (struct npChangeStatus
*) msg
);
511 rv
= nvm_changed(cl
, obj
, msg
);
514 rv
= DoSuperMethodA(cl
, obj
, msg
);