Minor fixes to comments.
[AROS.git] / rom / intuition / buildeasyrequestargs.c
blob55c794cc08db1d28b41dbf48ed1017dd2edc4f76
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4 $Id$
5 */
7 #define DEBUG_BUILDEASYREQUEST(x)
9 /**********************************************************************************************/
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <string.h>
14 #include <clib/macros.h>
15 #include <aros/asmcall.h>
16 #include <proto/exec.h>
17 #include <proto/intuition.h>
18 #include <proto/graphics.h>
19 #include <exec/memory.h>
20 #include <exec/rawfmt.h>
21 #include <intuition/gadgetclass.h>
22 #include <intuition/imageclass.h>
23 #include <intuition/screens.h>
24 #include <graphics/rastport.h>
25 #include <graphics/gfxmacros.h>
26 #include <utility/tagitem.h>
27 #include <aros/debug.h>
28 #include "intuition_intern.h"
31 /**********************************************************************************************/
33 struct reqdims
35 UWORD width; /* width of the requester */
36 UWORD height; /* height of the requester */
37 UWORD fontheight; /* height of the default font */
38 UWORD fontxheight; /* extra height */
39 UWORD textleft;
40 UWORD textheight; /* Height of text frame */
41 WORD gadgets; /* number of gadgets */
42 UWORD gadgetwidth; /* width of a gadget */
45 /**********************************************************************************************/
47 static STRPTR *buildeasyreq_makelabels(struct reqdims *dims,CONST_STRPTR labeltext, APTR args, struct IntuitionBase *IntuitionBase);
48 static STRPTR buildeasyreq_formattext(CONST_STRPTR textformat, APTR args, APTR *nextargptr, struct IntuitionBase *IntuitionBase);
49 static BOOL buildeasyreq_calculatedims(struct reqdims *dims,
50 struct Screen *scr,
51 STRPTR formattedtext,
52 STRPTR *gadgetlabels,
53 struct IntuitionBase *IntuitionBase);
54 static struct Gadget *buildeasyreq_makegadgets(struct reqdims *dims,
55 STRPTR *gadgetlabels,
56 struct Screen *scr,
57 struct IntuitionBase *IntuitionBase);
58 static void buildeasyreq_draw(struct reqdims *dims, STRPTR text,
59 struct Window *win, struct Screen *scr,
60 struct Gadget *gadgets,
61 struct IntuitionBase *IntuitionBase);
63 static int charsinstring(CONST_STRPTR string, char c);
65 /*****************************************************************************
67 NAME */
68 #include <proto/intuition.h>
69 #include <exec/types.h>
70 #include <intuition/intuition.h>
72 AROS_LH4(struct Window *, BuildEasyRequestArgs,
74 /* SYNOPSIS */
75 AROS_LHA(struct Window *, RefWindow, A0),
76 AROS_LHA(struct EasyStruct *, easyStruct, A1),
77 AROS_LHA(ULONG , IDCMP, D0),
78 AROS_LHA(APTR , Args, A3),
80 /* LOCATION */
81 struct IntuitionBase *, IntuitionBase, 99, Intuition)
83 /* FUNCTION
84 Opens a requester, which provides one or more choices. The control is
85 returned to the application after the requester was opened. It is
86 handled by subsequent calls to SysReqHandler() and closed by calling
87 FreeSysRequest().
89 INPUTS
90 RefWindow - A reference window. If NULL, the requester opens on
91 the default public screen.
92 easyStruct - The EasyStruct structure (<intuition/intuition.h>),
93 which describes the requester.
94 IDCMP - IDCMP flags, which should satisfy the requester, too. This is
95 useful for requesters, which want to listen to disk changes,
96 etc. Note that this is not a pointer to the flags as in
97 EasyRequestArgs().
98 Args - The arguments for easyStruct->es_TextFormat.
100 RESULT
101 Returns a pointer to the requester. Use this pointer only for calls
102 to SysReqHandler() and FreeSysRequest().
104 NOTES
106 EXAMPLE
108 BUGS
110 SEE ALSO
111 EasyRequestArgs(), SysReqHandler(), FreeSysRequest()
113 INTERNALS
115 HISTORY
117 *****************************************************************************/
119 AROS_LIBFUNC_INIT
121 struct Screen *scr = NULL, *lockedscr = NULL;
122 struct Window *req;
123 struct Gadget *gadgets;
124 CONST_STRPTR reqtitle;
125 STRPTR formattedtext;
126 STRPTR *gadgetlabels;
127 struct reqdims dims;
128 struct IntRequestUserData *requserdata;
129 APTR nextarg;
131 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: window 0x%p easystruct 0x%p IDCMPFlags 0x08%x args 0x%p\n",
132 RefWindow, easyStruct, IDCMP, Args));
134 if (!easyStruct)
135 return FALSE;
137 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: easy title <%s> Format <%s> Gadgets <%s>\n",
138 easyStruct->es_Title,
139 easyStruct->es_TextFormat,
140 easyStruct->es_GadgetFormat));
142 /* get requester title */
143 reqtitle = easyStruct->es_Title;
144 if ((!reqtitle) && (RefWindow))
145 reqtitle = RefWindow->Title;
147 if (!reqtitle) reqtitle = "System Request"; /* stegerg: should be localized */
149 /* get screen and screendrawinfo */
150 if (RefWindow)
151 scr = RefWindow->WScreen;
153 if (!scr)
155 scr = LockPubScreen(NULL);
156 if (!scr)
157 return FALSE;
159 lockedscr = scr;
162 /* create everything */
163 formattedtext = buildeasyreq_formattext(easyStruct->es_TextFormat,
164 Args,
165 &nextarg,
166 IntuitionBase);
167 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: formatted text 0x%p\n", formattedtext));
168 if (formattedtext)
170 gadgetlabels = buildeasyreq_makelabels(&dims,
171 easyStruct->es_GadgetFormat,
172 nextarg,
173 IntuitionBase);
174 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: gadget labels 0x%p\n", gadgetlabels));
176 if(gadgetlabels)
178 if (buildeasyreq_calculatedims(&dims, scr,
179 formattedtext, gadgetlabels, IntuitionBase))
181 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: dimensions OK\n"));
183 gadgets = buildeasyreq_makegadgets(&dims, gadgetlabels, scr, IntuitionBase);
184 if (gadgets)
186 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: gadgets 0x%p\n", gadgets));
188 requserdata = AllocVec(sizeof(struct IntRequestUserData),
189 MEMF_ANY|MEMF_CLEAR);
190 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: requester data 0x%p\n", requserdata));
192 if (requserdata)
194 struct TagItem win_tags[] =
196 { WA_Width , dims.width },
197 { WA_Height , dims.height },
198 { WA_Left , - scr->LeftEdge + (scr->ViewPort.DWidth/2) - (dims.width/2) },
199 { WA_Top , - scr->TopEdge + (scr->ViewPort.DHeight/2) - (dims.height/2)},
200 { WA_IDCMP , IDCMP_GADGETUP | IDCMP_RAWKEY | (IDCMP & ~IDCMP_VANILLAKEY) },
201 { WA_Gadgets , (IPTR)gadgets },
202 { WA_Title , (IPTR)reqtitle },
203 { (lockedscr ? WA_PubScreen : WA_CustomScreen), (IPTR)scr },
204 { WA_Flags , WFLG_DRAGBAR |
205 WFLG_DEPTHGADGET |
206 WFLG_ACTIVATE |
207 WFLG_RMBTRAP /*|
208 WFLG_SIMPLE_REFRESH*/ },
209 {TAG_DONE }
212 req = OpenWindowTagList(NULL, win_tags);
214 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: window 0x%p\n", req));
216 if (req)
218 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
220 req->UserData = (BYTE *)requserdata;
221 requserdata->IDCMP = IDCMP;
222 requserdata->GadgetLabels = gadgetlabels;
223 requserdata->Gadgets = gadgets;
224 requserdata->NumGadgets = dims.gadgets;
226 buildeasyreq_draw(&dims, formattedtext,
227 req, scr, gadgets, IntuitionBase);
228 FreeVec(formattedtext);
230 return req;
233 /* opening requester failed -> free everything */
234 FreeVec(requserdata);
236 } /* if (requserdata) */
238 intrequest_freegadgets(gadgets, IntuitionBase);
240 } /* if (gadgets) */
242 } /* if (if (buildeasyreq_calculatedims... */
244 intrequest_freelabels(gadgetlabels, IntuitionBase);
246 } /* if (gadgetlabels) */
248 FreeVec(formattedtext);
250 } /* if (formattedtext) */
252 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
254 return NULL;
256 AROS_LIBFUNC_EXIT
258 } /* BuildEasyRequestArgs */
260 /**********************************************************************************************/
262 CONST UWORD BgPattern[2] = { 0xAAAA, 0x5555 };
264 /**********************************************************************************************/
266 /* draw the contents of the requester */
267 static void buildeasyreq_draw(struct reqdims *dims, STRPTR text,
268 struct Window *req, struct Screen *scr,
269 struct Gadget *gadgets,
270 struct IntuitionBase *IntuitionBase)
272 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
273 struct TagItem frame_tags[] =
275 {IA_Left , req->BorderLeft + OUTERSPACING_X },
276 {IA_Top , req->BorderTop + OUTERSPACING_Y },
277 {IA_Width , req->Width - req->BorderLeft - req->BorderRight - OUTERSPACING_X * 2 },
278 {IA_Height , dims->textheight },
279 {IA_Recessed , TRUE },
280 {IA_EdgesOnly , FALSE },
281 {TAG_DONE }
283 struct DrawInfo *dri;
284 struct Image *frame;
285 LONG currentline;
287 dri = GetScreenDrawInfo(scr);
288 if (!dri)
289 return;
291 SetFont(req->RPort, dri->dri_Font);
293 /* draw background pattern */
294 SetABPenDrMd(req->RPort,
295 dri->dri_Pens[SHINEPEN], dri->dri_Pens[BACKGROUNDPEN],
296 JAM1);
297 SetAfPt(req->RPort, BgPattern, 1);
298 RectFill(req->RPort, req->BorderLeft,
299 req->BorderTop,
300 req->Width - req->BorderRight,
301 req->Height - req->BorderBottom);
302 SetAfPt(req->RPort, NULL, 0);
304 /* draw textframe */
305 frame = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
306 if (frame)
308 DrawImageState(req->RPort, frame, 0, 0, IDS_NORMAL, dri);
309 DisposeObject((Object *)frame);
312 /* draw text */
313 SetABPenDrMd(req->RPort,
314 dri->dri_Pens[TEXTPEN], dri->dri_Pens[BACKGROUNDPEN], JAM1);
315 for (currentline = 1; text[0] != '\0'; currentline++)
317 STRPTR strend;
318 int length;
320 strend = strchr(text, '\n');
321 if (strend)
323 length = strend - text;
325 else
327 length = strlen(text);
330 Move(req->RPort,
331 dims->textleft,
332 req->BorderTop + (dims->fontheight + dims->fontxheight) * (currentline - 1) +
333 OUTERSPACING_Y + TEXTBOXBORDER_Y + req->RPort->Font->tf_Baseline);
335 Text(req->RPort, text, length);
337 text += length;
338 if (text[0] == '\n')
339 text++;
342 /* draw gadgets */
343 RefreshGList(gadgets, req, NULL, -1L);
345 FreeScreenDrawInfo(scr, dri);
348 /**********************************************************************************************/
350 /* create an array of gadgetlabels */
351 static STRPTR *buildeasyreq_makelabels(struct reqdims *dims,
352 CONST_STRPTR labeltext,
353 APTR args,
354 struct IntuitionBase *IntuitionBase)
356 STRPTR *gadgetlabels;
357 STRPTR label;
358 int currentgadget;
359 ULONG len = 0;
362 /* make room for pointer-array */
363 dims->gadgets = charsinstring(labeltext, '|') + 1;
365 gadgetlabels = AllocVec((dims->gadgets + 1) * sizeof(STRPTR), MEMF_ANY);
366 if (!gadgetlabels)
367 return NULL;
369 gadgetlabels[dims->gadgets] = NULL;
371 /* copy label-string */
372 RawDoFmt(labeltext, args, (VOID_FUNC)RAWFMTFUNC_COUNT, &len);
374 label = AllocVec(len + 1, MEMF_ANY);
375 if (!label)
377 FreeVec(gadgetlabels);
378 return NULL;
381 RawDoFmt(labeltext, args, (VOID_FUNC)RAWFMTFUNC_STRING, label);
383 /* set up the pointers and insert null-bytes */
384 for (currentgadget = 0; currentgadget < dims->gadgets; currentgadget++)
386 gadgetlabels[currentgadget] = label;
388 if (currentgadget != (dims->gadgets - 1))
390 while (label[0] != '|')
391 label++;
393 label[0] = '\0';
394 label++;
398 return gadgetlabels;
401 /**********************************************************************************************/
403 /**********************************************************************************************/
405 /* format the supplied text string by using the supplied args */
406 static STRPTR buildeasyreq_formattext(CONST_STRPTR textformat,
407 APTR args,
408 APTR *nextargptr,
409 struct IntuitionBase *IntuitionBase)
411 STRPTR buffer;
412 ULONG len = 0;
414 RawDoFmt(textformat, args, (VOID_FUNC)RAWFMTFUNC_COUNT, &len);
416 buffer = AllocVec(len + 1, MEMF_ANY | MEMF_CLEAR);
417 if (!buffer) return NULL;
419 *nextargptr = RawDoFmt(textformat, args, (VOID_FUNC)RAWFMTFUNC_STRING, buffer);
421 return buffer;
424 /**********************************************************************************************/
426 /* calculate dimensions of the requester */
427 static BOOL buildeasyreq_calculatedims(struct reqdims *dims,
428 struct Screen *scr,
429 STRPTR formattedtext,
430 STRPTR *gadgetlabels,
431 struct IntuitionBase *IntuitionBase)
433 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
434 STRPTR textline;
435 int textlines, line; /* number of lines in es_TextFormat */
436 int currentgadget = 0;
437 UWORD textboxwidth = 0, gadgetswidth; /* width of upper/lower part */
439 /* calculate height of requester */
440 dims->fontheight = scr->RastPort.Font->tf_YSize;
441 dims->fontxheight = dims->fontheight - scr->RastPort.Font->tf_Baseline;
442 if (dims->fontxheight < 1) dims->fontxheight = 1;
444 textlines = charsinstring(formattedtext, '\n') + 1;
445 dims->textheight = TEXTBOXBORDER_Y +
446 textlines * (dims->fontheight + dims->fontxheight) - dims->fontxheight +
447 TEXTBOXBORDER_Y;
448 dims->height = scr->WBorTop + dims->fontheight + 1 +
449 OUTERSPACING_Y +
450 dims->textheight +
451 TEXTGADGETSPACING +
452 /* Width of gadgets is not counted here. It's counted in buildeasyreq_makegadgets(). */
453 OUTERSPACING_Y +
454 scr->WBorBottom;
456 /* calculate width of text-box */
457 textline = formattedtext;
458 for (line = 0; line<textlines; line++)
460 int linelen; /* length of current text line */
461 UWORD linewidth; /* width (pixel) of current text line */
463 if (line == (textlines - 1))
464 linelen = strlen(textline);
465 else
467 linelen = 0;
468 while (textline[linelen] != '\n')
469 linelen++;
471 linewidth = TextLength(&scr->RastPort, textline, linelen);
472 if (linewidth > textboxwidth)
473 textboxwidth = linewidth;
474 textline = textline + linelen + 1;
476 textboxwidth += TEXTBOXBORDER_X * 2;
478 /* calculate width of gadgets */
479 dims->gadgetwidth = 0;
480 while (gadgetlabels[currentgadget])
482 UWORD gadgetwidth; /* width of current gadget */
484 gadgetwidth = TextLength(&scr->RastPort, gadgetlabels[currentgadget],
485 strlen(gadgetlabels[currentgadget]));
486 if (gadgetwidth > dims->gadgetwidth)
487 dims->gadgetwidth = gadgetwidth;
488 currentgadget++;
491 dims->gadgetwidth += BUTTONBORDER_X * 2;
492 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * dims->gadgets - GADGETGADGETSPACING;
494 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_calculatedims: Textbox %u gadgets %u\n", textboxwidth, gadgetswidth));
496 /* calculate width of requester and position of requester text */
497 dims->textleft = scr->WBorLeft + OUTERSPACING_X + TEXTBOXBORDER_X;
498 if (textboxwidth > gadgetswidth)
500 dims->width = textboxwidth;
502 else
504 dims->textleft += (gadgetswidth - textboxwidth) / 2;
505 dims->width = gadgetswidth;
507 dims->width += OUTERSPACING_X * 2 + scr->WBorLeft + scr->WBorRight;
509 if (dims->width > scr->Width)
511 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_calculatedims: Too wide (requester %u, screen %u)\n", dims->width, scr->Width));
512 dims->width = scr->Width;
515 return TRUE;
518 /**********************************************************************************************/
520 /* make all the gadgets */
521 static struct Gadget *buildeasyreq_makegadgets(struct reqdims *dims,
522 STRPTR *gadgetlabels,
523 struct Screen *scr,
524 struct IntuitionBase *IntuitionBase)
526 UWORD gadgetheight = dims->fontheight + BUTTONBORDER_Y * 2;
527 struct Gadget *gadgetlist, *thisgadget = NULL;
528 struct Image *gadgetframe;
529 WORD currentgadget;
530 UWORD xoffset, yoffset, spacing, gadgetswidth, gadgetsheight, ngadgets, nrows;
531 UWORD x, y;
532 struct DrawInfo *dri;
534 if (gadgetlabels[0] == NULL)
535 return NULL;
537 gadgetframe = (struct Image *)NewObject(NULL, FRAMEICLASS, IA_FrameType, FRAME_BUTTON,
538 IA_Width , dims->gadgetwidth,
539 IA_Height , gadgetheight,
540 TAG_DONE);
542 if (!gadgetframe)
543 return NULL;
545 ngadgets = dims->gadgets;
546 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * ngadgets - GADGETGADGETSPACING;
547 spacing = dims->width - scr->WBorLeft - scr->WBorRight - OUTERSPACING_X * 2;
549 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Gadgets width %u, avalable space %u\n", gadgetswidth, spacing));
552 * At this point 'spacing' holds total width of inner space available for use by gadgets.
553 * If gadgets would occupy more space than we have (window/screen is too narrow),
554 * we will rearrange gadgets in several rows.
555 * First we need to calculate how many gadgets per row will fit on the screen.
557 while (gadgetswidth > spacing)
559 if (ngadgets == 1)
561 /* Only one gadget left? Too bad... */
562 break;
565 ngadgets--;
566 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * ngadgets - GADGETGADGETSPACING;
567 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Trying %u gadgets per row, width %u\n", ngadgets, gadgetswidth));
570 nrows = dims->gadgets / ngadgets;
571 if (nrows * ngadgets < dims->gadgets)
572 nrows++;
574 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Gadgets arranged in %u rows\n", nrows));
576 /* Now calculate spacing between gadgets */
577 if (ngadgets > 1)
578 spacing = (spacing - dims->gadgetwidth) / (ngadgets - 1);
580 dri = GetScreenDrawInfo(scr);
582 /* Now we know how much space our gadgets will occupy. Add the required height to the requester. */
583 gadgetheight += GADGETGADGETSPACING_Y;
584 gadgetsheight = nrows * gadgetheight - GADGETGADGETSPACING_Y;
585 dims->height += gadgetsheight;
587 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Resulting requester height: %u\n", dims->height));
589 /* Check if the resulting height fits on the screen. */
590 if (dims->height > scr->Height)
592 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Too high (screen %u)\n", scr->Height));
594 /* Decrease height of the requester at the expense of textbox */
595 dims->height = scr->Height;
596 dims->textheight = dims->height - scr->WBorTop - dims->fontheight - 1 -
597 OUTERSPACING_Y -
598 TEXTGADGETSPACING -
599 gadgetsheight -
600 OUTERSPACING_Y -
601 scr->WBorBottom;
604 gadgetlist = NULL;
605 currentgadget = 0;
606 yoffset = dims->height - scr->WBorBottom - OUTERSPACING_Y - gadgetsheight;
608 for (y = 0; y < nrows; y++)
610 xoffset = scr->WBorLeft + OUTERSPACING_X;
611 if (ngadgets == 1)
612 xoffset += (spacing - dims->gadgetwidth) / 2;
614 for (x = 0; x < ngadgets; x++)
616 WORD gadgetid = (currentgadget == (dims->gadgets - 1)) ? 0 : currentgadget + 1;
618 thisgadget = NewObject(NULL, FRBUTTONCLASS, GA_ID , gadgetid,
619 GA_Previous , thisgadget,
620 GA_Left , xoffset,
621 GA_Top , yoffset,
622 GA_Image , gadgetframe,
623 GA_RelVerify, TRUE,
624 GA_DrawInfo ,dri,
625 TAG_DONE);
626 if (currentgadget == 0)
627 gadgetlist = thisgadget;
629 if (!thisgadget)
631 intrequest_freegadgets(gadgetlist, IntuitionBase);
632 return NULL;
635 SetAttrs(thisgadget, GA_Text, gadgetlabels[currentgadget++], TAG_DONE);
637 if (currentgadget == dims->gadgets)
640 * The last row can be incomplete, if number of gadgets does not
641 * divide on number of rows.
643 break;
646 xoffset += spacing;
648 yoffset += gadgetheight;
651 FreeScreenDrawInfo(scr, dri);
653 return gadgetlist;
656 /**********************************************************************************************/
658 static int charsinstring(CONST_STRPTR string, char c)
660 int count = 0;
662 while (string[0])
664 if (string[0] == c)
665 count++;
666 string++;
668 return count;
671 /**********************************************************************************************/