Belarusian
[AROS.git] / rom / intuition / sysrequest_intern.c
blobe7f3bc4b4abac638d94186ec79c9882cbfafb78b
1 /*
2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4 $Id$
5 */
7 #define DEBUG_BUILDSYSREQUEST(x)
8 #define DEBUG_FREESYSREQUEST(x)
9 #define DEBUG_SYSREQHANDLER(x)
11 /**********************************************************************************************/
12 #include <proto/exec.h>
13 #include <proto/intuition.h>
14 #include <proto/graphics.h>
15 #include <proto/keymap.h>
16 #include <proto/utility.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <clib/macros.h>
21 #include <exec/memory.h>
22 #include <intuition/gadgetclass.h>
23 #include <intuition/imageclass.h>
24 #include <intuition/screens.h>
25 #include <graphics/rastport.h>
26 #include <graphics/gfxmacros.h>
27 #include <utility/tagitem.h>
28 #include "intuition_intern.h"
30 extern UWORD BgPattern[];
32 /**********************************************************************************************/
34 struct sysreqdims
36 UWORD width; /* width of the requester */
37 UWORD height; /* height of the requester */
38 UWORD fontheight; /* height of the default font */
39 UWORD itextleft;
40 int gadgets; /* number of gadgets */
41 UWORD gadgetwidth; /* width of a gadget */
44 /**********************************************************************************************/
46 static BOOL buildsysreq_calculatedims(struct sysreqdims *dims,
47 struct Screen *scr,
48 struct IntuiText *itext,
49 STRPTR *gadgetlabels,
50 struct IntuitionBase *IntuitionBase);
51 static struct Gadget *buildsysreq_makegadgets(struct sysreqdims *dims,
52 STRPTR *gadgetlabels,
53 struct Screen *scr,
54 struct IntuitionBase *IntuitionBase);
55 static void buildsysreq_draw(struct sysreqdims *dims, struct IntuiText *itext,
56 struct Window *win, struct Screen *scr,
57 struct Gadget *gadgets,
58 struct IntuitionBase *IntuitionBase);
60 static void ReqITextSize(struct Screen *scr, struct IntuiText *itext,
61 WORD *width, WORD *height,
62 struct IntuitionBase *IntuitionBase);
64 static void ReqPrintIText(struct Screen *scr, struct DrawInfo *dri,
65 struct RastPort *rp, struct IntuiText *itext, WORD x, WORD y,
66 struct IntuitionBase *IntuitionBase);
68 /**********************************************************************************************/
70 struct Window *buildsysreq_intern(struct Window *window, STRPTR reqtitle, struct IntuiText *bodytext,
71 struct IntuiText *postext, struct IntuiText *negtext,
72 ULONG IDCMPFlags, WORD width, WORD height, struct IntuitionBase *IntuitionBase)
74 struct Screen *scr = NULL, *lockedscr = NULL;
75 struct Window *req;
76 struct Gadget *gadgets;
77 STRPTR gadgetlabels[3];
78 struct sysreqdims dims;
79 struct IntRequestUserData *requserdata;
81 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: window 0x%p body <%s> postext <%s> negtext <%s> IDCMPFlags 0x%lx width %ld height %ld\n",
82 window,
83 bodytext ? (char *) bodytext->IText : "<NULL>",
84 (postext && postext->IText) ? (char *) postext->IText : "<NULL>",
85 (negtext && negtext->IText) ? (char *) negtext->IText : "<NULL>",
86 IDCMPFlags,
87 (LONG) width,
88 (LONG) height));
90 /* negtext and bodytest must be specified, postext is optional */
91 if (!negtext || !bodytext) return NULL;
93 /* get requester title */
94 if (!reqtitle)
95 reqtitle = window ? window->Title : (STRPTR)"System Request"; /* stegerg: should be localized */
97 /* get screen and screendrawinfo */
98 if (window)
99 scr = window->WScreen;
100 if (!scr)
102 scr = LockPubScreen(NULL);
103 if (!scr)
104 return NULL;
105 lockedscr = scr;
108 if (postext)
110 dims.gadgets = 2;
112 gadgetlabels[0] = postext->IText;
113 gadgetlabels[1] = negtext->IText;
114 gadgetlabels[2] = NULL;
116 else
118 dims.gadgets = 1;
120 gadgetlabels[0] = negtext->IText;
121 gadgetlabels[1] = NULL;
124 /* EXPERIMENTAL: Obey user-supplied size if the text fits into it. Processed in buildsysreq_calculatedims().
125 This is experimental. Currently DisplayAlert() relies on ability to specify requester size.
126 Requester size actually determines inner text box size - sonic. */
127 dims.width = width;
128 dims.height = height;
130 /* create everything */
132 if (buildsysreq_calculatedims(&dims, scr,
133 bodytext, gadgetlabels, IntuitionBase))
135 gadgets = buildsysreq_makegadgets(&dims, gadgetlabels, scr, IntuitionBase);
136 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: gadgets 0x%p\n", gadgets));
137 if (gadgets)
139 requserdata = AllocVec(sizeof(struct IntRequestUserData),
140 MEMF_ANY|MEMF_CLEAR);
141 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: requserdata 0x%p\n", requserdata));
142 if (requserdata)
144 struct TagItem win_tags[] =
146 {WA_Width , dims.width },
147 {WA_Height , dims.height },
148 {WA_Left , (scr->Width/2) - (dims.width/2) },
149 {WA_Top , (scr->Height/2) - (dims.height/2) },
150 {WA_IDCMP , (IDCMP_GADGETUP | IDCMP_RAWKEY | (IDCMPFlags & ~IDCMP_VANILLAKEY))},
151 {WA_Gadgets , (IPTR)gadgets },
152 {WA_Title , (IPTR)reqtitle },
153 {(lockedscr ? WA_PubScreen : WA_CustomScreen) , (IPTR)scr },
154 {WA_Flags , WFLG_DRAGBAR |
155 WFLG_DEPTHGADGET |
156 WFLG_ACTIVATE |
157 WFLG_RMBTRAP /*|
158 WFLG_SIMPLE_REFRESH*/ },
159 {TAG_DONE }
162 req = OpenWindowTagList(NULL, win_tags);
163 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: req 0x%p\n", req));
164 if (req)
166 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
168 req->UserData = (BYTE *)requserdata;
169 requserdata->IDCMP = IDCMPFlags;
170 requserdata->GadgetLabels = NULL;
171 requserdata->Gadgets = gadgets;
172 requserdata->NumGadgets = dims.gadgets;
173 buildsysreq_draw(&dims, bodytext,
174 req, scr, gadgets, IntuitionBase);
175 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: gadgets 0x%p\n", gadgets));
177 return req;
180 /* opening requester failed -> free everything */
181 FreeVec(requserdata);
183 intrequest_freegadgets(gadgets, IntuitionBase);
187 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
189 return NULL;
192 /**********************************************************************************************/
194 LONG sysreqhandler_intern(struct Window *window, ULONG *IDCMPFlagsPtr, BOOL WaitInput, struct IntuitionBase *IntuitionBase)
196 struct IntuiMessage *msg;
197 LONG result;
199 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: window 0x%lx IDCMPPtr 0x%lx WaitInput 0x%lx\n",
200 (ULONG) window,
201 (ULONG) IDCMPFlagsPtr,
202 (ULONG) WaitInput));
204 if (window == 0)
206 result = 0;
208 else if (window == (struct Window *)1)
210 result = 1;
212 else
214 result = -2;
216 if (WaitInput)
218 WaitPort(window->UserPort);
220 while ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)))
222 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: msg 0x%lx class 0x%lx\n", (ULONG) msg, msg->Class));
223 switch (msg->Class)
225 /* we don't use VANILLA (filtered from useridcmp!) to get
226 all events we need */
227 case IDCMP_RAWKEY:
229 #define RKBUFLEN 1
231 struct InputEvent ie;
232 char rawbuffer[RKBUFLEN];
234 ie.ie_Class = IECLASS_RAWKEY;
235 ie.ie_SubClass = 0;
236 ie.ie_Code = msg->Code;
237 ie.ie_Qualifier = 0;
238 ie.ie_EventAddress = (APTR *) *((ULONG *)msg->IAddress);
240 if (KeymapBase && MapRawKey(&ie,rawbuffer,RKBUFLEN,0))
242 if (msg->Qualifier & IEQUALIFIER_LCOMMAND)
244 if (ToUpper(rawbuffer[0]) == ToUpper(GetPrivIBase(IntuitionBase)->IControlPrefs.ic_ReqTrue))
246 if (((struct IntRequestUserData *)window->UserData)->NumGadgets > 1)
248 result = 1;
250 else
252 result = 0;
256 if (ToUpper(rawbuffer[0]) == ToUpper(GetPrivIBase(IntuitionBase)->IControlPrefs.ic_ReqFalse))
258 result = 0;
262 break;
265 case IDCMP_GADGETUP:
266 result = ((struct Gadget *)msg->IAddress)->GadgetID;
267 break;
269 default:
270 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: unknown IDCMP\n"));
271 if (result == -2)
273 if (msg->Class & ((struct IntRequestUserData *)window->UserData)->IDCMP)
275 if (IDCMPFlagsPtr) *IDCMPFlagsPtr = msg->Class;
276 result = -1;
279 break;
281 ReplyMsg((struct Message *)msg);
283 } /* while ((msg = (struct IntuiMessage *)GetMsg(window->UserPort))) */
285 } /* real window */
287 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: Result 0x%lx\n",result));
289 return result;
292 /**********************************************************************************************/
294 void freesysreq_intern(struct Window *window, struct IntuitionBase *IntuitionBase)
296 struct Screen *scr;
297 struct Gadget *gadgets;
298 STRPTR *gadgetlabels;
299 struct IntRequestUserData *requserdata;
301 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: window 0x%lx\n", (ULONG) window));
303 if ((window == NULL) || (window == (void *)1L))
304 return;
306 scr = window->WScreen;
308 requserdata = (struct IntRequestUserData *)window->UserData;
310 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: requserdata 0x%lx\n", (ULONG) requserdata));
312 gadgets = requserdata->Gadgets;
314 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: gadgets 0x%lx\n", (ULONG) gadgets));
316 /* Remove gadgets before closing window to avoid conflicts with system gadgets */
317 RemoveGList(window, gadgets, requserdata->NumGadgets);
319 gadgetlabels = requserdata->GadgetLabels;
321 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: gadgetlabels 0x%lx\n", (ULONG) gadgetlabels));
323 window->UserData = 0;
324 CloseWindow(window);
325 intrequest_freegadgets(gadgets, IntuitionBase);
326 intrequest_freelabels(gadgetlabels, IntuitionBase);
328 #ifdef SKINS
329 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: freeitext 0x%lx\n", (ULONG) requserdata->freeitext));
330 if (requserdata->freeitext) intrequest_freeitext(requserdata->Text,IntuitionBase);
331 if (requserdata->backfilldata.image) int_FreeCustomImage(TYPE_REQUESTERCLASS,requserdata->dri,IntuitionBase);
332 if (requserdata->Logo) int_FreeCustomImage(TYPE_REQUESTERCLASS,requserdata->dri,IntuitionBase);
333 if (requserdata->ReqGadgets) FreeVec(requserdata->ReqGadgets);
334 if (requserdata->dri) FreeScreenDrawInfo(requserdata->ReqScreen,(struct DrawInfo *)requserdata->dri);
335 #endif
336 FreeVec(requserdata);
337 } /* FreeSysRequest */
339 /**********************************************************************************************/
341 /* draw the contents of the requester */
342 static void buildsysreq_draw(struct sysreqdims *dims, struct IntuiText *itext,
343 struct Window *req, struct Screen *scr,
344 struct Gadget *gadgets,
345 struct IntuitionBase *IntuitionBase)
347 struct TagItem frame_tags[] =
349 {IA_Left , req->BorderLeft + OUTERSPACING_X },
350 {IA_Top , req->BorderTop + OUTERSPACING_Y },
351 {IA_Width , req->Width - req->BorderLeft - req->BorderRight - OUTERSPACING_X * 2 },
352 {IA_Height , req->Height - req->BorderTop - req->BorderBottom -
353 dims->fontheight - OUTERSPACING_Y * 2 -
354 TEXTGADGETSPACING - BUTTONBORDER_Y * 2 },
355 {IA_Recessed , TRUE },
356 {IA_EdgesOnly , FALSE },
357 {TAG_DONE }
359 struct DrawInfo *dri;
360 struct Image *frame;
362 dri = GetScreenDrawInfo(scr);
363 if (!dri)
364 return;
366 SetFont(req->RPort, dri->dri_Font);
368 /* draw background pattern */
369 SetABPenDrMd(req->RPort,
370 dri->dri_Pens[SHINEPEN], dri->dri_Pens[BACKGROUNDPEN],
371 JAM1);
372 SetAfPt(req->RPort, BgPattern, 1);
373 RectFill(req->RPort, req->BorderLeft,
374 req->BorderTop,
375 req->Width - req->BorderRight,
376 req->Height - req->BorderBottom);
377 SetAfPt(req->RPort, NULL, 0);
379 /* draw textframe */
380 frame = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
381 if (frame)
383 DrawImageState(req->RPort, frame, 0, 0, IDS_NORMAL, dri);
384 DisposeObject((Object *)frame);
387 /* draw text */
388 ReqPrintIText(scr, dri, req->RPort, itext,
389 dims->itextleft, req->BorderTop + OUTERSPACING_Y + TEXTBOXBORDER_Y,
390 IntuitionBase);
392 /* draw gadgets */
393 RefreshGList(gadgets, req, NULL, -1L);
395 FreeScreenDrawInfo(scr, dri);
398 /**********************************************************************************************/
400 /* calculate dimensions of the requester */
401 static BOOL buildsysreq_calculatedims(struct sysreqdims *dims,
402 struct Screen *scr,
403 struct IntuiText *itext,
404 STRPTR *gadgetlabels,
405 struct IntuitionBase *IntuitionBase)
408 LONG currentgadget = 0;
409 WORD itextwidth, itextheight;
410 UWORD textboxwidth = 0, gadgetswidth; /* width of upper/lower part */
411 UWORD textboxheight;
413 /* calculate height of requester */
414 dims->fontheight = scr->RastPort.Font->tf_YSize;
416 ReqITextSize(scr, itext, &itextwidth, &itextheight, IntuitionBase);
418 textboxheight = scr->WBorTop + dims->fontheight + 1 +
419 OUTERSPACING_Y +
420 TEXTBOXBORDER_Y +
421 itextheight +
422 TEXTBOXBORDER_Y +
423 TEXTGADGETSPACING +
424 BUTTONBORDER_Y +
425 dims->fontheight +
426 BUTTONBORDER_Y +
427 OUTERSPACING_Y +
428 scr->WBorBottom;
431 * Ensure that text fits into requested height.
432 * Note that calculated size will override user-supplied size if the latter
433 * is not large enough, but not vice versa.
434 * This behavior is experimental. DisplayAlert() currently relies on it - sonic
435 * See also similar check for width below.
437 if (textboxheight > dims->height)
438 dims->height = textboxheight;
440 if (dims->height > scr->Height)
441 return FALSE;
443 textboxwidth = itextwidth + TEXTBOXBORDER_X * 2;
445 /* calculate width of gadgets */
446 dims->gadgetwidth = 0;
447 while (gadgetlabels[currentgadget])
449 UWORD gadgetwidth; /* width of current gadget */
451 gadgetwidth = TextLength(&scr->RastPort, gadgetlabels[currentgadget],
452 strlen(gadgetlabels[currentgadget]));
453 if (gadgetwidth > dims->gadgetwidth)
454 dims->gadgetwidth = gadgetwidth;
455 currentgadget++;
457 dims->gadgetwidth += BUTTONBORDER_X * 2;
458 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * dims->gadgets - GADGETGADGETSPACING;
460 /* calculate width of requester and req text position */
461 dims->itextleft = scr->WBorLeft + OUTERSPACING_X + TEXTBOXBORDER_X;
462 if (textboxwidth <= gadgetswidth)
464 dims->itextleft += (gadgetswidth - textboxwidth) / 2;
465 textboxwidth = gadgetswidth;
468 /* EXPERIMENTAL: Ensure that text fits into requested width */
469 if (textboxwidth > dims->width)
470 dims->width = textboxwidth;
472 dims->width += OUTERSPACING_X * 2 + scr->WBorLeft + scr->WBorRight;
473 if (dims->width > scr->Width)
474 return FALSE;
476 return TRUE;
479 /**********************************************************************************************/
481 /* make all the gadgets */
482 static struct Gadget *buildsysreq_makegadgets(struct sysreqdims *dims,
483 STRPTR *gadgetlabels,
484 struct Screen *scr,
485 struct IntuitionBase *IntuitionBase)
487 struct TagItem frame_tags[] =
489 {IA_FrameType, FRAME_BUTTON },
490 {IA_Width , dims->gadgetwidth },
491 {IA_Height , dims->fontheight + BUTTONBORDER_Y * 2},
492 {TAG_DONE }
494 struct Gadget *gadgetlist, *thisgadget = NULL;
495 struct Image *gadgetframe;
496 WORD currentgadget;
497 UWORD xoffset, restwidth;
499 if (gadgetlabels[0] == NULL)
500 return NULL;
502 gadgetframe = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
503 if (!gadgetframe)
504 return NULL;
506 restwidth = dims->width - scr->WBorLeft - scr->WBorRight - OUTERSPACING_X * 2;
507 if (dims->gadgets == 1)
508 xoffset = scr->WBorLeft + OUTERSPACING_X + (restwidth - dims->gadgetwidth) / 2;
509 else
511 xoffset = scr->WBorLeft + OUTERSPACING_X;
512 restwidth -= dims->gadgets * dims->gadgetwidth;
515 gadgetlist = NULL;
517 for (currentgadget = 0; gadgetlabels[currentgadget]; currentgadget++)
519 WORD gadgetid = (currentgadget == (dims->gadgets - 1)) ? 0 : currentgadget + 1;
520 struct TagItem gad_tags[] =
522 {GA_ID , gadgetid },
523 {GA_Previous , (IPTR)thisgadget },
524 {GA_Left , xoffset },
525 {GA_Top , dims->height -
526 scr->WBorBottom - dims->fontheight -
527 OUTERSPACING_Y - BUTTONBORDER_Y * 2 },
528 {GA_Image , (IPTR)gadgetframe },
529 {GA_RelVerify , TRUE },
530 {TAG_DONE }
532 struct TagItem gad2_tags[] =
534 {GA_Text , (IPTR)gadgetlabels[currentgadget] },
535 {TAG_DONE }
538 thisgadget = NewObjectA(NULL, FRBUTTONCLASS, gad_tags);
541 if (currentgadget == 0)
542 gadgetlist = thisgadget;
544 if (!thisgadget)
546 intrequest_freegadgets(gadgetlist, IntuitionBase);
547 return NULL;
550 SetAttrsA(thisgadget, gad2_tags);
552 if ((currentgadget + 1) != dims->gadgets)
554 xoffset += dims->gadgetwidth +
555 restwidth / (dims->gadgets - currentgadget - 1);
556 restwidth -= restwidth / (dims->gadgets - currentgadget - 1);
560 return gadgetlist;
563 /**********************************************************************************************/
565 static void ReqITextSize(struct Screen *scr, struct IntuiText *itext,
566 WORD *width, WORD *height,
567 struct IntuitionBase *IntuitionBase)
569 WORD w, h;
571 *width = 0;
572 *height = 0;
574 while(itext)
576 w = TextLength(&scr->RastPort, itext->IText, strlen(itext->IText));
577 h = scr->RastPort.Font->tf_YSize;
579 if (itext->LeftEdge > 0) w += itext->LeftEdge;
580 if (itext->TopEdge > 0) h += itext->TopEdge;
582 if (w > *width) *width = w;
583 if (h > *height) *height = h;
585 itext = itext->NextText;
589 /**********************************************************************************************/
591 static void ReqPrintIText(struct Screen *scr, struct DrawInfo *dri,
592 struct RastPort *rp, struct IntuiText *itext, WORD x, WORD y,
593 struct IntuitionBase *IntuitionBase)
595 SetDrMd(rp, JAM1);
596 SetAPen(rp, dri->dri_Pens[TEXTPEN]);
598 /* Experimental: obey font specified in supplied IntuiText structures.
599 Makes sense because coordinates specified in these structures are taken
600 into account, but i guess they are specified according to font size.
601 Currently DisplayAlert() relies on this behavior - sonic.
602 while(itext)
604 Move(rp, x + itext->LeftEdge,
605 y + itext->TopEdge + scr->RastPort.Font->tf_Baseline);
606 Text(rp, itext->IText, strlen(itext->IText));
608 itext = itext->NextText;
610 int_PrintIText(rp, itext, x, y, TRUE, IntuitionBase);
613 /**********************************************************************************************/