_screen is only valid between show/hide.
[AROS.git] / rom / intuition / gadgets.c
blob3e6416291af1c88408dd0273ee250d72ffbaa3f5
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4 $Id$
6 Common routines for Gadgets.
7 */
9 /**********************************************************************************************/
11 #include <exec/types.h>
12 #include <proto/intuition.h>
13 #include <intuition/intuition.h>
14 #include <intuition/cghooks.h>
15 #include <intuition/classes.h>
16 #include <intuition/classusr.h>
17 #include <intuition/imageclass.h>
18 #include <proto/graphics.h>
19 #include <proto/layers.h>
20 #include <graphics/rastport.h>
21 #include <graphics/text.h>
22 #include <graphics/gfxmacros.h>
24 #include <string.h>
26 #include "intuition_intern.h"
27 #include "gadgets.h"
29 #define DEBUG_RENDERDISABLEPATTERN(x) ;
30 #define DEBUG_ERASERELGADGETAREA(x) ;
31 #define DEBUG_SETUPGINFO(x) ;
34 /**********************************************************************************************/
36 #define EG(o) ((struct ExtGadget *)o)
37 #define IM(o) ((struct Image *)o)
39 /**********************************************************************************************/
41 /* print the label of a gadget object */
43 void printgadgetlabel(Class *cl, Object *o, struct gpRender *msg,
44 struct IntuitionBase *IntuitionBase)
46 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
47 struct RastPort *rp = msg->gpr_RPort;
48 struct IBox container;
49 UWORD *pens = msg->gpr_GInfo->gi_DrInfo->dri_Pens;
50 ULONG len, x, y;
52 if (!(EG(o)->GadgetText)) return;
54 GetGadgetIBox((struct Gadget *)o, msg->gpr_GInfo, &container);
55 //dprintf("printgadgetlabel: o %p ibox %d %d %d %d\n",o,container.Left,container.Top,container.Width,container.Height);
57 SetFont(rp, msg->gpr_GInfo->gi_DrInfo->dri_Font);
59 switch (EG(o)->Flags & GFLG_LABELMASK)
61 case GFLG_LABELITEXT:
62 /* ITexts must not to be centered! */
64 /* frbuttonclass sets fg/bg/drawmode attributes */
65 int_PrintIText(rp, EG(o)->GadgetText, container.Left,container.Top, TRUE, IntuitionBase);
66 break;
68 case GFLG_LABELSTRING:
69 len = strlen ((STRPTR) EG(o)->GadgetText);
71 if (len > 0UL)
73 ULONG x;
74 ULONG y;
76 x = container.Left + (container.Width / 2);
77 x -= LabelWidth (rp,
78 (STRPTR)EG(o)->GadgetText, len, IntuitionBase) / 2;
79 y = container.Top + (container.Height / 2) +
80 rp->Font->tf_Baseline;
81 y -= rp->Font->tf_YSize / 2;
82 SetAPen (rp, pens[TEXTPEN]);
83 Move (rp, x, y);
84 RenderLabel (rp,
85 (STRPTR) EG(o)->GadgetText, len,
86 IntuitionBase);
88 break;
90 case GFLG_LABELIMAGE:
91 /* center image position */
93 x = container.Left + ((container.Width / 2) -
94 (IM(EG(o)->GadgetText)->Width / 2)) - IM(EG(o)->GadgetText)->LeftEdge;
96 y = container.Top + ((container.Height / 2) -
97 (IM(EG(o)->GadgetText)->Height / 2)) - IM(EG(o)->GadgetText)->TopEdge;
98 //dprintf("printgadgetlabel: o %p w %d h %d x %d y %d l %d t %d\n", o,IM(EG(o)->GadgetText)->Width,IM(EG(o)->GadgetText)->Height,x,y,IM(EG(o)->GadgetText)->LeftEdge,IM(EG(o)->GadgetText)->TopEdge);
100 DrawImageState(rp, IM(EG(o)->GadgetText),
101 x, y,
102 ((EG(o)->Flags & GFLG_SELECTED) ? IDS_SELECTED : IDS_NORMAL ),
103 msg->gpr_GInfo->gi_DrInfo);
104 break;
106 } /* switch (EG(o)->Flags & GFLG_LABELMASK) */
110 /**********************************************************************************************/
112 /* Calculate the size of the Bounding Box of the gadget */
113 void CalcBBox (struct Window * window, struct Requester * req, struct Gadget * gadget,
114 struct BBox * bbox)
117 GetDomGadgetIBox(gadget, window->WScreen, window, req, (struct IBox *)bbox);
119 } /* CalcBBox */
121 /**********************************************************************************************/
123 /* Figure out the size/position of the gadget rectangle, taking relative
124 * positioning into account.
126 VOID GetGadgetIBox(struct Gadget *g, struct GadgetInfo *gi, struct IBox *ibox)
128 ibox->Left = g->LeftEdge;
129 ibox->Top = g->TopEdge;
130 ibox->Width = g->Width;
131 ibox->Height = g->Height;
133 if (gi)
135 if (g->Flags & GFLG_RELRIGHT)
136 ibox->Left += gi->gi_Domain.Width - 1;
138 if (g->Flags & GFLG_RELBOTTOM)
139 ibox->Top += gi->gi_Domain.Height - 1;
141 if (g->Flags & GFLG_RELWIDTH)
142 ibox->Width += gi->gi_Domain.Width;
144 if (g->Flags & GFLG_RELHEIGHT)
145 ibox->Height += gi->gi_Domain.Height;
148 DEBUG_GETGADGETIBOX(dprintf("GetGadgetIBox: Gadget 0x%lx GInfo 0x%lx Flags 0x%lx Left %ld Top %ld Width %ld Height %ld\n",
149 g, gi, g->Flags, ibox->Left, ibox->Top, ibox->Width, ibox->Height));
152 /**********************************************************************************************/
154 ULONG LabelWidth (struct RastPort * rp, STRPTR label, ULONG len,
155 struct IntuitionBase * IntuitionBase)
157 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
158 ULONG totalwidth, uscorewidth;
160 totalwidth = TextLength (rp, label, len);
161 uscorewidth = TextLength (rp, "_", 1);
163 while (len && *label)
165 if (*label == '_')
166 totalwidth -= uscorewidth;
168 label ++;
169 len --;
172 return totalwidth;
175 /**********************************************************************************************/
177 void RenderLabel (struct RastPort * rp, STRPTR label, ULONG len,
178 struct IntuitionBase * IntuitionBase)
180 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
181 ULONG renderlen;
182 ULONG uscorewidth;
184 while (*label)
186 renderlen = 0;
188 while (label[renderlen] && label[renderlen] != '_')
189 renderlen ++;
191 Text (rp, label, renderlen);
193 label += renderlen;
195 if (*label) /* '_' ? */
197 WORD cx, cy;
199 label ++; /* Skip */
201 uscorewidth = TextLength (rp, label, 1);
203 cx = rp->cp_x;
204 cy = rp->cp_y;
206 Move (rp, cx, cy+2);
207 Draw (rp, cx+uscorewidth-1, cy+2);
208 Move (rp, cx, cy);
213 /**********************************************************************************************/
215 VOID drawrect(struct RastPort *rp, WORD x1, WORD y1, WORD x2, WORD y2,
216 struct IntuitionBase *IntuitionBase)
218 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
220 /* We RectFill() because it is generally faster than Draw()
221 (Draw() uses Set/GetPixel() while RectFill() can do higherlevel
222 clipping. Also it is MUCH faster in the x11gfx hidd.
225 RectFill(rp, x1, y1, x2 - 1, y1); /* Top */
226 RectFill(rp, x2, y1, x2, y2 - 1); /* Right */
227 RectFill(rp, x1 + 1, y2, x2, y2); /* Bottom */
228 RectFill(rp, x1, y1 + 1, x1, y2); /* Left */
230 return;
233 /**********************************************************************************************/
235 void GetGadgetDomain(struct Gadget *gad, struct Screen *scr, struct Window *win,
236 struct Requester *req, struct IBox *box)
238 switch (gad->GadgetType & (GTYP_GADGETTYPE & ~GTYP_SYSGADGET))
240 case GTYP_SCRGADGET:
241 box->Left = 0;
242 box->Top = 0;
243 box->Width = scr->Width;
244 box->Height = scr->Height;
246 break;
248 case GTYP_GZZGADGET:
249 /* stegerg: this means gadget is in window border! */
251 box->Left = 0;
252 box->Top = 0;
253 box->Width = win->Width;
254 box->Height = win->Height;
256 break;
258 case GTYP_REQGADGET:
259 box->Left = req->LeftEdge + win->BorderLeft;
260 box->Top = req->TopEdge + win->BorderTop;
261 box->Width = req->Width;
262 box->Height = req->Height;
264 break;
266 default:
267 if (win->Flags & WFLG_GIMMEZEROZERO)
269 /* stegerg: domain.left and domain.top must not be added
270 to gadget position when it is rendered, because gadgets
271 in the innerlayer of a gzz gadget are already shifted
272 thanks to the innerlayer. */
274 box->Left = win->BorderLeft;
275 box->Top = win->BorderTop;
277 box->Width = win->Width - win->BorderLeft - win->BorderRight;
278 box->Height = win->Height - win->BorderTop - win->BorderBottom;
281 else
283 box->Left = 0;
284 box->Top = 0;
285 box->Width = win->Width;
286 box->Height = win->Height;
290 break;
292 } /* switch (gadgettype) */
295 /**********************************************************************************************/
297 WORD GetGadgetLeft(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
299 struct IBox box;
301 GetGadgetDomain(gad, scr, win, req, &box);
303 return gad->LeftEdge + ADDREL(gad, GFLG_RELRIGHT, (&box), Width - 1);
306 /**********************************************************************************************/
308 WORD GetGadgetTop(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
310 struct IBox box;
312 GetGadgetDomain(gad, scr, win, req, &box);
314 return gad->TopEdge + ADDREL(gad, GFLG_RELBOTTOM, (&box), Height - 1);
317 /**********************************************************************************************/
319 WORD GetGadgetWidth(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
321 struct IBox box;
323 GetGadgetDomain(gad, scr, win, req, &box);
325 return gad->Width + ADDREL(gad, GFLG_RELWIDTH, (&box), Width);
328 /**********************************************************************************************/
330 WORD GetGadgetHeight(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
332 struct IBox box;
334 GetGadgetDomain(gad, scr, win, req, &box);
336 return gad->Height + ADDREL(gad, GFLG_RELHEIGHT, (&box), Height);
339 /**********************************************************************************************/
341 /* gadget box in screen coords */
342 void GetScrGadgetIBox(struct Gadget *gad, struct Screen *scr, struct Window *win,
343 struct Requester *req, struct IBox *box)
345 GetWinGadgetIBox(gad, scr, win, req, box);
347 if (win)
349 box->Left += win->LeftEdge;
350 box->Top += win->TopEdge;
354 /**********************************************************************************************/
356 /* gadget box relative to upper left window edge */
357 void GetWinGadgetIBox(struct Gadget *gad, struct Screen *scr, struct Window *win,
358 struct Requester *req, struct IBox *box)
360 struct IBox domain;
362 GetGadgetDomain(gad, scr, win, req, &domain);
364 box->Left = gad->LeftEdge;
365 box->Top = gad->TopEdge;
366 box->Width = gad->Width;
367 box->Height = gad->Height;
369 if (gad->Flags & GFLG_RELRIGHT)
370 box->Left += domain.Width - 1;
372 if (gad->Flags & GFLG_RELBOTTOM)
373 box->Top += domain.Height - 1;
375 if (gad->Flags & GFLG_RELWIDTH)
376 box->Width += domain.Width;
378 if (gad->Flags & GFLG_RELHEIGHT)
379 box->Height += domain.Height;
381 box->Left += domain.Left;
382 box->Top += domain.Top;
385 /**********************************************************************************************/
387 /* gadget box in domain coords */
388 void GetDomGadgetIBox(struct Gadget *gad, struct Screen *scr, struct Window *win,
389 struct Requester *req, struct IBox *box)
391 struct IBox domain;
393 GetWinGadgetIBox(gad, scr, win, req, box);
394 GetGadgetDomain(gad, scr, win, req, &domain);
396 box->Left -= domain.Left;
397 box->Top -= domain.Top;
400 /**********************************************************************************************/
402 /* gadget bounds in screen coords */
403 void GetScrGadgetBounds(struct Gadget *gad, struct Screen *scr, struct Window *win,
404 struct Requester *req, struct IBox *box)
406 struct IBox domain;
408 if (gad->Flags & GFLG_EXTENDED)
410 if (EG(gad)->MoreFlags & GMORE_BOUNDS)
412 GetGadgetDomain(gad, scr, win, req, &domain);
414 box->Left = domain.Left +
415 EG(gad)->BoundsLeftEdge + ADDREL(gad, GFLG_RELRIGHT, (&domain), Width - 1) +
416 (win ? win->LeftEdge : 0);
418 box->Top = domain.Top +
419 EG(gad)->BoundsTopEdge + ADDREL(gad, GFLG_RELBOTTOM, (&domain), Height - 1) +
420 (win ? win->TopEdge : 0);
422 box->Width = EG(gad)->BoundsWidth + ADDREL(gad, GFLG_RELWIDTH, (&domain), Width);
424 box->Height = EG(gad)->BoundsHeight + ADDREL(gad, GFLG_RELHEIGHT, (&domain), Height);
426 return;
428 } /* if (gad->MoreFlags & GMORE_BOUNDS) */
430 } /* if (gad->Flags & GFLG_EXTENDED) */
432 /* if gadget does not have bounds return box */
434 GetScrGadgetIBox(gad, scr, win, req, box);
437 /**********************************************************************************************/
439 /* gadget bounds relative to upper left window edge */
440 void GetWinGadgetBounds(struct Gadget *gad, struct Screen *scr, struct Window *win,
441 struct Requester *req, struct IBox *box)
443 GetScrGadgetBounds(gad, scr, win, req, box);
445 if (win)
447 box->Left -= win->LeftEdge;
448 box->Top -= win->TopEdge;
452 /**********************************************************************************************/
454 /* gadget bounds in domain coords */
455 void GetDomGadgetBounds(struct Gadget *gad, struct Screen *scr, struct Window *win,
456 struct Requester *req, struct IBox *box)
458 struct IBox domain;
460 GetWinGadgetBounds(gad, scr, win, req, box);
461 GetGadgetDomain(gad, scr, win, req, &domain);
463 box->Left -= domain.Left;
464 box->Top -= domain.Top;
467 /**********************************************************************************************/
469 void EraseRelGadgetArea(struct Window *win, struct Rectangle *clipto,
470 BOOL onlydamagelist, struct IntuitionBase *IntuitionBase)
472 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
473 struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
474 struct Gadget *gad;
475 struct Region *old_clipregion = NULL; /* shut up the compiler */
476 struct RastPort *rp, *rp2;
477 struct Layer *lay;
478 struct IBox box;
479 WORD old_scroll_x = 0, old_scroll_y = 0, i, num_loops;
481 DEBUG_ERASERELGADGETAREA(dprintf("EraseRelGadgetArea: win 0x%lx onlydamage %d\n",
482 win, onlydamagelist));
484 rp = win->RPort;
485 rp2 = win->BorderRPort;
487 if (rp->Layer == rp2->Layer)
489 num_loops = 1;
491 else
493 num_loops = 2;
494 clipto = NULL; /* Don't do any border clipping for GZZ windows */
497 for(i = 0; i < num_loops; i++, rp = rp2)
499 lay = rp->Layer;
501 LockLayer(0, lay);
503 if (!onlydamagelist)
505 old_scroll_x = lay->Scroll_X;
506 old_scroll_y = lay->Scroll_Y;
507 old_clipregion = InstallClipRegion(lay, NULL);
510 gad = win->FirstGadget;
511 while(gad)
513 BOOL checkgad = FALSE;
515 DEBUG_ERASERELGADGETAREA(dprintf("EraseRelGadgetArea: Gadget 0x%lx Flags 0x%lx Type 0x%lx Activation 0x%lx %d,%d %d×%d\n",
516 gad, gad->Flags, gad->GadgetType, gad->Activation,
517 gad->LeftEdge, gad->TopEdge, gad->Width, gad->Height));
519 if (num_loops == 1)
521 checkgad = TRUE;
523 else
525 if (i == 0)
527 if (!IS_BORDER_GADGET(gad)) checkgad = TRUE;
529 else
531 if (IS_BORDER_GADGET(gad)) checkgad = TRUE;
535 if (checkgad)
537 if (gad->Flags & (GFLG_RELRIGHT | GFLG_RELBOTTOM |
538 GFLG_RELWIDTH | GFLG_RELHEIGHT | GFLG_RELSPECIAL))
540 struct Rectangle rect;
542 GetDomGadgetBounds(gad, win->WScreen, win, NULL, &box);
544 if ((box.Width > 0) && (box.Height > 0))
546 rect.MinX = box.Left;
547 rect.MinY = box.Top;
548 rect.MaxX = box.Left + box.Width - 1;
549 rect.MaxY = box.Top + box.Height - 1;
551 if (!(lay->Flags & LAYERSUPER))
553 DEBUG_ERASERELGADGETAREA(dprintf("EraseRelGadgetArea: gad 0x%lx add (%d,%d)-(%d,%d)\n", gad, rect.MinX, rect.MinY, rect.MaxX, rect.MaxY));
555 OrRectRegion(lay->DamageList, &rect);
556 lay->Flags |= LAYERREFRESH;
559 if (!onlydamagelist)
561 if (!clipto || AndRectRect(&rect, clipto, &rect))
563 EraseRect(rp, rect.MinX, rect.MinY, rect.MaxX, rect.MaxY);
571 } /* if (checkgad) */
573 gad = gad->NextGadget;
575 } /* while(gad) */
577 if (!onlydamagelist)
579 InstallClipRegion(lay, old_clipregion);
580 lay->Scroll_X = old_scroll_x;
581 lay->Scroll_Y = old_scroll_y;
584 UnlockLayer(lay);
586 } /* for(i = 0; i < num_loops; i++, rp = rp2) */
590 /**********************************************************************************************/
592 void RenderDisabledPattern(struct RastPort *rp, struct DrawInfo *dri, WORD x1, WORD y1,
593 WORD x2, WORD y2, struct IntuitionBase *IntuitionBase)
595 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
596 UWORD pen;
597 UWORD pattern[] = { 0x8888, 0x2222 };
599 DEBUG_RENDERDISABLEPATTERN(dprintf("RenderDisabledPattern: rp 0x%lx dri 0x%lx x1 %ld y1 %ld x2 %ld y2 %ld\n",
600 rp,dri,x1,y1,x2,y2));
602 if (dri)
604 pen = dri->dri_Pens[SHADOWPEN];
606 else
608 pen = 1;
611 SetDrMd( rp, JAM1 );
612 SetAPen( rp, pen );
613 SetAfPt( rp, pattern, 1);
615 /* render disable pattern */
616 RectFill(rp, x1, y1, x2, y2);
618 SetAfPt (rp, NULL, 0);
622 /**********************************************************************************************/
624 ULONG GetGadgetState(struct Window *window, struct Gadget *gadget)
626 ULONG state = IDS_NORMAL;
628 if (IS_BORDER_GADGET(gadget)
629 && !(window->Flags & (WFLG_WINDOWACTIVE | WFLG_TOOLBOX)))
631 if (gadget->Flags & GFLG_DISABLED)
633 if (gadget->Flags & GFLG_SELECTED)
635 state = IDS_INACTIVEDISABLED; /* Hmm ... there's no INACTIVEDISABLEDSELECTED */
637 else
639 state = IDS_INACTIVEDISABLED;
642 else
644 if (gadget->Flags & GFLG_SELECTED)
646 state = IDS_INACTIVESELECTED;
648 else
650 state = IDS_INACTIVENORMAL;
654 else
656 if (gadget->Flags & GFLG_DISABLED)
658 if (gadget->Flags & GFLG_SELECTED)
660 state = IDS_SELECTEDDISABLED;
662 else
664 state = IDS_DISABLED;
667 else
669 if (gadget->Flags & GFLG_SELECTED)
671 state = IDS_SELECTED;
673 else
675 state = IDS_NORMAL;
680 return state;
683 /**********************************************************************************************/
685 void SetupGInfo(struct GadgetInfo *gi, struct Window *win, struct Requester *req,
686 struct Gadget *gad, struct IntuitionBase *IntuitionBase)
688 struct Window *tw = 0;
690 DEBUG_SETUPGINFO(dprintf("SetupGInfo: gi %p win %p req %p gadget %p (Type 0x%x)\n",
691 gi, win, req, gad, gad->GadgetType));
693 memset(gi, 0, sizeof(*gi));
695 if (req)
697 tw = req->RWindow;
699 else
701 tw = win;
704 if (tw)
706 if (IS_SCREEN_GADGET(gad))
708 gi->gi_Window = NULL;
709 gi->gi_Screen = (struct Screen *)tw;
710 gi->gi_Pens.DetailPen = 0;
711 gi->gi_Pens.BlockPen = 0;
713 else
715 gi->gi_Window = tw;
716 gi->gi_Screen = tw->WScreen;
717 gi->gi_Pens.DetailPen = tw->DetailPen;
718 gi->gi_Pens.BlockPen = tw->BlockPen;
720 gi->gi_Requester = req;
721 gi->gi_DrInfo = GetScreenDrawInfo (gi->gi_Screen);
723 SET_GI_RPORT(gi, tw, req, gad);
725 gi->gi_Layer = gi->gi_RastPort ? gi->gi_RastPort->Layer : NULL;
727 GetGadgetDomain(gad, gi->gi_Screen, gi->gi_Window, req, &gi->gi_Domain);
728 } /* if (tw) */
730 DEBUG_SETUPGINFO(dprintf("SetGInfo: Win %p Req %p RP %p Layer %p\n",
731 gi->gi_Window, gi->gi_Requester, gi->gi_RastPort, gi->gi_Layer));
734 /**********************************************************************************************/