This should solve an error which made the nightly build fail with:
[AROS-Contrib.git] / bgui / frameclass.c
blobb731f9979d67f825a5aa05d4a333b543a409a0d5
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * frameclass.c
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.
13 * $Log$
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:01 mlemos
35 * Bumped to revision 42.0 before handing BGUI to AROS team
37 * Revision 41.11 2000/05/09 19:54:17 mlemos
38 * Merged with the branch Manuel_Lemos_fixes.
40 * Revision 41.10.2.7 1999/07/04 05:24:40 mlemos
41 * Fixed attempts to render areas witrh invalid dimensions.
43 * Revision 41.10.2.6 1999/07/03 15:17:37 mlemos
44 * Replaced the calls to CallHookPkt to BGUI_CallHookPkt.
46 * Revision 41.10.2.5 1999/07/03 15:12:26 mlemos
47 * Ensured that frame is only drawn if dimensions are bigger than 0.
48 * Removed debug code to warn when dimensions are too small.
50 * Revision 41.10.2.4 1999/07/03 14:29:56 mlemos
51 * Added assertion code to warn frame dimensions are too small.
53 * Revision 41.10.2.3 1999/07/03 14:13:08 mlemos
54 * Fixed off by one mistake on the computation of the minimum frame size
56 * Revision 41.10.2.2 1998/12/07 03:06:59 mlemos
57 * Replaced OpenFont and CloseFont calls by the respective BGUI debug macros.
59 * Revision 41.10.2.1 1998/02/28 02:22:54 mlemos
60 * Made setting the frame title to NULL to reset text title object.
62 * Revision 41.10 1998/02/25 21:12:05 mlemos
63 * Bumping to 41.10
65 * Revision 1.1 1998/02/25 17:08:20 mlemos
66 * Ian sources
71 /// Class definitions.
73 #include "include/classdefs.h"
76 * Object instance data.
78 typedef struct fd_ {
79 ULONG fd_Flags; /* Flags. */
80 Object *fd_Title; /* Frame title. */
81 struct TextAttr *fd_TitleFont; /* Font for the title. */
82 struct TextFont *fd_Font; /* The opened font. */
83 struct Hook fd_DefBackfill; /* Default backfill hook. */
84 struct Hook *fd_FrameHook; /* Custom frame hook. */
85 struct Hook *fd_BackFillHook; /* Custom backfill hook. */
86 struct bguiPattern *fd_Pattern; /* Normal fill pattern. */
87 struct bguiPattern *fd_SelPattern; /* Selected fill pattern. */
88 Object *fd_ParentGroup; /* Parent Group. */
89 UWORD fd_Type; /* Frame type. */
90 UWORD fd_BackFill; /* Backfilling type. */
91 UBYTE fd_Horizontal; /* Horizontal thickness */
92 UBYTE fd_Vertical; /* Vertical thickness */
94 UWORD fd_BackPen, fd_BackPen2; /* Normal backfill pens. */
95 UWORD fd_SelPen, fd_SelPen2; /* Selected backfill pens. */
96 BYTE fd_OuterX1, fd_OuterX2, fd_OuterY1, fd_OuterY2;
97 BYTE fd_InnerX1, fd_InnerX2, fd_InnerY1, fd_InnerY2;
98 } FD;
100 #define FRF_SELFOPEN (1<<31)
101 #define FRF_INBORDER (1<<30) /* Image in window border? */
102 #define FRF_BACKDRI (1<<29)
103 #define FRF_SELDRI (1<<28)
104 #define FRF_BACKDRI2 (1<<27)
105 #define FRF_SELDRI2 (1<<26)
106 #define FRF_CUST_THICK (1<<25)
107 #define FRF_FILL_OUTER (1<<24)
109 #define FD_ENTRY(tag, offset, flags) PACK_ENTRY(FRM_TAGSTART, tag, fd_, offset, flags)
110 #define FD_FLAG(tag, flag) PACK_LONGBIT(FRM_TAGSTART, tag, fd_, fd_Flags, PKCTRL_BIT, flag)
112 static ULONG FramePackTable[] =
114 PACK_STARTTABLE(FRM_TAGSTART),
116 FD_ENTRY(FRM_Flags, fd_Flags, PKCTRL_ULONG),
117 FD_ENTRY(FRM_CustomHook, fd_FrameHook, PKCTRL_ULONG),
118 FD_ENTRY(FRM_BackFillHook, fd_BackFillHook, PKCTRL_ULONG),
119 FD_ENTRY(FRM_TextAttr, fd_TitleFont, PKCTRL_ULONG),
120 FD_ENTRY(FRM_Type, fd_Type, PKCTRL_UWORD),
121 FD_ENTRY(FRM_BackFill, fd_BackFill, PKCTRL_UWORD),
122 FD_ENTRY(FRM_FillPattern, fd_Pattern, PKCTRL_ULONG),
123 FD_ENTRY(FRM_SelectedFillPattern, fd_SelPattern, PKCTRL_ULONG),
125 FD_ENTRY(FRM_FrameWidth, fd_Horizontal, PKCTRL_UBYTE),
126 FD_ENTRY(FRM_FrameHeight, fd_Vertical, PKCTRL_UBYTE),
127 FD_ENTRY(FRM_OuterOffsetLeft, fd_OuterX1, PKCTRL_BYTE),
128 FD_ENTRY(FRM_OuterOffsetRight, fd_OuterX2, PKCTRL_BYTE),
129 FD_ENTRY(FRM_OuterOffsetTop, fd_OuterY1, PKCTRL_BYTE),
130 FD_ENTRY(FRM_OuterOffsetBottom, fd_OuterY2, PKCTRL_BYTE),
131 FD_ENTRY(FRM_InnerOffsetLeft, fd_InnerX1, PKCTRL_BYTE),
132 FD_ENTRY(FRM_InnerOffsetRight, fd_InnerX2, PKCTRL_BYTE),
133 FD_ENTRY(FRM_InnerOffsetTop, fd_InnerY1, PKCTRL_BYTE),
134 FD_ENTRY(FRM_InnerOffsetBottom, fd_InnerY2, PKCTRL_BYTE),
136 FD_FLAG(FRM_EdgesOnly, FRF_EDGES_ONLY),
137 FD_FLAG(FRM_Recessed, FRF_RECESSED),
138 FD_FLAG(FRM_CenterTitle, FRF_CENTER_TITLE),
139 FD_FLAG(FRM_HighlightTitle, FRF_HIGHLIGHT_TITLE),
140 FD_FLAG(FRM_ThinFrame, FRF_THIN_FRAME),
141 FD_FLAG(FRM_TitleLeft, FRF_TITLE_LEFT),
142 FD_FLAG(FRM_TitleRight, FRF_TITLE_RIGHT),
144 PACK_ENDTABLE
149 * Built-in background hook. This hook will take
150 * care of the backfilling rasters and the special
151 * backfilling pens.
153 //STATIC SAVEDS ASM BuiltInBack(REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct FrameDrawMsg *fdm)
154 STATIC SAVEDS ASM REGFUNC3(IPTR, BuiltInBack,
155 REGPARAM(A0, struct Hook *, hook),
156 REGPARAM(A2, Object *, obj),
157 REGPARAM(A1, struct FrameDrawMsg *, fdm))
159 FD *fd = INST_DATA(OCLASS(obj), obj);
160 UWORD *pens = PENS(fdm->fdm_DrawInfo), apen, bpen;
161 struct RastPort *rp = fdm->fdm_RPort;
162 struct IBox ib;
163 struct bguiPattern *pat;
165 int fill;
167 int x1 = fdm->fdm_Bounds->MinX;
168 int x2 = fdm->fdm_Bounds->MaxX;
169 int y1 = fdm->fdm_Bounds->MinY;
170 int y2 = fdm->fdm_Bounds->MaxY;
172 BOOL sel = ((fdm->fdm_State == IDS_SELECTED) || (fdm->fdm_State == IDS_INACTIVESELECTED));
174 STATIC UBYTE backfill[][2] =
176 { BACKGROUNDPEN, BACKGROUNDPEN }, // STANDARD_FILL
177 { SHINEPEN, BACKGROUNDPEN }, // SHINE_RASTER
178 { SHADOWPEN, BACKGROUNDPEN }, // SHADOW_RASTER
179 { SHINEPEN, SHADOWPEN }, // SHINE_SHADOW_RASTER
180 { FILLPEN, BACKGROUNDPEN }, // FILL_RASTER
181 { SHINEPEN, FILLPEN }, // SHINE_FILL_RASTER
182 { SHADOWPEN, FILLPEN }, // SHADOW_FILL_RASTER
183 { SHINEPEN, SHINEPEN }, // SHINE_BLOCK
184 { SHADOWPEN, SHADOWPEN }, // SHADOW_BLOCK
185 { FILLPEN, FILLPEN }, // FILL_BLOCK
189 * Render the backfill?
191 if (fdm->fdm_MethodID == FRM_RENDER)
194 * Setup domain.
196 ib.Left = x1;
197 ib.Top = y1;
198 ib.Width = x2 - x1 + 1;
199 ib.Height = y2 - y1 + 1;
201 pat = fd->fd_Pattern;
202 if (sel && !pat) pat = fd->fd_SelPattern;
204 if (pat)
206 BGUI_FillRectPattern(rp, pat, x1, y1, x2, y2);
207 return FRC_OK;
210 if (fd->fd_BackFill == STANDARD_FILL)
213 * A raster backfill. Set up the pens.
217 * First check for a normal (dri)pen.
218 * If none is given we use the default color.
220 if ((apen = fd->fd_BackPen) != (UWORD)~0)
222 if (fd->fd_Flags & FRF_BACKDRI) apen = pens[apen];
224 if ((bpen = fd->fd_BackPen2) == (UWORD)~0)
226 bpen = apen;
228 else
230 if (fd->fd_Flags & FRF_SELDRI2) bpen = pens[bpen];
234 if (sel && (fd->fd_SelPen != (UWORD)~0))
237 * First check for a selected (dri)pen.
238 * If none is given we use the default color.
240 if ((apen = fd->fd_SelPen) != (UWORD)~0)
242 if (fd->fd_Flags & FRF_SELDRI) apen = pens[apen];
244 if ((bpen = fd->fd_SelPen2) == (UWORD)~0)
246 bpen = apen;
248 else
250 if (fd->fd_Flags & FRF_SELDRI2) bpen = pens[bpen];
255 if (apen == (UWORD)~0)
257 switch (fd->fd_Type)
260 * NeXT, DropBox and Ridge frames do not support a SELECTED state
261 * so we force the BACKGROUNDPEN for these types.
263 case FRTYPE_NEXT:
264 case FRTYPE_DROPBOX:
265 case FRTYPE_RIDGE:
266 case FRTYPE_FUZZ_RIDGE:
267 case FRTYPE_RADIOBUTTON:
268 apen = BACKGROUNDPEN;
269 break;
271 default:
273 * Check the state of the frame
275 switch (fdm->fdm_State)
277 case IDS_SELECTED:
278 apen = FILLPEN;
279 break;
280 case IDS_INACTIVESELECTED:
281 case IDS_INACTIVENORMAL:
282 apen = BACKGROUNDPEN;
283 break;
284 default:
286 * And BACKGROUNDPEN for normal frames.
288 apen = ((fd->fd_Flags & FRF_INBORDER) || (fd->fd_Type == FRTYPE_BORDER)) ? FILLPEN : BACKGROUNDPEN;
289 break;
292 apen = bpen = pens[apen];
295 else
297 fill = fd->fd_BackFill;
298 if (fill > FILL_BLOCK) fill = 0;
300 apen = pens[backfill[fill][0]];
301 bpen = pens[backfill[fill][1]];
305 * Fill the frame.
307 RenderBackFillRaster(rp, &ib, apen, bpen);
309 return FRC_OK;
311 return FRC_UNKNOWN;
313 REGFUNC_END
315 /// FRAMEM_BACKFILL
317 * Frame background routine.
319 METHOD(FrameClassBackfill, struct fmBackfill *, fmb)
321 FD *fd = INST_DATA(cl, obj);
322 struct FrameDrawMsg fdraw;
325 * Setup framedraw message.
327 fdraw.fdm_MethodID = FRM_RENDER;
328 fdraw.fdm_RPort = fmb->fmb_BInfo->bi_RPort;
329 fdraw.fdm_DrawInfo = fmb->fmb_BInfo->bi_DrInfo;
330 fdraw.fdm_Bounds = fmb->fmb_Bounds;
331 fdraw.fdm_State = fmb->fmb_State;
334 * Call the custom back-fill hook routine.
335 * Note that this can also be the default backfill hook
336 * which is defined above.
338 BGUI_CallHookPkt(fd->fd_BackFillHook, (VOID *)obj, (VOID *)&fdraw);
340 return 1;
342 METHOD_END
344 #define Line(x1,y1,x2,y2) { Move(rp, x1, y1); Draw(rp, x2, y2); }
345 #define Point(x1,y1) WritePixel(rp, x1, y1)
347 /// RenderRadioFrame
349 * Render the radio button frame
351 STATIC VOID RenderRadioFrame(struct bmRender *bmr, WORD l, WORD t, WORD r, WORD b, FD *fd)
353 struct BaseInfo *bi = bmr->bmr_BInfo;
354 struct RastPort *rp = bi->bi_RPort;
355 WORD array[16], *a;
356 BOOL normal = !(fd->fd_Flags & FRF_RECESSED);
357 BOOL thin = fd->fd_Flags & FRF_THIN_FRAME;
360 * Check if we need to draw a normal or a selected frame
362 switch (bmr->bmr_Flags)
364 case IDS_SELECTED:
365 case IDS_INACTIVESELECTED:
366 normal = !normal;
367 break;
371 * Draw the shine side of the frame
373 a = array;
375 *a++ = l + 2; *a++ = t;
376 *a++ = l; *a++ = t + 2;
377 *a++ = l; *a++ = b - 2;
378 *a++ = l + 2; *a++ = b;
379 *a++ = l + 2; *a++ = b - 1;
382 * Thin lines?
384 if (!thin)
386 *a++ = l + 1; *a++ = b - 2;
387 *a++ = l + 1; *a++ = t + 2;
388 *a++ = l + 2; *a++ = t + 1;
391 BSetDPenA(bi, normal ? SHINEPEN : SHADOWPEN);
392 Move(rp, r - 3, t);
393 PolyDraw(rp, (a - array) >> 1, array);
396 * Draw the shadow side of the frame
398 a = array;
400 *a++ = r - 2; *a++ = b;
401 *a++ = r; *a++ = b - 2;
402 *a++ = r; *a++ = t + 2;
403 *a++ = r - 2; *a++ = t;
404 *a++ = r - 2; *a++ = t + 1;
407 * Thin lines?
409 if (!thin)
411 *a++ = r - 1; *a++ = t + 2;
412 *a++ = r - 1; *a++ = b - 2;
413 *a++ = r - 2; *a++ = b - 1;
416 BSetDPenA(bi, normal ? SHADOWPEN : SHINEPEN);
417 Move(rp, l + 3, b);
418 PolyDraw(rp, (a - array) >> 1, array);
421 /// RenderTabFrame
423 * Render the tab frame.
425 STATIC VOID RenderTabFrame(struct bmRender *bmr, int l0, int t0, int r0, int b0, FD *fd)
427 struct BaseInfo *bi = bmr->bmr_BInfo;
428 struct RastPort *rp = bi->bi_RPort;
430 int l1 = l0 + 1, l2 = l0 + 2, l3 = l0 + 3, l4 = l0 + 4;
431 int r1 = r0 - 1, r2 = r0 - 2, r3 = r0 - 3, r4 = r0 - 4;
432 int t1 = t0 + 1, t2 = t0 + 2, t3 = t0 + 3, t4 = t0 + 4;
433 int b1 = b0 - 1, b2 = b0 - 2, b3 = b0 - 3, b4 = b0 - 4;
435 BOOL sel = ((bmr->bmr_Flags == IDS_SELECTED) || (bmr->bmr_Flags == IDS_INACTIVESELECTED));
436 BOOL thin = fd->fd_Flags & FRF_THIN_FRAME;
438 switch (fd->fd_Type)
440 case FRTYPE_TAB_TOP:
442 * Shine side.
444 BSetDPenA(bi, SHINEPEN);
445 if (sel)
447 Point(l0, b0);
448 Line(l1, t2, l1, b1); if (!thin) Line(l2, t2, l2, b1);
449 Line(l2, t1, l3, t1);
450 Line(l3, t0, r3, t0);
452 else
454 Line(l0, b0, r0, b0);
455 Line(l2, t3, l2, b1); if (!thin) Line(l3, t3, l3, b1);
456 Line(l3, t2, l4, t2);
457 Line(l4, t1, r4, t1);
461 * Shadow side.
463 BSetDPenA(bi, SHADOWPEN);
464 if (sel)
466 Line(r2, t1, r3, t1);
467 Line(r1, t2, r1, b1); if (!thin) Line(r2, t2, r2, b1);
468 Point(r0, b0);
470 else
472 Line(r3, t2, r4, t2);
473 Line(r2, t3, r2, b1); if (!thin) Line(r3, t3, r3, b1);
475 break;
477 case FRTYPE_TAB_BOTTOM:
479 * Shine side.
481 BSetDPenA(bi, SHINEPEN);
482 if (sel)
484 Point(l0, t0);
485 Line(l1, t1, l1, b2); if (!thin) Line(l2, t1, l2, b2);
486 Line(l2, b1, l3, b1);
488 else
490 Line(l2, t1, l2, b3); if (!thin) Line(l3, t1, l3, b3);
491 Line(l3, b2, l4, b2);
495 * Shadow side.
497 BSetDPenA(bi, SHADOWPEN);
498 if (sel)
500 Point(r0, t0);
501 Line(r3, b1, r2, b1);
502 Line(r1, t1, r1, b2); if (!thin) Line(r2, t1, r2, b2);
503 Line(l3, b0, r3, b0);
505 else
507 Line(l0, t0, r0, t0);
508 Line(r4, b2, r3, b2);
509 Line(r2, t1, r2, b3); if (!thin) Line(r3, t1, r3, b3);
510 Line(l4, b1, r4, b1);
512 break;
516 /// RenderXenFrame
518 * Render the XEN button frame.
520 STATIC VOID RenderXenFrame(struct bmRender *bmr, WORD l, WORD t, WORD r, WORD b, FD *fd)
522 struct BaseInfo *bi = bmr->bmr_BInfo;
523 struct RastPort *rp = bi->bi_RPort;
526 * Setup pen for the XEN lines
527 * around the normal button frame.
529 BSetDPenA(bi, SHADOWPEN);
530 BSetDrMd(bi, JAM1);
533 * Move & Render...
535 t++; l++, r--; b--;
537 HLine(rp, l, t - 1, r);
538 VLine(rp, r - 1, t, b);
539 HLine(rp, l, b - 1, r);
540 VLine(rp, l - 1, t, b);
543 * Render bevel.
545 RenderBevelBox(bi, l, t, r, b, bmr->bmr_Flags, fd->fd_Flags & FRF_RECESSED, fd->fd_Flags & FRF_THIN_FRAME);
550 * Pass on the frame thickness.
552 //STATIC ASM VOID FrameThickness(REG(a0) Class *cl, REG(a2) Object *obj)
553 STATIC ASM REGFUNC2(VOID, FrameThickness,
554 REGPARAM(A0, Class *, cl),
555 REGPARAM(A2, Object *, obj))
557 FD *fd = INST_DATA(cl, obj);
558 struct ThicknessMsg tm;
559 UBYTE h, v;
560 int type;
561 BOOL thin;
563 STATIC UBYTE thick[][4] =
565 { 1, 1, 1, 1 }, // FRTYPE_CUSTOM
566 { 2, 1, 1, 1 }, // FRTYPE_BUTTON
567 { 4, 2, 2, 2 }, // FRTYPE_RIDGE
568 { 6, 3, 3, 3 }, // FRTYPE_DROPBOX
569 { 4, 2, 2, 2 }, // FRTYPE_NEXT
570 { 1, 1, 1, 1 }, // FRTYPE_RADIOBUTTON
571 { 3, 2, 2, 2 }, // FRTYPE_XEN_BUTTON
572 { 2, 1, 1, 1 }, // FRTYPE_TAB_ABOVE
573 { 2, 1, 1, 1 }, // FRTYPE_TAB_BELOW
574 { 1, 1, 1, 1 }, // FRTYPE_BORDER
575 { 0, 0, 0, 0 }, // FRTYPE_NONE
576 { 3, 2, 3, 3 }, // FRTYPE_FUZZ_BUTTON
577 { 3, 2, 3, 3 }, // FRTYPE_FUZZ_RIDGE
578 { 6, 2, 5, 2 }, // FRTYPE_TAB_TOP
579 { 6, 2, 5, 2 }, // FRTYPE_TAB_BOTTOM
580 { 2, 6, 2, 5 }, // FRTYPE_TAB_LEFT
581 { 2, 6, 2, 5 }, // FRTYPE_TAB_RIGHT
584 if (!(fd->fd_Flags & FRF_CUST_THICK))
586 thin = fd->fd_Flags & FRF_THIN_FRAME;
589 * Do we have a hook?
591 if (fd->fd_FrameHook)
594 * Yes. Call it to get the thickness
595 * of the custom frame.
597 tm.tm_MethodID = FRM_THICKNESS;
598 tm.tm_Thickness.Horizontal = &h;
599 tm.tm_Thickness.Vertical = &v;
600 tm.tm_Thin = thin;
603 * If this method is not understood
604 * by the hook we use default values.
606 if (BGUI_CallHookPkt(fd->fd_FrameHook, (VOID *)obj, (VOID *)&tm) != FRC_OK)
608 h = v = 1;
611 else
614 * Setup frame thickness of the internal frames.
616 type = fd->fd_Type;
617 if (type > FRTYPE_FUZZ_RIDGE) type = 0;
619 h = thick[type][thin ? 2 : 0];
620 v = thick[type][thin ? 3 : 1];
622 fd->fd_Horizontal = h;
623 fd->fd_Vertical = v;
626 REGFUNC_END
629 * Setup frame attributes.
631 //STATIC ASM VOID SetFrameAttrs(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct TagItem *attr)
632 STATIC ASM REGFUNC3(VOID, SetFrameAttrs,
633 REGPARAM(A0, Class *, cl),
634 REGPARAM(A2, Object *, obj),
635 REGPARAM(A1, struct TagItem *, attr))
637 FD *fd = INST_DATA(cl, obj);
638 struct TextFont *tf;
639 struct TagItem *tstate = attr, *tag;
640 ULONG temp = NULL;
641 Object *ob = NULL;
642 ULONG data;
644 if (tag = FindTagItem(FRM_Template, attr))
646 ob = (Object *)tag->ti_Data;
647 if (ob)
649 Get_Attr(ob, FRM_Template, &temp);
650 if (temp)
652 CopyMem((FD *)temp, fd, sizeof(FD));
653 fd->fd_Flags &= ~FRF_SELFOPEN;
658 BGUI_PackStructureTags((APTR)fd, FramePackTable, attr);
661 * Set attributes.
663 while (tag = NextTagItem(&tstate))
665 data = tag->ti_Data;
667 switch (tag->ti_Tag)
669 case BT_ParentGroup:
670 fd->fd_ParentGroup = (Object *)data;
671 break;
673 case FRM_FrameWidth:
674 case FRM_FrameHeight:
675 fd->fd_Flags |= FRF_CUST_THICK;
676 break;
678 case IMAGE_TextFont:
679 if (fd->fd_Font && (fd->fd_Flags & FRF_SELFOPEN))
680 BGUI_CloseFont(fd->fd_Font);
681 fd->fd_Font = (struct TextFont *)data;
682 fd->fd_Flags &= ~FRF_SELFOPEN;
683 break;
685 case FRM_TextAttr:
686 if (data)
688 if (tf = BGUI_OpenFont((struct TextAttr *)tag->ti_Data))
690 if (fd->fd_Font && (fd->fd_Flags & FRF_SELFOPEN))
691 BGUI_CloseFont(fd->fd_Font);
692 fd->fd_Font = tf;
693 fd->fd_TitleFont = (struct TextAttr *)tag->ti_Data;
694 fd->fd_Flags |= FRF_SELFOPEN;
697 break;
699 case FRM_BackFill:
700 fd->fd_BackFill = data;
701 fd->fd_BackFillHook = NULL;
702 fd->fd_Flags &= ~FRF_EDGES_ONLY;
703 break;
705 case FRM_BackRasterPen:
706 fd->fd_BackPen2 = data;
707 fd->fd_Flags &= ~FRF_BACKDRI2;
708 if (fd->fd_BackPen != (UWORD)~0) break;
709 case FRM_BackPen:
710 fd->fd_BackPen = data;
711 fd->fd_Flags &= ~FRF_BACKDRI;
712 break;
714 case FRM_BackRasterDriPen:
715 fd->fd_BackPen2 = data;
716 fd->fd_Flags |= FRF_BACKDRI2;
717 if (fd->fd_BackPen != (UWORD)~0) break;
718 case FRM_BackDriPen:
719 fd->fd_BackPen = data;
720 fd->fd_Flags |= FRF_BACKDRI;
721 break;
723 case FRM_SelectedBackRasterPen:
724 fd->fd_SelPen2 = data;
725 fd->fd_Flags &= ~FRF_SELDRI2;
726 if (fd->fd_SelPen != (UWORD)~0) break;
727 case FRM_SelectedBackPen:
728 fd->fd_SelPen = data;
729 fd->fd_Flags &= ~FRF_SELDRI;
730 break;
732 case FRM_SelectedBackRasterDriPen:
733 fd->fd_SelPen2 = data;
734 fd->fd_Flags |= FRF_SELDRI2;
735 if (fd->fd_SelPen != (UWORD)~0) break;
736 case FRM_SelectedBackDriPen:
737 fd->fd_SelPen = data;
738 fd->fd_Flags |= FRF_SELDRI;
739 break;
741 case FRM_Title:
742 if (!fd->fd_Title && data)
743 fd->fd_Title = BGUI_NewObject(BGUI_TEXT_GRAPHIC, TEXTA_CopyText, TRUE, TAG_DONE);
744 if (fd->fd_Title)
746 if(data)
747 DoSetMethodNG(fd->fd_Title, TEXTA_Text, data, TAG_DONE);
748 else
750 DisposeObject(fd->fd_Title);
751 fd->fd_Title=NULL;
754 break;
756 case FRM_TitleID:
757 if (!fd->fd_Title) fd->fd_Title = BGUI_NewObject(BGUI_TEXT_GRAPHIC, TEXTA_CopyText, TRUE, TAG_DONE);
758 if (fd->fd_Title) DoSetMethodNG(fd->fd_Title, TEXTA_TextID, data, TAG_DONE);
759 break;
762 * BGUI private!
764 case IMAGE_InBorder:
765 if (data) fd->fd_Flags |= FRF_INBORDER;
766 else fd->fd_Flags &= ~FRF_INBORDER;
767 break;
769 case FRM_Type:
770 case FRM_ThinFrame:
771 case FRM_CustomHook:
772 FrameThickness(cl, obj);
773 break;
778 * Sanity checks.
780 if (fd->fd_FrameHook) fd->fd_Type = FRTYPE_CUSTOM;
781 else if (!fd->fd_Type) fd->fd_Type = FRTYPE_BUTTON;
783 if (fd->fd_BackFillHook == NULL)
784 fd->fd_BackFillHook = &fd->fd_DefBackfill;
786 switch (fd->fd_Type)
788 case FRTYPE_TAB_TOP:
789 case FRTYPE_TAB_BOTTOM:
790 case FRTYPE_TAB_LEFT:
791 case FRTYPE_TAB_RIGHT:
792 fd->fd_Flags |= FRF_FILL_OUTER;
793 break;
794 default:
795 fd->fd_Flags &= ~FRF_FILL_OUTER;
796 break;
799 REGFUNC_END
801 /// OM_NEW
803 * Create a shiny new object.
805 METHOD(FrameClassNew, struct opSet *, ops)
807 FD *fd;
808 ULONG rc;
811 * First we let the superclass
812 * create a new object.
814 if (rc = AsmDoSuperMethodA(cl, obj, (Msg)ops))
817 * Get us the instance data.
819 fd = INST_DATA(cl, rc);
822 * Setup defaults.
824 fd->fd_Type = FRTYPE_BUTTON;
825 fd->fd_BackPen = (UWORD)~0;
826 fd->fd_SelPen = (UWORD)~0;
827 fd->fd_BackPen2 = (UWORD)~0;
828 fd->fd_SelPen2 = (UWORD)~0;
830 fd->fd_DefBackfill.h_Entry = (HOOKFUNC)BuiltInBack;
833 * Setup the object.
835 SetFrameAttrs(cl, (Object *)rc, ops->ops_AttrList);
836 FrameThickness(cl, (Object *)rc);
839 return rc;
841 METHOD_END
843 /// OM_SET
845 * Change one or more attrubutes.
847 METHOD(FrameClassSet, struct opSet *, ops)
849 FD *fd = INST_DATA(cl, obj);
850 ULONG rc;
853 * First we let the superclass
854 * change the attributes it
855 * knows.
857 rc = AsmDoSuperMethodA(cl, obj, (Msg)ops);
860 * Setup attributes.
862 SetFrameAttrs(cl, obj, ops->ops_AttrList);
864 return rc;
866 METHOD_END
868 /// OM_GET
870 * Give an attribute value.
872 METHOD(FrameClassGet, struct opGet *, opg)
874 FD *fd = INST_DATA(cl, obj);
875 ULONG rc = 1, tag = opg->opg_AttrID, *store = opg->opg_Storage;
878 * First we see if the attribute
879 * they want is known to us. If not
880 * we pass it onto the superclass.
882 switch (tag)
884 case FRM_Template:
885 STORE fd;
886 break;
888 case FRM_FrameWidth:
889 STORE fd->fd_Horizontal;
890 break;
891 case FRM_FrameHeight:
892 STORE fd->fd_Vertical;
893 break;
895 case FRM_BackPen:
896 STORE fd->fd_Flags & FRF_BACKDRI ? ~0 : fd->fd_BackPen;
897 break;
898 case FRM_BackDriPen:
899 STORE fd->fd_Flags & FRF_BACKDRI ? fd->fd_BackPen : ~0;
900 break;
901 case FRM_SelectedBackPen:
902 STORE fd->fd_Flags & FRF_SELDRI ? ~0 : fd->fd_SelPen;
903 break;
904 case FRM_SelectedBackDriPen:
905 STORE fd->fd_Flags & FRF_SELDRI ? fd->fd_SelPen : ~0;
906 break;
907 case FRM_BackRasterPen:
908 STORE fd->fd_Flags & FRF_BACKDRI2 ? ~0 : fd->fd_BackPen2;
909 break;
910 case FRM_BackRasterDriPen:
911 STORE fd->fd_Flags & FRF_BACKDRI2 ? fd->fd_BackPen2 : ~0;
912 break;
913 case FRM_SelectedBackRasterPen:
914 STORE fd->fd_Flags & FRF_SELDRI2 ? ~0 : fd->fd_SelPen2;
915 break;
916 case FRM_SelectedBackRasterDriPen:
917 STORE fd->fd_Flags & FRF_SELDRI2 ? fd->fd_SelPen2 : ~0;
918 break;
920 default:
921 rc = BGUI_UnpackStructureTag((UBYTE *)fd, FramePackTable, tag, store);
922 if (!rc) rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
923 break;
925 return rc;
927 METHOD_END
929 /// OM_DISPOSE
931 * Dispose of the object.
933 METHOD(FrameClassDispose, Msg, msg)
935 FD *fd = INST_DATA(cl, obj);
938 * Close the font.
940 if (fd->fd_Font && (fd->fd_Flags & FRF_SELFOPEN))
941 BGUI_CloseFont(fd->fd_Font);
944 * Dispose of the text graphic.
946 if (fd->fd_Title) DisposeObject(fd->fd_Title);
949 * The rest goes to the superclass.
951 return AsmDoSuperMethodA(cl, obj, msg);
953 METHOD_END
955 /// FRAMEM_SETUPBOUNDS
957 METHOD(FrameClassSetupBounds, struct fmSetupBounds *, fmsb)
959 FD *fd = INST_DATA(cl, obj);
960 struct IBox *hb = fmsb->fmsb_HitBox;
961 struct IBox *ib = fmsb->fmsb_InnerBox;
962 int ox1 = fd->fd_OuterX1;
963 int ox2 = fd->fd_OuterX2;
964 int oy1 = fd->fd_OuterY1;
965 int oy2 = fd->fd_OuterY2;
967 hb->Left += ox1;
968 hb->Top += oy1;
969 hb->Width -= ox1 + ox2;
970 hb->Height -= oy1 + oy2;
972 ox1 += fd->fd_InnerX1 + fd->fd_Horizontal;
973 ox2 += fd->fd_InnerX2 + fd->fd_Horizontal;
974 oy1 += fd->fd_InnerY1 + fd->fd_Vertical;
975 oy2 += fd->fd_InnerY2 + fd->fd_Vertical;
977 if (fd->fd_Title)
979 if (fd->fd_Font) oy1 += fd->fd_Font->tf_YSize;
980 else if (fd->fd_TitleFont) oy1 += fd->fd_TitleFont->ta_YSize;
983 ib->Left += ox1;
984 ib->Top += oy1;
985 ib->Width -= ox1 + ox2;
986 ib->Height -= oy1 + oy2;
988 SetImageBounds(obj, fmsb->fmsb_HitBox);
990 return 1;
992 METHOD_END
994 /// BASE_DIMENSIONS
996 METHOD(FrameClassDimensions, struct bmDimensions *, bmd)
998 FD *fd = INST_DATA(cl, obj);
999 struct bguiExtent *be = bmd->bmd_Extent;
1000 int ox = (fd->fd_Horizontal << 1) + fd->fd_InnerX1 + fd->fd_InnerX2;
1001 int oy = (fd->fd_Vertical << 1) + fd->fd_InnerY1 + fd->fd_InnerY2;
1003 if (fd->fd_Title)
1005 if (fd->fd_Font) oy += fd->fd_Font->tf_YSize;
1006 else if (fd->fd_TitleFont) oy += fd->fd_TitleFont->ta_YSize;
1009 be->be_Min.Width += ox;
1010 be->be_Min.Height += oy;
1012 be->be_Nom.Width += ox;
1013 be->be_Nom.Height += oy;
1015 return 1;
1017 METHOD_END
1019 /// BASE_RENDER
1021 * Render the frame.
1023 METHOD(FrameClassRender, struct bmRender *, bmr)
1025 FD *fd = INST_DATA(cl, obj);
1026 struct BaseInfo *bi = bmr->bmr_BInfo;
1027 struct RastPort *rp = bi->bi_RPort;
1028 struct Rectangle rect;
1029 struct FrameDrawMsg fdraw;
1030 WORD l, t, r, b, place;
1031 ULONG rc = 1;
1032 int tv, th, dv, dh, shadow, shine, tmp, tmp2;
1033 int state = bmr->bmr_Flags;
1034 int i_fuzz, i_blank, i_swap, i_mix;
1035 Object *fr;
1037 static UWORD pat[] = { 0x5555, 0xAAAA };
1039 static BYTE taboff[4][4][2] =
1041 { { 3, 2 }, { 3, 2 }, { 2, 1 }, { 0, 0 } },
1042 { { 3, 2 }, { 3, 2 }, { 0, 0 }, { 2, 1 } },
1043 { { 2, 1 }, { 0, 0 }, { 3, 2 }, { 3, 2 } },
1044 { { 0, 0 }, { 2, 1 }, { 3, 2 }, { 3, 2 } },
1047 BSetDrMd(bi, JAM2);
1050 * Calculate the frame position and dimensions
1052 l = IMAGE(obj)->LeftEdge;
1053 t = IMAGE(obj)->TopEdge;
1054 r = IMAGE(obj)->Width + l - 1;
1055 b = IMAGE(obj)->Height + t - 1;
1057 if (fd->fd_Title)
1060 * Setup the font if one is present.
1062 if (fd->fd_Font) BSetFont(bi, fd->fd_Font);
1065 * Adjust top position if there is a title present.
1067 if (fd->fd_Flags & FRF_CENTER_TITLE)
1068 t += (rp->TxBaseline - (rp->TxHeight >> 1));
1069 else
1070 t += rp->TxBaseline;
1073 rect.MinX = l;
1074 rect.MinY = t;
1075 rect.MaxX = r;
1076 rect.MaxY = b;
1078 * First we do the background.
1080 * When this is a FRF_EDGES_ONLY frame we do nothing.
1081 * No hooks are called, and nothing is filled.
1083 if (!(fd->fd_Flags & FRF_EDGES_ONLY))
1085 if (fd->fd_Flags & FRF_FILL_OUTER)
1087 if (fr = fd->fd_ParentGroup ? BASE_DATA(fd->fd_ParentGroup)->bc_Frame : NULL)
1089 AsmDoMethod(fr, FRAMEM_BACKFILL, bi, &rect, IDS_NORMAL);
1091 else
1093 BSetDPenA(bi, BACKGROUNDPEN);
1094 BRectFillA(bi, &rect);
1096 tmp = fd->fd_Type - FRTYPE_TAB_TOP;
1097 tmp2 = ((state == IDS_SELECTED) || (state == IDS_SELECTED)) ? 1 : 0;
1099 rect.MinX += taboff[tmp][0][tmp2];
1100 rect.MaxX -= taboff[tmp][1][tmp2];
1101 rect.MinY += taboff[tmp][2][tmp2];
1102 rect.MaxY -= taboff[tmp][3][tmp2];
1104 state = IDS_NORMAL;
1106 AsmDoMethod(obj, FRAMEM_BACKFILL, bi, &rect, state);
1110 * Get frame thickness.
1112 th = fd->fd_Horizontal;
1113 tv = fd->fd_Vertical;
1115 if ((th << 1) > (r - l + 1)) th = (r - l + 1) >> 1;
1116 if ((tv << 1) > (b - t + 1)) tv = (b - t + 1) >> 1;
1119 * Draw the frame (whatever type it is)
1121 state = bmr->bmr_Flags;
1124 * Selected or normal?
1126 switch (state)
1128 case IDS_SELECTED:
1129 case IDS_INACTIVESELECTED:
1130 shadow = SHINEPEN;
1131 shine = SHADOWPEN;
1132 break;
1134 default:
1135 shadow = SHADOWPEN;
1136 shine = SHINEPEN;
1137 break;
1141 * Swap pens if we must
1142 * recess the frame.
1144 if (fd->fd_Flags & FRF_RECESSED)
1146 tmp = shadow;
1147 shadow = shine;
1148 shine = tmp;
1151 if(th>0
1152 && tv>0)
1154 switch (fd->fd_Type)
1156 case FRTYPE_CUSTOM:
1158 * Fill in the data structures for the custom frame hook
1160 fdraw.fdm_MethodID = FRM_RENDER;
1161 fdraw.fdm_RPort = rp;
1162 fdraw.fdm_DrawInfo = bi->bi_DrInfo;
1163 fdraw.fdm_Bounds = &rect;
1164 fdraw.fdm_State = state;
1165 fdraw.fdm_Horizontal = th;
1166 fdraw.fdm_Vertical = tv;
1168 * Call the hook routine.
1170 rc = BGUI_CallHookPkt(fd->fd_FrameHook, (VOID *)obj, (VOID *)&fdraw);
1171 break;
1173 case FRTYPE_RIDGE:
1174 case FRTYPE_NEXT:
1175 case FRTYPE_DROPBOX:
1176 case FRTYPE_FUZZ_BUTTON:
1177 case FRTYPE_FUZZ_RIDGE:
1178 case FRTYPE_BUTTON:
1179 i_fuzz = -1;
1180 i_blank = -1;
1181 i_swap = -1;
1182 i_mix = -1;
1184 dv = (tv + th - 1) / th; if (dv < 1) dv = 1;
1185 dh = (th + tv - 1) / tv; if (dh < 1) dh = 1;
1187 if (fd->fd_Type == FRTYPE_FUZZ_BUTTON)
1190 * 1/4 Normal, 3/4 Raster
1192 i_fuzz = (tv / dv) / 4;
1194 if (fd->fd_Type == FRTYPE_FUZZ_RIDGE)
1197 * 1/3 Normal, 1/3 Blank, 1/3 Recessed
1199 tmp = shine;
1200 tmp2 = shadow;
1201 i_mix = (tv / dv) / 3 - 1;
1202 i_swap = (2 * tv / dv) / 3 - 1;
1204 if (fd->fd_Type == FRTYPE_DROPBOX)
1207 * 1/3 Normal, 1/3 Blank, 1/3 Recessed
1209 tmp = shine;
1210 tmp2 = shadow;
1211 i_blank = (tv / dv) / 3 - 1;
1212 i_swap = (2 * tv / dv) / 3 - 1;
1214 if (fd->fd_Type == FRTYPE_NEXT)
1217 * 1/2 Recessed, 1/2 Normal
1219 tmp2 = shine;
1220 tmp = shadow;
1221 shine = tmp;
1222 shadow = tmp2;
1223 i_swap = (tv / dv) / 2 - 1;
1225 if (fd->fd_Type == FRTYPE_RIDGE)
1228 * 1/2 Normal, 1/2 Recessed
1230 tmp = shine;
1231 tmp2 = shadow;
1232 i_swap = (tv / dv) / 2 - 1;
1236 * Render the bevelbox.
1238 while ((tv > 0) && (th > 0))
1240 if (shine >= 0) BSetDPenA(bi, shine);
1241 if(dh>0
1242 && t<=b)
1243 BRectFill(bi, l, t, l + dh - 1, b); l += dh;
1244 if (shadow >= 0) BSetDPenA(bi, shadow);
1245 if(dv>0
1246 && l<=r)
1247 BRectFill(bi, l, b - dv + 1, r, b); b -= dv;
1248 if(dh>0
1249 && t<=b)
1250 BRectFill(bi, r - dh + 1, t, r, b); r -= dh;
1251 if (shine >= 0) BSetDPenA(bi, shine);
1252 if(dv>0
1253 && l<=r)
1254 BRectFill(bi, l, t, r, t + dv - 1); t += dv;
1255 tv -= dv;
1256 th -= dh;
1258 if (i_fuzz-- == 0)
1260 BSetAfPt(bi, pat, 1);
1262 if (i_blank-- == 0)
1264 shine = BACKGROUNDPEN;
1265 shadow = BACKGROUNDPEN;
1267 if (i_swap-- == 0)
1269 BClearAfPt(bi);
1270 shine = tmp2;
1271 shadow = tmp;
1273 if (i_mix-- == 0)
1275 BSetAfPt(bi, pat, 1);
1276 BSetDPenA(bi, shine);
1277 BSetDPenB(bi, shadow);
1278 shine = shadow = -1;
1281 if (tv > 0)
1283 BSetDPenA(bi, shine);
1284 BRectFill(bi, l, t, r, t + tv - 1);
1285 BSetDPenA(bi, shadow);
1286 BRectFill(bi, l, b - tv + 1, r, b);
1288 if (th > 0)
1290 BSetDPenA(bi, shine);
1291 BRectFill(bi, l, t, l + th - 1, b);
1292 BSetDPenA(bi, shadow);
1293 BRectFill(bi, r - th + 1, t, r, b);
1295 break;
1297 case FRTYPE_RADIOBUTTON:
1298 RenderRadioFrame(bmr, l, t, r, b, fd);
1299 break;
1301 case FRTYPE_XEN_BUTTON:
1302 RenderXenFrame(bmr, l, t, r, b, fd);
1303 break;
1305 case FRTYPE_TAB_TOP:
1306 case FRTYPE_TAB_BOTTOM:
1307 case FRTYPE_TAB_LEFT:
1308 case FRTYPE_TAB_RIGHT:
1309 RenderTabFrame(bmr, l, t, r, b, fd);
1310 break;
1312 case FRTYPE_TAB_ABOVE:
1314 * Render the frame.
1316 BSetDPenA(bi, shine);
1317 BRectFill(bi, l, t, l + th - 1, b - tv);
1318 BSetDPenA(bi, shadow);
1319 BRectFill(bi, l + 1, b - tv + 1, r, b);
1320 BRectFill(bi, r - th + 1, t, r, b);
1321 break;
1323 case FRTYPE_TAB_BELOW:
1325 * Render the frame.
1327 BSetDPenA(bi, shine);
1328 BRectFill(bi, l, t, l + th - 1, b - tv + 1);
1329 BRectFill(bi, l, t, r - th + 1, t + tv - 1);
1330 BSetDPenA(bi, shadow);
1331 BRectFill(bi, r - th + 1, t, r, b);
1332 break;
1334 case FRTYPE_BORDER:
1336 * Render the borderbox.
1338 RenderBevelBox(bi, l, t, r, b, state, fd->fd_Flags & FRF_RECESSED, TRUE);
1339 break;
1341 case FRTYPE_NONE:
1342 break;
1347 * Render frame the title.
1349 if (fd->fd_Title)
1351 place = 0;
1354 * Left or right?
1356 if (fd->fd_Flags & FRF_TITLE_LEFT ) place = 1;
1357 else if (fd->fd_Flags & FRF_TITLE_RIGHT) place = 2;
1360 * Render the title.
1362 RenderTitle(fd->fd_Title, bi, l, t, r - l + 1,
1363 fd->fd_Flags & FRF_HIGHLIGHT_TITLE, fd->fd_Flags & FRF_CENTER_TITLE, place);
1367 return rc;
1369 METHOD_END
1371 /// BASE_LOCALIZE
1373 METHOD(FrameClassLocalize, struct bmLocalize *, bml)
1375 FD *fd = INST_DATA(cl, obj);
1376 ULONG rc = 0;
1378 if (fd->fd_Title) rc = AsmDoMethodA(fd->fd_Title, (Msg)bml);
1380 return rc;
1382 METHOD_END
1384 /// Class initialization.
1387 * Class function table.
1389 STATIC DPFUNC ClassFunc[] = {
1390 BASE_RENDER, (FUNCPTR)FrameClassRender,
1391 BASE_DIMENSIONS, (FUNCPTR)FrameClassDimensions,
1392 FRAMEM_BACKFILL, (FUNCPTR)FrameClassBackfill,
1393 FRAMEM_SETUPBOUNDS, (FUNCPTR)FrameClassSetupBounds,
1394 OM_SET, (FUNCPTR)FrameClassSet,
1395 OM_GET, (FUNCPTR)FrameClassGet,
1396 OM_NEW, (FUNCPTR)FrameClassNew,
1397 OM_DISPOSE, (FUNCPTR)FrameClassDispose,
1398 BASE_LOCALIZE, (FUNCPTR)FrameClassLocalize,
1399 DF_END, NULL
1403 * Simple class initialization.
1405 makeproto Class *InitFrameClass(void)
1407 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_IMAGE_OBJECT,
1408 CLASS_ObjectSize, sizeof(FD),
1409 CLASS_DFTable, ClassFunc,
1410 TAG_DONE);