Update to lasso handling. Adjust scroll amount based on difference between mouse...
[AROS.git] / rom / intuition / gadgets.c
blob3b9a2c2cf69e3ffb404b0f6cefef940c25b6923e
1 /*
2 Copyright © 1995-2009, 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 RastPort *rp = msg->gpr_RPort;
47 struct IBox container;
48 UWORD *pens = msg->gpr_GInfo->gi_DrInfo->dri_Pens;
49 ULONG len, x, y;
51 if (!(EG(o)->GadgetText)) return;
53 GetGadgetIBox((struct Gadget *)o, msg->gpr_GInfo, &container);
54 //dprintf("printgadgetlabel: o %p ibox %d %d %d %d\n",o,container.Left,container.Top,container.Width,container.Height);
56 SetFont(rp, msg->gpr_GInfo->gi_DrInfo->dri_Font);
58 switch (EG(o)->Flags & GFLG_LABELMASK)
60 case GFLG_LABELITEXT:
61 /* ITexts must not to be centered! */
63 /* frbuttonclass sets fg/bg/drawmode attributes */
64 int_PrintIText(rp, EG(o)->GadgetText, container.Left,container.Top, TRUE, IntuitionBase);
65 break;
67 case GFLG_LABELSTRING:
68 len = strlen ((STRPTR) EG(o)->GadgetText);
70 if (len > 0UL)
72 ULONG x;
73 ULONG y;
75 x = container.Left + (container.Width / 2);
76 x -= LabelWidth (rp,
77 (STRPTR)EG(o)->GadgetText, len, IntuitionBase) / 2;
78 y = container.Top + (container.Height / 2) +
79 rp->Font->tf_Baseline;
80 y -= rp->Font->tf_YSize / 2;
81 SetAPen (rp, pens[TEXTPEN]);
82 Move (rp, x, y);
83 RenderLabel (rp,
84 (STRPTR) EG(o)->GadgetText, len,
85 IntuitionBase);
87 break;
89 case GFLG_LABELIMAGE:
90 /* center image position */
92 x = container.Left + ((container.Width / 2) -
93 (IM(EG(o)->GadgetText)->Width / 2)) - IM(EG(o)->GadgetText)->LeftEdge;
95 y = container.Top + ((container.Height / 2) -
96 (IM(EG(o)->GadgetText)->Height / 2)) - IM(EG(o)->GadgetText)->TopEdge;
97 //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);
99 DrawImageState(rp, IM(EG(o)->GadgetText),
100 x, y,
101 ((EG(o)->Flags & GFLG_SELECTED) ? IDS_SELECTED : IDS_NORMAL ),
102 msg->gpr_GInfo->gi_DrInfo);
103 break;
105 } /* switch (EG(o)->Flags & GFLG_LABELMASK) */
109 /**********************************************************************************************/
111 /* Calculate the size of the Bounding Box of the gadget */
112 void CalcBBox (struct Window * window, struct Requester * req, struct Gadget * gadget,
113 struct BBox * bbox)
116 GetDomGadgetIBox(gadget, window->WScreen, window, req, (struct IBox *)bbox);
118 } /* CalcBBox */
120 /**********************************************************************************************/
122 /* Figure out the size of the gadget rectangle, taking relative
123 * positioning into account.
125 VOID GetGadgetIBox(struct Gadget *g, struct GadgetInfo *gi, struct IBox *ibox)
127 ibox->Left = g->LeftEdge;
128 ibox->Top = g->TopEdge;
129 ibox->Width = g->Width;
130 ibox->Height = g->Height;
132 if (gi)
134 if (g->Flags & GFLG_RELRIGHT)
135 ibox->Left += gi->gi_Domain.Width - 1;
137 if (g->Flags & GFLG_RELBOTTOM)
138 ibox->Top += gi->gi_Domain.Height - 1;
140 if (g->Flags & GFLG_RELWIDTH)
141 ibox->Width += gi->gi_Domain.Width;
143 if (g->Flags & GFLG_RELHEIGHT)
144 ibox->Height += gi->gi_Domain.Height;
147 DEBUG_GETGADGETIBOX(dprintf("GetGadgetIBox: Gadget 0x%lx GInfo 0x%lx Flags 0x%lx Left %ld Top %ld Width %ld Height %ld\n",
148 g, gi, g->Flags, ibox->Left, ibox->Top, ibox->Width, ibox->Height));
151 /**********************************************************************************************/
153 ULONG LabelWidth (struct RastPort * rp, STRPTR label, ULONG len,
154 struct IntuitionBase * IntuitionBase)
156 ULONG totalwidth, uscorewidth;
158 totalwidth = TextLength (rp, label, len);
159 uscorewidth = TextLength (rp, "_", 1);
161 while (len && *label)
163 if (*label == '_')
164 totalwidth -= uscorewidth;
166 label ++;
167 len --;
170 return totalwidth;
173 /**********************************************************************************************/
175 void RenderLabel (struct RastPort * rp, STRPTR label, ULONG len,
176 struct IntuitionBase * IntuitionBase)
178 ULONG renderlen;
179 ULONG uscorewidth;
181 while (*label)
183 renderlen = 0;
185 while (label[renderlen] && label[renderlen] != '_')
186 renderlen ++;
188 Text (rp, label, renderlen);
190 label += renderlen;
192 if (*label) /* '_' ? */
194 WORD cx, cy;
196 label ++; /* Skip */
198 uscorewidth = TextLength (rp, label, 1);
200 cx = rp->cp_x;
201 cy = rp->cp_y;
203 Move (rp, cx, cy+2);
204 Draw (rp, cx+uscorewidth-1, cy+2);
205 Move (rp, cx, cy);
210 /**********************************************************************************************/
212 VOID drawrect(struct RastPort *rp, WORD x1, WORD y1, WORD x2, WORD y2,
213 struct IntuitionBase *IntuitionBase)
215 Move(rp, x1, y1);
217 /* We RectFill() because it is generally faster than Draw()
218 (Draw() uses Set/GetPixel() while RectFill() can do higherlevel
219 clipping. Also it is MUCH faster in the x11gfx hidd.
222 RectFill(rp, x1, y1, x2 - 1, y1); /* Top */
223 RectFill(rp, x2, y1, x2, y2 - 1); /* Right */
224 RectFill(rp, x1 + 1, y2, x2, y2); /* Bottom */
225 RectFill(rp, x1, y1 + 1, x1, y2); /* Left */
227 return;
230 /**********************************************************************************************/
232 void GetGadgetDomain(struct Gadget *gad, struct Screen *scr, struct Window *win,
233 struct Requester *req, struct IBox *box)
235 switch (gad->GadgetType & (GTYP_GADGETTYPE & ~GTYP_SYSGADGET))
237 case GTYP_SCRGADGET:
238 box->Left = 0;
239 box->Top = 0;
240 box->Width = scr->Width;
241 box->Height = scr->Height;
243 break;
245 case GTYP_GZZGADGET:
246 /* stegerg: this means gadget is in window border! */
248 box->Left = 0;
249 box->Top = 0;
250 box->Width = win->Width;
251 box->Height = win->Height;
253 break;
255 case GTYP_REQGADGET:
256 box->Left = req->LeftEdge + win->BorderLeft;
257 box->Top = req->TopEdge + win->BorderTop;
258 box->Width = req->Width;
259 box->Height = req->Height;
261 break;
263 default:
264 if (win->Flags & WFLG_GIMMEZEROZERO)
266 /* stegerg: domain.left and domain.top must not be added
267 to gadget position when it is rendered, because gadgets
268 in the innerlayer of a gzz gadget are already shifted
269 thanks to the innerlayer. */
271 box->Left = win->BorderLeft;
272 box->Top = win->BorderTop;
274 box->Width = win->Width - win->BorderLeft - win->BorderRight;
275 box->Height = win->Height - win->BorderTop - win->BorderBottom;
278 else
280 box->Left = 0;
281 box->Top = 0;
282 box->Width = win->Width;
283 box->Height = win->Height;
287 break;
289 } /* switch (gadgettype) */
292 /**********************************************************************************************/
294 WORD GetGadgetLeft(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
296 struct IBox box;
298 GetGadgetDomain(gad, scr, win, req, &box);
300 return gad->LeftEdge + ADDREL(gad, GFLG_RELRIGHT, (&box), Width - 1);
303 /**********************************************************************************************/
305 WORD GetGadgetTop(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
307 struct IBox box;
309 GetGadgetDomain(gad, scr, win, req, &box);
311 return gad->TopEdge + ADDREL(gad, GFLG_RELBOTTOM, (&box), Height - 1);
314 /**********************************************************************************************/
316 WORD GetGadgetWidth(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
318 struct IBox box;
320 GetGadgetDomain(gad, scr, win, req, &box);
322 return gad->Width + ADDREL(gad, GFLG_RELWIDTH, (&box), Width);
325 /**********************************************************************************************/
327 WORD GetGadgetHeight(struct Gadget *gad, struct Screen *scr, struct Window *win, struct Requester *req)
329 struct IBox box;
331 GetGadgetDomain(gad, scr, win, req, &box);
333 return gad->Height + ADDREL(gad, GFLG_RELHEIGHT, (&box), Height);
336 /**********************************************************************************************/
338 /* gadget box in screen coords */
339 void GetScrGadgetIBox(struct Gadget *gad, struct Screen *scr, struct Window *win,
340 struct Requester *req, struct IBox *box)
342 GetWinGadgetIBox(gad, scr, win, req, box);
344 if (win)
346 box->Left += win->LeftEdge;
347 box->Top += win->TopEdge;
351 /**********************************************************************************************/
353 /* gadget box relative to upper left window edge */
354 void GetWinGadgetIBox(struct Gadget *gad, struct Screen *scr, struct Window *win,
355 struct Requester *req, struct IBox *box)
357 struct IBox domain;
359 GetGadgetDomain(gad, scr, win, req, &domain);
361 box->Left = gad->LeftEdge;
362 box->Top = gad->TopEdge;
363 box->Width = gad->Width;
364 box->Height = gad->Height;
366 if (gad->Flags & GFLG_RELRIGHT)
367 box->Left += domain.Width - 1;
369 if (gad->Flags & GFLG_RELBOTTOM)
370 box->Top += domain.Height - 1;
372 if (gad->Flags & GFLG_RELWIDTH)
373 box->Width += domain.Width;
375 if (gad->Flags & GFLG_RELHEIGHT)
376 box->Height += domain.Height;
378 box->Left += domain.Left;
379 box->Top += domain.Top;
382 /**********************************************************************************************/
384 /* gadget box in domain coords */
385 void GetDomGadgetIBox(struct Gadget *gad, struct Screen *scr, struct Window *win,
386 struct Requester *req, struct IBox *box)
388 struct IBox domain;
390 GetWinGadgetIBox(gad, scr, win, req, box);
391 GetGadgetDomain(gad, scr, win, req, &domain);
393 box->Left -= domain.Left;
394 box->Top -= domain.Top;
397 /**********************************************************************************************/
399 /* gadget bounds in screen coords */
400 void GetScrGadgetBounds(struct Gadget *gad, struct Screen *scr, struct Window *win,
401 struct Requester *req, struct IBox *box)
403 struct IBox domain;
405 if (gad->Flags & GFLG_EXTENDED)
407 if (EG(gad)->MoreFlags & GMORE_BOUNDS)
409 GetGadgetDomain(gad, scr, win, req, &domain);
411 box->Left = domain.Left +
412 EG(gad)->BoundsLeftEdge + ADDREL(gad, GFLG_RELRIGHT, (&domain), Width - 1) +
413 (win ? win->LeftEdge : 0);
415 box->Top = domain.Top +
416 EG(gad)->BoundsTopEdge + ADDREL(gad, GFLG_RELBOTTOM, (&domain), Height - 1) +
417 (win ? win->TopEdge : 0);
419 box->Width = EG(gad)->BoundsWidth + ADDREL(gad, GFLG_RELWIDTH, (&domain), Width);
421 box->Height = EG(gad)->BoundsHeight + ADDREL(gad, GFLG_RELHEIGHT, (&domain), Height);
423 return;
425 } /* if (gad->MoreFlags & GMORE_BOUNDS) */
427 } /* if (gad->Flags & GFLG_EXTENDED) */
429 /* if gadget does not have bounds return box */
431 GetScrGadgetIBox(gad, scr, win, req, box);
434 /**********************************************************************************************/
436 /* gadget bounds relative to upper left window edge */
437 void GetWinGadgetBounds(struct Gadget *gad, struct Screen *scr, struct Window *win,
438 struct Requester *req, struct IBox *box)
440 GetScrGadgetBounds(gad, scr, win, req, box);
442 if (win)
444 box->Left -= win->LeftEdge;
445 box->Top -= win->TopEdge;
449 /**********************************************************************************************/
451 /* gadget bounds in domain coords */
452 void GetDomGadgetBounds(struct Gadget *gad, struct Screen *scr, struct Window *win,
453 struct Requester *req, struct IBox *box)
455 struct IBox domain;
457 GetWinGadgetBounds(gad, scr, win, req, box);
458 GetGadgetDomain(gad, scr, win, req, &domain);
460 box->Left -= domain.Left;
461 box->Top -= domain.Top;
464 /**********************************************************************************************/
466 void EraseRelGadgetArea(struct Window *win, struct Rectangle *clipto,
467 BOOL onlydamagelist, struct IntuitionBase *IntuitionBase)
469 struct Gadget *gad;
470 struct Region *old_clipregion = NULL; /* shut up the compiler */
471 struct RastPort *rp, *rp2;
472 struct Layer *lay;
473 struct IBox box;
474 WORD old_scroll_x = 0, old_scroll_y = 0, i, num_loops;
476 DEBUG_ERASERELGADGETAREA(dprintf("EraseRelGadgetArea: win 0x%lx onlydamage %d\n",
477 win, onlydamagelist));
479 rp = win->RPort;
480 rp2 = win->BorderRPort;
482 if (rp->Layer == rp2->Layer)
484 num_loops = 1;
486 else
488 num_loops = 2;
489 clipto = NULL; /* Don't do any border clipping for GZZ windows */
492 for(i = 0; i < num_loops; i++, rp = rp2)
494 lay = rp->Layer;
496 LockLayer(0, lay);
498 if (!onlydamagelist)
500 old_scroll_x = lay->Scroll_X;
501 old_scroll_y = lay->Scroll_Y;
502 old_clipregion = InstallClipRegion(lay, NULL);
505 gad = win->FirstGadget;
506 while(gad)
508 BOOL checkgad = FALSE;
510 DEBUG_ERASERELGADGETAREA(dprintf("EraseRelGadgetArea: Gadget 0x%lx Flags 0x%lx Type 0x%lx Activation 0x%lx %d,%d %d×%d\n",
511 gad, gad->Flags, gad->GadgetType, gad->Activation,
512 gad->LeftEdge, gad->TopEdge, gad->Width, gad->Height));
514 if (num_loops == 1)
516 checkgad = TRUE;
518 else
520 if (i == 0)
522 if (!IS_BORDER_GADGET(gad)) checkgad = TRUE;
524 else
526 if (IS_BORDER_GADGET(gad)) checkgad = TRUE;
530 if (checkgad)
532 if (gad->Flags & (GFLG_RELRIGHT | GFLG_RELBOTTOM |
533 GFLG_RELWIDTH | GFLG_RELHEIGHT | GFLG_RELSPECIAL))
535 struct Rectangle rect;
537 GetDomGadgetBounds(gad, win->WScreen, win, NULL, &box);
539 if ((box.Width > 0) && (box.Height > 0))
541 rect.MinX = box.Left;
542 rect.MinY = box.Top;
543 rect.MaxX = box.Left + box.Width - 1;
544 rect.MaxY = box.Top + box.Height - 1;
546 if (!(lay->Flags & LAYERSUPER))
548 DEBUG_ERASERELGADGETAREA(dprintf("EraseRelGadgetArea: gad 0x%lx add (%d,%d)-(%d,%d)\n", gad, rect.MinX, rect.MinY, rect.MaxX, rect.MaxY));
550 OrRectRegion(lay->DamageList, &rect);
551 lay->Flags |= LAYERREFRESH;
554 if (!onlydamagelist)
556 if (!clipto || AndRectRect(&rect, clipto, &rect))
558 EraseRect(rp, rect.MinX, rect.MinY, rect.MaxX, rect.MaxY);
566 } /* if (checkgad) */
568 gad = gad->NextGadget;
570 } /* while(gad) */
572 if (!onlydamagelist)
574 InstallClipRegion(lay, old_clipregion);
575 lay->Scroll_X = old_scroll_x;
576 lay->Scroll_Y = old_scroll_y;
579 UnlockLayer(lay);
581 } /* for(i = 0; i < num_loops; i++, rp = rp2) */
585 /**********************************************************************************************/
587 void RenderDisabledPattern(struct RastPort *rp, struct DrawInfo *dri, WORD x1, WORD y1,
588 WORD x2, WORD y2, struct IntuitionBase *IntuitionBase)
590 UWORD pen;
591 UWORD pattern[] = { 0x8888, 0x2222 };
593 DEBUG_RENDERDISABLEPATTERN(dprintf("RenderDisabledPattern: rp 0x%lx dri 0x%lx x1 %ld y1 %ld x2 %ld y2 %ld\n",
594 rp,dri,x1,y1,x2,y2));
596 if (dri)
598 pen = dri->dri_Pens[SHADOWPEN];
600 else
602 pen = 1;
605 SetDrMd( rp, JAM1 );
606 SetAPen( rp, pen );
607 SetAfPt( rp, pattern, 1);
609 /* render disable pattern */
610 RectFill(rp, x1, y1, x2, y2);
612 SetAfPt (rp, NULL, 0);
616 /**********************************************************************************************/
618 ULONG GetGadgetState(struct Window *window, struct Gadget *gadget)
620 ULONG state = IDS_NORMAL;
622 if (IS_BORDER_GADGET(gadget)
623 && !(window->Flags & (WFLG_WINDOWACTIVE | WFLG_TOOLBOX)))
625 if (gadget->Flags & GFLG_DISABLED)
627 if (gadget->Flags & GFLG_SELECTED)
629 state = IDS_INACTIVEDISABLED; /* Hmm ... there's no INACTIVEDISABLEDSELECTED */
631 else
633 state = IDS_INACTIVEDISABLED;
636 else
638 if (gadget->Flags & GFLG_SELECTED)
640 state = IDS_INACTIVESELECTED;
642 else
644 state = IDS_INACTIVENORMAL;
648 else
650 if (gadget->Flags & GFLG_DISABLED)
652 if (gadget->Flags & GFLG_SELECTED)
654 state = IDS_SELECTEDDISABLED;
656 else
658 state = IDS_DISABLED;
661 else
663 if (gadget->Flags & GFLG_SELECTED)
665 state = IDS_SELECTED;
667 else
669 state = IDS_NORMAL;
674 return state;
677 /**********************************************************************************************/
679 void SetupGInfo(struct GadgetInfo *gi, struct Window *win, struct Requester *req,
680 struct Gadget *gad, struct IntuitionBase *IntuitionBase)
682 struct Window *tw = 0;
684 DEBUG_SETUPGINFO(dprintf("SetupGInfo: gi %p win %p req %p gadget %p (Type 0x%x)\n",
685 gi, win, req, gad, gad->GadgetType));
687 memset(gi, 0, sizeof(*gi));
689 if (req)
691 tw = req->RWindow;
693 else
695 tw = win;
698 if (tw)
700 if (IS_SCREEN_GADGET(gad))
702 gi->gi_Window = NULL;
703 gi->gi_Screen = (struct Screen *)tw;
704 gi->gi_Pens.DetailPen = 0;
705 gi->gi_Pens.BlockPen = 0;
707 else
709 gi->gi_Window = tw;
710 gi->gi_Screen = tw->WScreen;
711 gi->gi_Pens.DetailPen = tw->DetailPen;
712 gi->gi_Pens.BlockPen = tw->BlockPen;
714 gi->gi_Requester = req;
715 gi->gi_DrInfo = GetScreenDrawInfo (gi->gi_Screen);
717 SET_GI_RPORT(gi, tw, req, gad);
719 gi->gi_Layer = gi->gi_RastPort ? gi->gi_RastPort->Layer : NULL;
721 GetGadgetDomain(gad, gi->gi_Screen, gi->gi_Window, req, &gi->gi_Domain);
722 } /* if (tw) */
724 DEBUG_SETUPGINFO(dprintf("SetGInfo: Win %p Req %p RP %p Layer %p\n",
725 gi->gi_Window, gi->gi_Requester, gi->gi_RastPort, gi->gi_Layer));
728 /**********************************************************************************************/