Fix for a crash which happened when a document couldn't be opened.
[AROS-Contrib.git] / bgui / frameclass.c
blob71f94262836e06f3ed11d55c198c3232c4504897
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_Type, fd_Type, PKCTRL_UWORD),
118 FD_ENTRY(FRM_BackFill, fd_BackFill, PKCTRL_UWORD),
120 FD_ENTRY(FRM_FrameWidth, fd_Horizontal, PKCTRL_UBYTE),
121 FD_ENTRY(FRM_FrameHeight, fd_Vertical, PKCTRL_UBYTE),
122 FD_ENTRY(FRM_OuterOffsetLeft, fd_OuterX1, PKCTRL_BYTE),
123 FD_ENTRY(FRM_OuterOffsetRight, fd_OuterX2, PKCTRL_BYTE),
124 FD_ENTRY(FRM_OuterOffsetTop, fd_OuterY1, PKCTRL_BYTE),
125 FD_ENTRY(FRM_OuterOffsetBottom, fd_OuterY2, PKCTRL_BYTE),
126 FD_ENTRY(FRM_InnerOffsetLeft, fd_InnerX1, PKCTRL_BYTE),
127 FD_ENTRY(FRM_InnerOffsetRight, fd_InnerX2, PKCTRL_BYTE),
128 FD_ENTRY(FRM_InnerOffsetTop, fd_InnerY1, PKCTRL_BYTE),
129 FD_ENTRY(FRM_InnerOffsetBottom, fd_InnerY2, PKCTRL_BYTE),
131 FD_FLAG(FRM_EdgesOnly, FRF_EDGES_ONLY),
132 FD_FLAG(FRM_Recessed, FRF_RECESSED),
133 FD_FLAG(FRM_CenterTitle, FRF_CENTER_TITLE),
134 FD_FLAG(FRM_HighlightTitle, FRF_HIGHLIGHT_TITLE),
135 FD_FLAG(FRM_ThinFrame, FRF_THIN_FRAME),
136 FD_FLAG(FRM_TitleLeft, FRF_TITLE_LEFT),
137 FD_FLAG(FRM_TitleRight, FRF_TITLE_RIGHT),
139 PACK_ENDTABLE
144 * Built-in background hook. This hook will take
145 * care of the backfilling rasters and the special
146 * backfilling pens.
148 //STATIC SAVEDS ASM BuiltInBack(REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct FrameDrawMsg *fdm)
149 STATIC SAVEDS ASM REGFUNC3(IPTR, BuiltInBack,
150 REGPARAM(A0, struct Hook *, hook),
151 REGPARAM(A2, Object *, obj),
152 REGPARAM(A1, struct FrameDrawMsg *, fdm))
154 FD *fd = INST_DATA(OCLASS(obj), obj);
155 UWORD *pens = PENS(fdm->fdm_DrawInfo), apen, bpen = 0;
156 struct RastPort *rp = fdm->fdm_RPort;
157 struct IBox ib;
158 struct bguiPattern *pat;
160 int fill;
162 int x1 = fdm->fdm_Bounds->MinX;
163 int x2 = fdm->fdm_Bounds->MaxX;
164 int y1 = fdm->fdm_Bounds->MinY;
165 int y2 = fdm->fdm_Bounds->MaxY;
167 BOOL sel = ((fdm->fdm_State == IDS_SELECTED) || (fdm->fdm_State == IDS_INACTIVESELECTED));
169 STATIC UBYTE backfill[][2] =
171 { BACKGROUNDPEN, BACKGROUNDPEN }, // STANDARD_FILL
172 { SHINEPEN, BACKGROUNDPEN }, // SHINE_RASTER
173 { SHADOWPEN, BACKGROUNDPEN }, // SHADOW_RASTER
174 { SHINEPEN, SHADOWPEN }, // SHINE_SHADOW_RASTER
175 { FILLPEN, BACKGROUNDPEN }, // FILL_RASTER
176 { SHINEPEN, FILLPEN }, // SHINE_FILL_RASTER
177 { SHADOWPEN, FILLPEN }, // SHADOW_FILL_RASTER
178 { SHINEPEN, SHINEPEN }, // SHINE_BLOCK
179 { SHADOWPEN, SHADOWPEN }, // SHADOW_BLOCK
180 { FILLPEN, FILLPEN }, // FILL_BLOCK
184 * Render the backfill?
186 if (fdm->fdm_MethodID == FRM_RENDER)
189 * Setup domain.
191 ib.Left = x1;
192 ib.Top = y1;
193 ib.Width = x2 - x1 + 1;
194 ib.Height = y2 - y1 + 1;
196 pat = fd->fd_Pattern;
197 if (sel && !pat) pat = fd->fd_SelPattern;
199 if (pat)
201 BGUI_FillRectPattern(rp, pat, x1, y1, x2, y2);
202 return FRC_OK;
205 if (fd->fd_BackFill == STANDARD_FILL)
208 * A raster backfill. Set up the pens.
212 * First check for a normal (dri)pen.
213 * If none is given we use the default color.
215 if ((apen = fd->fd_BackPen) != (UWORD)~0)
217 if (fd->fd_Flags & FRF_BACKDRI) apen = pens[apen];
219 if ((bpen = fd->fd_BackPen2) == (UWORD)~0)
221 bpen = apen;
223 else
225 if (fd->fd_Flags & FRF_SELDRI2) bpen = pens[bpen];
229 if (sel && (fd->fd_SelPen != (UWORD)~0))
232 * First check for a selected (dri)pen.
233 * If none is given we use the default color.
235 if ((apen = fd->fd_SelPen) != (UWORD)~0)
237 if (fd->fd_Flags & FRF_SELDRI) apen = pens[apen];
239 if ((bpen = fd->fd_SelPen2) == (UWORD)~0)
241 bpen = apen;
243 else
245 if (fd->fd_Flags & FRF_SELDRI2) bpen = pens[bpen];
250 if (apen == (UWORD)~0)
252 switch (fd->fd_Type)
255 * NeXT, DropBox and Ridge frames do not support a SELECTED state
256 * so we force the BACKGROUNDPEN for these types.
258 case FRTYPE_NEXT:
259 case FRTYPE_DROPBOX:
260 case FRTYPE_RIDGE:
261 case FRTYPE_FUZZ_RIDGE:
262 case FRTYPE_RADIOBUTTON:
263 apen = BACKGROUNDPEN;
264 break;
266 default:
268 * Check the state of the frame
270 switch (fdm->fdm_State)
272 case IDS_SELECTED:
273 apen = FILLPEN;
274 break;
275 case IDS_INACTIVESELECTED:
276 case IDS_INACTIVENORMAL:
277 apen = BACKGROUNDPEN;
278 break;
279 default:
281 * And BACKGROUNDPEN for normal frames.
283 apen = ((fd->fd_Flags & FRF_INBORDER) || (fd->fd_Type == FRTYPE_BORDER)) ? FILLPEN : BACKGROUNDPEN;
284 break;
287 apen = bpen = pens[apen];
290 else
292 fill = fd->fd_BackFill;
293 if (fill > FILL_BLOCK) fill = 0;
295 apen = pens[backfill[fill][0]];
296 bpen = pens[backfill[fill][1]];
300 * Fill the frame.
302 RenderBackFillRaster(rp, &ib, apen, bpen);
304 return FRC_OK;
306 return FRC_UNKNOWN;
308 REGFUNC_END
310 /// FRAMEM_BACKFILL
312 * Frame background routine.
314 METHOD(FrameClassBackfill, struct fmBackfill *, fmb)
316 FD *fd = INST_DATA(cl, obj);
317 struct FrameDrawMsg fdraw;
320 * Setup framedraw message.
322 fdraw.fdm_MethodID = FRM_RENDER;
323 fdraw.fdm_RPort = fmb->fmb_BInfo->bi_RPort;
324 fdraw.fdm_DrawInfo = fmb->fmb_BInfo->bi_DrInfo;
325 fdraw.fdm_Bounds = fmb->fmb_Bounds;
326 fdraw.fdm_State = fmb->fmb_State;
329 * Call the custom back-fill hook routine.
330 * Note that this can also be the default backfill hook
331 * which is defined above.
333 BGUI_CallHookPkt(fd->fd_BackFillHook, (VOID *)obj, (VOID *)&fdraw);
335 return 1;
337 METHOD_END
339 #define Line(x1,y1,x2,y2) { Move(rp, x1, y1); Draw(rp, x2, y2); }
340 #define Point(x1,y1) WritePixel(rp, x1, y1)
342 /// RenderRadioFrame
344 * Render the radio button frame
346 STATIC VOID RenderRadioFrame(struct bmRender *bmr, WORD l, WORD t, WORD r, WORD b, FD *fd)
348 struct BaseInfo *bi = bmr->bmr_BInfo;
349 struct RastPort *rp = bi->bi_RPort;
350 WORD array[16], *a;
351 BOOL normal = !(fd->fd_Flags & FRF_RECESSED);
352 BOOL thin = fd->fd_Flags & FRF_THIN_FRAME;
355 * Check if we need to draw a normal or a selected frame
357 switch (bmr->bmr_Flags)
359 case IDS_SELECTED:
360 case IDS_INACTIVESELECTED:
361 normal = !normal;
362 break;
366 * Draw the shine side of the frame
368 a = array;
370 *a++ = l + 2; *a++ = t;
371 *a++ = l; *a++ = t + 2;
372 *a++ = l; *a++ = b - 2;
373 *a++ = l + 2; *a++ = b;
374 *a++ = l + 2; *a++ = b - 1;
377 * Thin lines?
379 if (!thin)
381 *a++ = l + 1; *a++ = b - 2;
382 *a++ = l + 1; *a++ = t + 2;
383 *a++ = l + 2; *a++ = t + 1;
386 BSetDPenA(bi, normal ? SHINEPEN : SHADOWPEN);
387 Move(rp, r - 3, t);
388 PolyDraw(rp, (a - array) >> 1, array);
391 * Draw the shadow side of the frame
393 a = array;
395 *a++ = r - 2; *a++ = b;
396 *a++ = r; *a++ = b - 2;
397 *a++ = r; *a++ = t + 2;
398 *a++ = r - 2; *a++ = t;
399 *a++ = r - 2; *a++ = t + 1;
402 * Thin lines?
404 if (!thin)
406 *a++ = r - 1; *a++ = t + 2;
407 *a++ = r - 1; *a++ = b - 2;
408 *a++ = r - 2; *a++ = b - 1;
411 BSetDPenA(bi, normal ? SHADOWPEN : SHINEPEN);
412 Move(rp, l + 3, b);
413 PolyDraw(rp, (a - array) >> 1, array);
416 /// RenderTabFrame
418 * Render the tab frame.
420 STATIC VOID RenderTabFrame(struct bmRender *bmr, int l0, int t0, int r0, int b0, FD *fd)
422 struct BaseInfo *bi = bmr->bmr_BInfo;
423 struct RastPort *rp = bi->bi_RPort;
425 int l1 = l0 + 1, l2 = l0 + 2, l3 = l0 + 3, l4 = l0 + 4;
426 int r1 = r0 - 1, r2 = r0 - 2, r3 = r0 - 3, r4 = r0 - 4;
427 int t1 = t0 + 1, t2 = t0 + 2, t3 = t0 + 3; //, t4 = t0 + 4;
428 int b1 = b0 - 1, b2 = b0 - 2, b3 = b0 - 3; //, b4 = b0 - 4;
430 BOOL sel = ((bmr->bmr_Flags == IDS_SELECTED) || (bmr->bmr_Flags == IDS_INACTIVESELECTED));
431 BOOL thin = fd->fd_Flags & FRF_THIN_FRAME;
433 switch (fd->fd_Type)
435 case FRTYPE_TAB_TOP:
437 * Shine side.
439 BSetDPenA(bi, SHINEPEN);
440 if (sel)
442 Point(l0, b0);
443 Line(l1, t2, l1, b1); if (!thin) Line(l2, t2, l2, b1);
444 Line(l2, t1, l3, t1);
445 Line(l3, t0, r3, t0);
447 else
449 Line(l0, b0, r0, b0);
450 Line(l2, t3, l2, b1); if (!thin) Line(l3, t3, l3, b1);
451 Line(l3, t2, l4, t2);
452 Line(l4, t1, r4, t1);
456 * Shadow side.
458 BSetDPenA(bi, SHADOWPEN);
459 if (sel)
461 Line(r2, t1, r3, t1);
462 Line(r1, t2, r1, b1); if (!thin) Line(r2, t2, r2, b1);
463 Point(r0, b0);
465 else
467 Line(r3, t2, r4, t2);
468 Line(r2, t3, r2, b1); if (!thin) Line(r3, t3, r3, b1);
470 break;
472 case FRTYPE_TAB_BOTTOM:
474 * Shine side.
476 BSetDPenA(bi, SHINEPEN);
477 if (sel)
479 Point(l0, t0);
480 Line(l1, t1, l1, b2); if (!thin) Line(l2, t1, l2, b2);
481 Line(l2, b1, l3, b1);
483 else
485 Line(l2, t1, l2, b3); if (!thin) Line(l3, t1, l3, b3);
486 Line(l3, b2, l4, b2);
490 * Shadow side.
492 BSetDPenA(bi, SHADOWPEN);
493 if (sel)
495 Point(r0, t0);
496 Line(r3, b1, r2, b1);
497 Line(r1, t1, r1, b2); if (!thin) Line(r2, t1, r2, b2);
498 Line(l3, b0, r3, b0);
500 else
502 Line(l0, t0, r0, t0);
503 Line(r4, b2, r3, b2);
504 Line(r2, t1, r2, b3); if (!thin) Line(r3, t1, r3, b3);
505 Line(l4, b1, r4, b1);
507 break;
511 /// RenderXenFrame
513 * Render the XEN button frame.
515 STATIC VOID RenderXenFrame(struct bmRender *bmr, WORD l, WORD t, WORD r, WORD b, FD *fd)
517 struct BaseInfo *bi = bmr->bmr_BInfo;
518 struct RastPort *rp = bi->bi_RPort;
521 * Setup pen for the XEN lines
522 * around the normal button frame.
524 BSetDPenA(bi, SHADOWPEN);
525 BSetDrMd(bi, JAM1);
528 * Move & Render...
530 t++; l++, r--; b--;
532 HLine(rp, l, t - 1, r);
533 VLine(rp, r - 1, t, b);
534 HLine(rp, l, b - 1, r);
535 VLine(rp, l - 1, t, b);
538 * Render bevel.
540 RenderBevelBox(bi, l, t, r, b, bmr->bmr_Flags, fd->fd_Flags & FRF_RECESSED, fd->fd_Flags & FRF_THIN_FRAME);
545 * Pass on the frame thickness.
547 STATIC ASM VOID FrameThickness(REG(a0) Class *cl, REG(a2) Object *obj)
549 FD *fd = INST_DATA(cl, obj);
550 struct ThicknessMsg tm;
551 UBYTE h, v;
552 int type;
553 BOOL thin;
555 STATIC UBYTE thick[][4] =
557 { 1, 1, 1, 1 }, // FRTYPE_CUSTOM
558 { 2, 1, 1, 1 }, // FRTYPE_BUTTON
559 { 4, 2, 2, 2 }, // FRTYPE_RIDGE
560 { 6, 3, 3, 3 }, // FRTYPE_DROPBOX
561 { 4, 2, 2, 2 }, // FRTYPE_NEXT
562 { 1, 1, 1, 1 }, // FRTYPE_RADIOBUTTON
563 { 3, 2, 2, 2 }, // FRTYPE_XEN_BUTTON
564 { 2, 1, 1, 1 }, // FRTYPE_TAB_ABOVE
565 { 2, 1, 1, 1 }, // FRTYPE_TAB_BELOW
566 { 1, 1, 1, 1 }, // FRTYPE_BORDER
567 { 0, 0, 0, 0 }, // FRTYPE_NONE
568 { 3, 2, 3, 3 }, // FRTYPE_FUZZ_BUTTON
569 { 3, 2, 3, 3 }, // FRTYPE_FUZZ_RIDGE
570 { 6, 2, 5, 2 }, // FRTYPE_TAB_TOP
571 { 6, 2, 5, 2 }, // FRTYPE_TAB_BOTTOM
572 { 2, 6, 2, 5 }, // FRTYPE_TAB_LEFT
573 { 2, 6, 2, 5 }, // FRTYPE_TAB_RIGHT
576 if (!(fd->fd_Flags & FRF_CUST_THICK))
578 thin = fd->fd_Flags & FRF_THIN_FRAME;
581 * Do we have a hook?
583 if (fd->fd_FrameHook)
586 * Yes. Call it to get the thickness
587 * of the custom frame.
589 tm.tm_MethodID = FRM_THICKNESS;
590 tm.tm_Thickness.Horizontal = &h;
591 tm.tm_Thickness.Vertical = &v;
592 tm.tm_Thin = thin;
595 * If this method is not understood
596 * by the hook we use default values.
598 if (BGUI_CallHookPkt(fd->fd_FrameHook, (VOID *)obj, (VOID *)&tm) != FRC_OK)
600 h = v = 1;
603 else
606 * Setup frame thickness of the internal frames.
608 type = fd->fd_Type;
609 if (type > FRTYPE_FUZZ_RIDGE) type = 0;
611 h = thick[type][thin ? 2 : 0];
612 v = thick[type][thin ? 3 : 1];
614 fd->fd_Horizontal = h;
615 fd->fd_Vertical = v;
620 * Setup frame attributes.
622 STATIC ASM VOID SetFrameAttrs(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct TagItem *attr)
624 FD *fd = INST_DATA(cl, obj);
625 struct TextFont *tf;
626 IPTR temp = (IPTR)NULL;
627 struct TagItem *tstate = attr;
628 struct TagItem *tag;
629 Object *ob = NULL;
630 IPTR data;
632 if ((tag = FindTagItem(FRM_Template, attr)))
634 ob = (Object *)tag->ti_Data;
635 if (ob)
637 Get_Attr(ob, FRM_Template, &temp);
638 if (temp)
640 CopyMem((FD *)temp, fd, sizeof(FD));
641 fd->fd_Flags &= ~FRF_SELFOPEN;
646 BGUI_PackStructureTags((APTR)fd, FramePackTable, attr);
649 * Set attributes.
651 while ((tag = NextTagItem(&tstate)))
653 data = tag->ti_Data;
655 switch (tag->ti_Tag)
657 case BT_ParentGroup:
658 fd->fd_ParentGroup = (Object *)data;
659 break;
661 case FRM_FrameWidth:
662 case FRM_FrameHeight:
663 fd->fd_Flags |= FRF_CUST_THICK;
664 break;
666 case IMAGE_TextFont:
667 if (fd->fd_Font && (fd->fd_Flags & FRF_SELFOPEN))
668 BGUI_CloseFont(fd->fd_Font);
669 fd->fd_Font = (struct TextFont *)data;
670 fd->fd_Flags &= ~FRF_SELFOPEN;
671 break;
673 case FRM_TextAttr:
674 if (data)
676 if ((tf = BGUI_OpenFont((struct TextAttr *)data)))
678 if (fd->fd_Font && (fd->fd_Flags & FRF_SELFOPEN))
679 BGUI_CloseFont(fd->fd_Font);
680 fd->fd_Font = tf;
681 fd->fd_TitleFont = (struct TextAttr *)data;
682 fd->fd_Flags |= FRF_SELFOPEN;
685 break;
687 case FRM_BackFill:
688 fd->fd_BackFill = data;
689 fd->fd_BackFillHook = NULL;
690 fd->fd_Flags &= ~FRF_EDGES_ONLY;
691 break;
693 case FRM_BackRasterPen:
694 fd->fd_BackPen2 = data;
695 fd->fd_Flags &= ~FRF_BACKDRI2;
696 if (fd->fd_BackPen != (UWORD)~0) break;
697 case FRM_BackPen:
698 fd->fd_BackPen = data;
699 fd->fd_Flags &= ~FRF_BACKDRI;
700 break;
702 case FRM_BackRasterDriPen:
703 fd->fd_BackPen2 = data;
704 fd->fd_Flags |= FRF_BACKDRI2;
705 if (fd->fd_BackPen != (UWORD)~0) break;
706 case FRM_BackDriPen:
707 fd->fd_BackPen = data;
708 fd->fd_Flags |= FRF_BACKDRI;
709 break;
711 case FRM_SelectedBackRasterPen:
712 fd->fd_SelPen2 = data;
713 fd->fd_Flags &= ~FRF_SELDRI2;
714 if (fd->fd_SelPen != (UWORD)~0) break;
715 case FRM_SelectedBackPen:
716 fd->fd_SelPen = data;
717 fd->fd_Flags &= ~FRF_SELDRI;
718 break;
720 case FRM_SelectedBackRasterDriPen:
721 fd->fd_SelPen2 = data;
722 fd->fd_Flags |= FRF_SELDRI2;
723 if (fd->fd_SelPen != (UWORD)~0) break;
724 case FRM_SelectedBackDriPen:
725 fd->fd_SelPen = data;
726 fd->fd_Flags |= FRF_SELDRI;
727 break;
729 case FRM_Title:
730 if (!fd->fd_Title && data)
731 fd->fd_Title = BGUI_NewObject(BGUI_TEXT_GRAPHIC, TEXTA_CopyText, TRUE, TAG_DONE);
732 if (fd->fd_Title)
734 if(data)
735 DoSetMethodNG(fd->fd_Title, TEXTA_Text, data, TAG_DONE);
736 else
738 DisposeObject(fd->fd_Title);
739 fd->fd_Title=NULL;
742 break;
744 case FRM_TitleID:
745 if (!fd->fd_Title) fd->fd_Title = BGUI_NewObject(BGUI_TEXT_GRAPHIC, TEXTA_CopyText, TRUE, TAG_DONE);
746 if (fd->fd_Title) DoSetMethodNG(fd->fd_Title, TEXTA_TextID, data, TAG_DONE);
747 break;
750 * BGUI private!
752 case IMAGE_InBorder:
753 if (data) fd->fd_Flags |= FRF_INBORDER;
754 else fd->fd_Flags &= ~FRF_INBORDER;
755 break;
757 case FRM_FillPattern:
758 fd->fd_Pattern = (struct bguiPattern *)data;
759 break;
761 case FRM_SelectedFillPattern:
762 fd->fd_SelPattern = (struct bguiPattern *)data;
763 break;
765 case FRM_BackFillHook:
766 fd->fd_BackFillHook = (struct Hook *)data;
767 break;
769 case FRM_CustomHook:
770 fd->fd_FrameHook = (struct Hook *)data;
771 /* Fallthough */
772 case FRM_Type:
773 case FRM_ThinFrame:
774 FrameThickness(cl, obj);
775 break;
780 * Sanity checks.
782 if (fd->fd_FrameHook) fd->fd_Type = FRTYPE_CUSTOM;
783 else if (!fd->fd_Type) fd->fd_Type = FRTYPE_BUTTON;
785 if (fd->fd_BackFillHook == NULL)
786 fd->fd_BackFillHook = &fd->fd_DefBackfill;
788 switch (fd->fd_Type)
790 case FRTYPE_TAB_TOP:
791 case FRTYPE_TAB_BOTTOM:
792 case FRTYPE_TAB_LEFT:
793 case FRTYPE_TAB_RIGHT:
794 fd->fd_Flags |= FRF_FILL_OUTER;
795 break;
796 default:
797 fd->fd_Flags &= ~FRF_FILL_OUTER;
798 break;
802 /// OM_NEW
804 * Create a shiny new object.
806 METHOD(FrameClassNew, struct opSet *, ops)
808 FD *fd;
809 IPTR rc;
812 * First we let the superclass
813 * create a new object.
815 if ((rc = AsmDoSuperMethodA(cl, obj, (Msg)ops)))
818 * Get us the instance data.
820 fd = INST_DATA(cl, rc);
823 * Setup defaults.
825 fd->fd_Type = FRTYPE_BUTTON;
826 fd->fd_BackPen = (UWORD)~0;
827 fd->fd_SelPen = (UWORD)~0;
828 fd->fd_BackPen2 = (UWORD)~0;
829 fd->fd_SelPen2 = (UWORD)~0;
831 fd->fd_DefBackfill.h_Entry = (HOOKFUNC)BuiltInBack;
834 * Setup the object.
836 SetFrameAttrs(cl, (Object *)rc, ops->ops_AttrList);
837 FrameThickness(cl, (Object *)rc);
840 return rc;
842 METHOD_END
844 /// OM_SET
846 * Change one or more attrubutes.
848 METHOD(FrameClassSet, struct opSet *, ops)
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;
876 Tag tag = opg->opg_AttrID;
877 IPTR *store = opg->opg_Storage;
880 * First we see if the attribute
881 * they want is known to us. If not
882 * we pass it onto the superclass.
884 switch (tag)
886 case FRM_Template:
887 STORE fd;
888 break;
890 case FRM_TextAttr:
891 STORE fd->fd_TitleFont;
892 break;
894 case FRM_CustomHook:
895 STORE fd->fd_FrameHook;
896 break;
898 case FRM_BackFillHook:
899 STORE fd->fd_BackFillHook;
900 break;
902 case FRM_FillPattern:
903 STORE fd->fd_Pattern;
904 break;
906 case FRM_SelectedFillPattern:
907 STORE fd->fd_SelPattern;
908 break;
910 case FRM_FrameWidth:
911 STORE fd->fd_Horizontal;
912 break;
913 case FRM_FrameHeight:
914 STORE fd->fd_Vertical;
915 break;
917 case FRM_BackPen:
918 STORE fd->fd_Flags & FRF_BACKDRI ? ~0 : fd->fd_BackPen;
919 break;
920 case FRM_BackDriPen:
921 STORE fd->fd_Flags & FRF_BACKDRI ? fd->fd_BackPen : ~0;
922 break;
923 case FRM_SelectedBackPen:
924 STORE fd->fd_Flags & FRF_SELDRI ? ~0 : fd->fd_SelPen;
925 break;
926 case FRM_SelectedBackDriPen:
927 STORE fd->fd_Flags & FRF_SELDRI ? fd->fd_SelPen : ~0;
928 break;
929 case FRM_BackRasterPen:
930 STORE fd->fd_Flags & FRF_BACKDRI2 ? ~0 : fd->fd_BackPen2;
931 break;
932 case FRM_BackRasterDriPen:
933 STORE fd->fd_Flags & FRF_BACKDRI2 ? fd->fd_BackPen2 : ~0;
934 break;
935 case FRM_SelectedBackRasterPen:
936 STORE fd->fd_Flags & FRF_SELDRI2 ? ~0 : fd->fd_SelPen2;
937 break;
938 case FRM_SelectedBackRasterDriPen:
939 STORE fd->fd_Flags & FRF_SELDRI2 ? fd->fd_SelPen2 : ~0;
940 break;
942 default:
943 rc = BGUI_UnpackStructureTag((UBYTE *)fd, FramePackTable, tag, store);
944 if (!rc) rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
945 break;
947 return rc;
949 METHOD_END
951 /// OM_DISPOSE
953 * Dispose of the object.
955 METHOD(FrameClassDispose, Msg, msg)
957 FD *fd = INST_DATA(cl, obj);
960 * Close the font.
962 if (fd->fd_Font && (fd->fd_Flags & FRF_SELFOPEN))
963 BGUI_CloseFont(fd->fd_Font);
966 * Dispose of the text graphic.
968 if (fd->fd_Title) DisposeObject(fd->fd_Title);
971 * The rest goes to the superclass.
973 return AsmDoSuperMethodA(cl, obj, msg);
975 METHOD_END
977 /// FRAMEM_SETUPBOUNDS
979 METHOD(FrameClassSetupBounds, struct fmSetupBounds *, fmsb)
981 FD *fd = INST_DATA(cl, obj);
982 struct IBox *hb = fmsb->fmsb_HitBox;
983 struct IBox *ib = fmsb->fmsb_InnerBox;
984 int ox1 = fd->fd_OuterX1;
985 int ox2 = fd->fd_OuterX2;
986 int oy1 = fd->fd_OuterY1;
987 int oy2 = fd->fd_OuterY2;
989 hb->Left += ox1;
990 hb->Top += oy1;
991 hb->Width -= ox1 + ox2;
992 hb->Height -= oy1 + oy2;
994 ox1 += fd->fd_InnerX1 + fd->fd_Horizontal;
995 ox2 += fd->fd_InnerX2 + fd->fd_Horizontal;
996 oy1 += fd->fd_InnerY1 + fd->fd_Vertical;
997 oy2 += fd->fd_InnerY2 + fd->fd_Vertical;
999 if (fd->fd_Title)
1001 if (fd->fd_Font) oy1 += fd->fd_Font->tf_YSize;
1002 else if (fd->fd_TitleFont) oy1 += fd->fd_TitleFont->ta_YSize;
1005 ib->Left += ox1;
1006 ib->Top += oy1;
1007 ib->Width -= ox1 + ox2;
1008 ib->Height -= oy1 + oy2;
1010 SetImageBounds(obj, fmsb->fmsb_HitBox);
1012 return 1;
1014 METHOD_END
1016 /// BASE_DIMENSIONS
1018 METHOD(FrameClassDimensions, struct bmDimensions *, bmd)
1020 FD *fd = INST_DATA(cl, obj);
1021 struct bguiExtent *be = bmd->bmd_Extent;
1022 int ox = (fd->fd_Horizontal << 1) + fd->fd_InnerX1 + fd->fd_InnerX2;
1023 int oy = (fd->fd_Vertical << 1) + fd->fd_InnerY1 + fd->fd_InnerY2;
1025 if (fd->fd_Title)
1027 if (fd->fd_Font) oy += fd->fd_Font->tf_YSize;
1028 else if (fd->fd_TitleFont) oy += fd->fd_TitleFont->ta_YSize;
1031 be->be_Min.Width += ox;
1032 be->be_Min.Height += oy;
1034 be->be_Nom.Width += ox;
1035 be->be_Nom.Height += oy;
1037 return 1;
1039 METHOD_END
1041 /// BASE_RENDER
1043 * Render the frame.
1045 METHOD(FrameClassRender, struct bmRender *, bmr)
1047 FD *fd = INST_DATA(cl, obj);
1048 struct BaseInfo *bi = bmr->bmr_BInfo;
1049 struct RastPort *rp = bi->bi_RPort;
1050 struct Rectangle rect;
1051 struct FrameDrawMsg fdraw;
1052 WORD l, t, r, b, place;
1053 ULONG rc = 1;
1054 int tv, th, dv, dh, shadow, shine, tmp = 0, tmp2 = 0;
1055 int state = bmr->bmr_Flags;
1056 int i_fuzz, i_blank, i_swap, i_mix;
1057 Object *fr;
1059 static UWORD pat[] = { 0x5555, 0xAAAA };
1061 static BYTE taboff[4][4][2] =
1063 { { 3, 2 }, { 3, 2 }, { 2, 1 }, { 0, 0 } },
1064 { { 3, 2 }, { 3, 2 }, { 0, 0 }, { 2, 1 } },
1065 { { 2, 1 }, { 0, 0 }, { 3, 2 }, { 3, 2 } },
1066 { { 0, 0 }, { 2, 1 }, { 3, 2 }, { 3, 2 } },
1069 BSetDrMd(bi, JAM2);
1072 * Calculate the frame position and dimensions
1074 l = IMAGE(obj)->LeftEdge;
1075 t = IMAGE(obj)->TopEdge;
1076 r = IMAGE(obj)->Width + l - 1;
1077 b = IMAGE(obj)->Height + t - 1;
1079 if (fd->fd_Title)
1082 * Setup the font if one is present.
1084 if (fd->fd_Font) BSetFont(bi, fd->fd_Font);
1087 * Adjust top position if there is a title present.
1089 if (fd->fd_Flags & FRF_CENTER_TITLE)
1090 t += (rp->TxBaseline - (rp->TxHeight >> 1));
1091 else
1092 t += rp->TxBaseline;
1095 rect.MinX = l;
1096 rect.MinY = t;
1097 rect.MaxX = r;
1098 rect.MaxY = b;
1100 * First we do the background.
1102 * When this is a FRF_EDGES_ONLY frame we do nothing.
1103 * No hooks are called, and nothing is filled.
1105 if (!(fd->fd_Flags & FRF_EDGES_ONLY))
1107 if (fd->fd_Flags & FRF_FILL_OUTER)
1109 if ((fr = fd->fd_ParentGroup ? BASE_DATA(fd->fd_ParentGroup)->bc_Frame : NULL))
1111 AsmDoMethod(fr, FRAMEM_BACKFILL, bi, &rect, IDS_NORMAL);
1113 else
1115 BSetDPenA(bi, BACKGROUNDPEN);
1116 BRectFillA(bi, &rect);
1118 tmp = fd->fd_Type - FRTYPE_TAB_TOP;
1119 tmp2 = ((state == IDS_SELECTED) || (state == IDS_SELECTED)) ? 1 : 0;
1121 rect.MinX += taboff[tmp][0][tmp2];
1122 rect.MaxX -= taboff[tmp][1][tmp2];
1123 rect.MinY += taboff[tmp][2][tmp2];
1124 rect.MaxY -= taboff[tmp][3][tmp2];
1126 state = IDS_NORMAL;
1128 AsmDoMethod(obj, FRAMEM_BACKFILL, bi, &rect, state);
1132 * Get frame thickness.
1134 th = fd->fd_Horizontal;
1135 tv = fd->fd_Vertical;
1137 if ((th << 1) > (r - l + 1)) th = (r - l + 1) >> 1;
1138 if ((tv << 1) > (b - t + 1)) tv = (b - t + 1) >> 1;
1141 * Draw the frame (whatever type it is)
1143 state = bmr->bmr_Flags;
1146 * Selected or normal?
1148 switch (state)
1150 case IDS_SELECTED:
1151 case IDS_INACTIVESELECTED:
1152 shadow = SHINEPEN;
1153 shine = SHADOWPEN;
1154 break;
1156 default:
1157 shadow = SHADOWPEN;
1158 shine = SHINEPEN;
1159 break;
1163 * Swap pens if we must
1164 * recess the frame.
1166 if (fd->fd_Flags & FRF_RECESSED)
1168 tmp = shadow;
1169 shadow = shine;
1170 shine = tmp;
1173 if(th>0
1174 && tv>0)
1176 switch (fd->fd_Type)
1178 case FRTYPE_CUSTOM:
1180 * Fill in the data structures for the custom frame hook
1182 fdraw.fdm_MethodID = FRM_RENDER;
1183 fdraw.fdm_RPort = rp;
1184 fdraw.fdm_DrawInfo = bi->bi_DrInfo;
1185 fdraw.fdm_Bounds = &rect;
1186 fdraw.fdm_State = state;
1187 fdraw.fdm_Horizontal = th;
1188 fdraw.fdm_Vertical = tv;
1190 * Call the hook routine.
1192 rc = BGUI_CallHookPkt(fd->fd_FrameHook, (VOID *)obj, (VOID *)&fdraw);
1193 break;
1195 case FRTYPE_RIDGE:
1196 case FRTYPE_NEXT:
1197 case FRTYPE_DROPBOX:
1198 case FRTYPE_FUZZ_BUTTON:
1199 case FRTYPE_FUZZ_RIDGE:
1200 case FRTYPE_BUTTON:
1201 i_fuzz = -1;
1202 i_blank = -1;
1203 i_swap = -1;
1204 i_mix = -1;
1206 dv = (tv + th - 1) / th; if (dv < 1) dv = 1;
1207 dh = (th + tv - 1) / tv; if (dh < 1) dh = 1;
1209 if (fd->fd_Type == FRTYPE_FUZZ_BUTTON)
1212 * 1/4 Normal, 3/4 Raster
1214 i_fuzz = (tv / dv) / 4;
1216 if (fd->fd_Type == FRTYPE_FUZZ_RIDGE)
1219 * 1/3 Normal, 1/3 Blank, 1/3 Recessed
1221 tmp = shine;
1222 tmp2 = shadow;
1223 i_mix = (tv / dv) / 3 - 1;
1224 i_swap = (2 * tv / dv) / 3 - 1;
1226 if (fd->fd_Type == FRTYPE_DROPBOX)
1229 * 1/3 Normal, 1/3 Blank, 1/3 Recessed
1231 tmp = shine;
1232 tmp2 = shadow;
1233 i_blank = (tv / dv) / 3 - 1;
1234 i_swap = (2 * tv / dv) / 3 - 1;
1236 if (fd->fd_Type == FRTYPE_NEXT)
1239 * 1/2 Recessed, 1/2 Normal
1241 tmp2 = shine;
1242 tmp = shadow;
1243 shine = tmp;
1244 shadow = tmp2;
1245 i_swap = (tv / dv) / 2 - 1;
1247 if (fd->fd_Type == FRTYPE_RIDGE)
1250 * 1/2 Normal, 1/2 Recessed
1252 tmp = shine;
1253 tmp2 = shadow;
1254 i_swap = (tv / dv) / 2 - 1;
1258 * Render the bevelbox.
1260 while ((tv > 0) && (th > 0))
1262 if (shine >= 0) BSetDPenA(bi, shine);
1263 if(dh>0
1264 && t<=b)
1265 BRectFill(bi, l, t, l + dh - 1, b); l += dh;
1266 if (shadow >= 0) BSetDPenA(bi, shadow);
1267 if(dv>0
1268 && l<=r)
1269 BRectFill(bi, l, b - dv + 1, r, b); b -= dv;
1270 if(dh>0
1271 && t<=b)
1272 BRectFill(bi, r - dh + 1, t, r, b); r -= dh;
1273 if (shine >= 0) BSetDPenA(bi, shine);
1274 if(dv>0
1275 && l<=r)
1276 BRectFill(bi, l, t, r, t + dv - 1); t += dv;
1277 tv -= dv;
1278 th -= dh;
1280 if (i_fuzz-- == 0)
1282 BSetAfPt(bi, pat, 1);
1284 if (i_blank-- == 0)
1286 shine = BACKGROUNDPEN;
1287 shadow = BACKGROUNDPEN;
1289 if (i_swap-- == 0)
1291 BClearAfPt(bi);
1292 shine = tmp2;
1293 shadow = tmp;
1295 if (i_mix-- == 0)
1297 BSetAfPt(bi, pat, 1);
1298 BSetDPenA(bi, shine);
1299 BSetDPenB(bi, shadow);
1300 shine = shadow = -1;
1303 if (tv > 0)
1305 BSetDPenA(bi, shine);
1306 BRectFill(bi, l, t, r, t + tv - 1);
1307 BSetDPenA(bi, shadow);
1308 BRectFill(bi, l, b - tv + 1, r, b);
1310 if (th > 0)
1312 BSetDPenA(bi, shine);
1313 BRectFill(bi, l, t, l + th - 1, b);
1314 BSetDPenA(bi, shadow);
1315 BRectFill(bi, r - th + 1, t, r, b);
1317 break;
1319 case FRTYPE_RADIOBUTTON:
1320 RenderRadioFrame(bmr, l, t, r, b, fd);
1321 break;
1323 case FRTYPE_XEN_BUTTON:
1324 RenderXenFrame(bmr, l, t, r, b, fd);
1325 break;
1327 case FRTYPE_TAB_TOP:
1328 case FRTYPE_TAB_BOTTOM:
1329 case FRTYPE_TAB_LEFT:
1330 case FRTYPE_TAB_RIGHT:
1331 RenderTabFrame(bmr, l, t, r, b, fd);
1332 break;
1334 case FRTYPE_TAB_ABOVE:
1336 * Render the frame.
1338 BSetDPenA(bi, shine);
1339 BRectFill(bi, l, t, l + th - 1, b - tv);
1340 BSetDPenA(bi, shadow);
1341 BRectFill(bi, l + 1, b - tv + 1, r, b);
1342 BRectFill(bi, r - th + 1, t, r, b);
1343 break;
1345 case FRTYPE_TAB_BELOW:
1347 * Render the frame.
1349 BSetDPenA(bi, shine);
1350 BRectFill(bi, l, t, l + th - 1, b - tv + 1);
1351 BRectFill(bi, l, t, r - th + 1, t + tv - 1);
1352 BSetDPenA(bi, shadow);
1353 BRectFill(bi, r - th + 1, t, r, b);
1354 break;
1356 case FRTYPE_BORDER:
1358 * Render the borderbox.
1360 RenderBevelBox(bi, l, t, r, b, state, fd->fd_Flags & FRF_RECESSED, TRUE);
1361 break;
1363 case FRTYPE_NONE:
1364 break;
1369 * Render frame the title.
1371 if (fd->fd_Title)
1373 place = 0;
1376 * Left or right?
1378 if (fd->fd_Flags & FRF_TITLE_LEFT ) place = 1;
1379 else if (fd->fd_Flags & FRF_TITLE_RIGHT) place = 2;
1382 * Render the title.
1384 RenderTitle(fd->fd_Title, bi, l, t, r - l + 1,
1385 fd->fd_Flags & FRF_HIGHLIGHT_TITLE, fd->fd_Flags & FRF_CENTER_TITLE, place);
1389 return rc;
1391 METHOD_END
1393 /// BASE_LOCALIZE
1395 METHOD(FrameClassLocalize, struct bmLocalize *, bml)
1397 FD *fd = INST_DATA(cl, obj);
1398 ULONG rc = 0;
1400 if (fd->fd_Title) rc = AsmDoMethodA(fd->fd_Title, (Msg)bml);
1402 return rc;
1404 METHOD_END
1406 /// Class initialization.
1409 * Class function table.
1411 STATIC DPFUNC ClassFunc[] = {
1412 { BASE_RENDER, FrameClassRender, },
1413 { BASE_DIMENSIONS, FrameClassDimensions, },
1414 { FRAMEM_BACKFILL, FrameClassBackfill, },
1415 { FRAMEM_SETUPBOUNDS, FrameClassSetupBounds, },
1416 { OM_SET, FrameClassSet, },
1417 { OM_GET, FrameClassGet, },
1418 { OM_NEW, FrameClassNew, },
1419 { OM_DISPOSE, FrameClassDispose, },
1420 { BASE_LOCALIZE, FrameClassLocalize, },
1421 { DF_END },
1425 * Simple class initialization.
1427 makeproto Class *InitFrameClass(void)
1429 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_IMAGE_OBJECT,
1430 CLASS_ObjectSize, sizeof(FD),
1431 CLASS_DFTable, ClassFunc,
1432 TAG_DONE);