wrong version committed
[AROS.git] / rom / intuition / buildeasyrequestargs.c
blobdad519e3ae2ccd8af728df7bc6d7faa90714eb01
1 /*
2 Copyright © 1995-2013, 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 *****************************************************************************/
117 AROS_LIBFUNC_INIT
119 struct Screen *scr = NULL, *lockedscr = NULL;
120 struct Window *req;
121 struct Gadget *gadgets;
122 CONST_STRPTR reqtitle;
123 STRPTR formattedtext;
124 STRPTR *gadgetlabels;
125 struct reqdims dims;
126 struct IntRequestUserData *requserdata;
127 APTR nextarg;
129 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: window 0x%p easystruct 0x%p IDCMPFlags 0x08%x args 0x%p\n",
130 RefWindow, easyStruct, IDCMP, Args));
132 if (!easyStruct)
133 return FALSE;
135 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: easy title <%s> Format <%s> Gadgets <%s>\n",
136 easyStruct->es_Title,
137 easyStruct->es_TextFormat,
138 easyStruct->es_GadgetFormat));
140 /* get requester title */
141 reqtitle = easyStruct->es_Title;
142 if ((!reqtitle) && (RefWindow))
143 reqtitle = RefWindow->Title;
145 if (!reqtitle) reqtitle = "System Request"; /* stegerg: should be localized */
147 /* get screen and screendrawinfo */
148 if (RefWindow)
149 scr = RefWindow->WScreen;
151 if (!scr)
153 scr = LockPubScreen(NULL);
154 if (!scr)
155 return FALSE;
157 lockedscr = scr;
160 /* create everything */
161 formattedtext = buildeasyreq_formattext(easyStruct->es_TextFormat,
162 Args,
163 &nextarg,
164 IntuitionBase);
165 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: formatted text 0x%p\n", formattedtext));
166 if (formattedtext)
168 gadgetlabels = buildeasyreq_makelabels(&dims,
169 easyStruct->es_GadgetFormat,
170 nextarg,
171 IntuitionBase);
172 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: gadget labels 0x%p\n", gadgetlabels));
174 if(gadgetlabels)
176 if (buildeasyreq_calculatedims(&dims, scr,
177 formattedtext, gadgetlabels, IntuitionBase))
179 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: dimensions OK\n"));
181 gadgets = buildeasyreq_makegadgets(&dims, gadgetlabels, scr, IntuitionBase);
182 if (gadgets)
184 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: gadgets 0x%p\n", gadgets));
186 requserdata = AllocVec(sizeof(struct IntRequestUserData),
187 MEMF_ANY|MEMF_CLEAR);
188 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: requester data 0x%p\n", requserdata));
190 if (requserdata)
192 struct TagItem win_tags[] =
194 { WA_Width , dims.width },
195 { WA_Height , dims.height },
196 { WA_Left , - scr->LeftEdge + (scr->ViewPort.DWidth/2) - (dims.width/2) },
197 { WA_Top , - scr->TopEdge + (scr->ViewPort.DHeight/2) - (dims.height/2)},
198 { WA_IDCMP , IDCMP_GADGETUP | IDCMP_RAWKEY | (IDCMP & ~IDCMP_VANILLAKEY) },
199 { WA_Gadgets , (IPTR)gadgets },
200 { WA_Title , (IPTR)reqtitle },
201 { (lockedscr ? WA_PubScreen : WA_CustomScreen), (IPTR)scr },
202 { WA_Flags , WFLG_DRAGBAR |
203 WFLG_DEPTHGADGET |
204 WFLG_ACTIVATE |
205 WFLG_RMBTRAP /*|
206 WFLG_SIMPLE_REFRESH*/ },
207 {TAG_DONE }
210 req = OpenWindowTagList(NULL, win_tags);
212 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: window 0x%p\n", req));
214 if (req)
216 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
218 req->UserData = (BYTE *)requserdata;
219 requserdata->IDCMP = IDCMP;
220 requserdata->GadgetLabels = gadgetlabels;
221 requserdata->Gadgets = gadgets;
222 requserdata->NumGadgets = dims.gadgets;
224 buildeasyreq_draw(&dims, formattedtext,
225 req, scr, gadgets, IntuitionBase);
226 FreeVec(formattedtext);
228 return req;
231 /* opening requester failed -> free everything */
232 FreeVec(requserdata);
234 } /* if (requserdata) */
236 intrequest_freegadgets(gadgets, IntuitionBase);
238 } /* if (gadgets) */
240 } /* if (if (buildeasyreq_calculatedims... */
242 intrequest_freelabels(gadgetlabels, IntuitionBase);
244 } /* if (gadgetlabels) */
246 FreeVec(formattedtext);
248 } /* if (formattedtext) */
250 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
252 return NULL;
254 AROS_LIBFUNC_EXIT
256 } /* BuildEasyRequestArgs */
258 /**********************************************************************************************/
260 CONST UWORD BgPattern[2] = { 0xAAAA, 0x5555 };
262 /**********************************************************************************************/
264 /* draw the contents of the requester */
265 static void buildeasyreq_draw(struct reqdims *dims, STRPTR text,
266 struct Window *req, struct Screen *scr,
267 struct Gadget *gadgets,
268 struct IntuitionBase *IntuitionBase)
270 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
271 struct TagItem frame_tags[] =
273 {IA_Left , req->BorderLeft + OUTERSPACING_X },
274 {IA_Top , req->BorderTop + OUTERSPACING_Y },
275 {IA_Width , req->Width - req->BorderLeft - req->BorderRight - OUTERSPACING_X * 2 },
276 {IA_Height , dims->textheight },
277 {IA_Recessed , TRUE },
278 {IA_EdgesOnly , FALSE },
279 {TAG_DONE }
281 struct DrawInfo *dri;
282 struct Image *frame;
283 LONG currentline;
285 dri = GetScreenDrawInfo(scr);
286 if (!dri)
287 return;
289 SetFont(req->RPort, dri->dri_Font);
291 /* draw background pattern */
292 SetABPenDrMd(req->RPort,
293 dri->dri_Pens[SHINEPEN], dri->dri_Pens[BACKGROUNDPEN],
294 JAM1);
295 SetAfPt(req->RPort, BgPattern, 1);
296 RectFill(req->RPort, req->BorderLeft,
297 req->BorderTop,
298 req->Width - req->BorderRight,
299 req->Height - req->BorderBottom);
300 SetAfPt(req->RPort, NULL, 0);
302 /* draw textframe */
303 frame = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
304 if (frame)
306 DrawImageState(req->RPort, frame, 0, 0, IDS_NORMAL, dri);
307 DisposeObject((Object *)frame);
310 /* draw text */
311 SetABPenDrMd(req->RPort,
312 dri->dri_Pens[TEXTPEN], dri->dri_Pens[BACKGROUNDPEN], JAM1);
313 for (currentline = 1; text[0] != '\0'; currentline++)
315 STRPTR strend;
316 int length;
318 strend = strchr(text, '\n');
319 if (strend)
321 length = strend - text;
323 else
325 length = strlen(text);
328 Move(req->RPort,
329 dims->textleft,
330 req->BorderTop + (dims->fontheight + dims->fontxheight) * (currentline - 1) +
331 OUTERSPACING_Y + TEXTBOXBORDER_Y + req->RPort->Font->tf_Baseline);
333 Text(req->RPort, text, length);
335 text += length;
336 if (text[0] == '\n')
337 text++;
340 /* draw gadgets */
341 RefreshGList(gadgets, req, NULL, -1L);
343 FreeScreenDrawInfo(scr, dri);
346 /**********************************************************************************************/
348 /* create an array of gadgetlabels */
349 static STRPTR *buildeasyreq_makelabels(struct reqdims *dims,
350 CONST_STRPTR labeltext,
351 APTR args,
352 struct IntuitionBase *IntuitionBase)
354 STRPTR *gadgetlabels;
355 STRPTR label;
356 int currentgadget;
357 ULONG len = 0;
360 /* make room for pointer-array */
361 dims->gadgets = charsinstring(labeltext, '|') + 1;
363 gadgetlabels = AllocVec((dims->gadgets + 1) * sizeof(STRPTR), MEMF_ANY);
364 if (!gadgetlabels)
365 return NULL;
367 gadgetlabels[dims->gadgets] = NULL;
369 /* copy label-string */
370 RawDoFmt(labeltext, args, (VOID_FUNC)RAWFMTFUNC_COUNT, &len);
372 label = AllocVec(len + 1, MEMF_ANY);
373 if (!label)
375 FreeVec(gadgetlabels);
376 return NULL;
379 RawDoFmt(labeltext, args, (VOID_FUNC)RAWFMTFUNC_STRING, label);
381 /* set up the pointers and insert null-bytes */
382 for (currentgadget = 0; currentgadget < dims->gadgets; currentgadget++)
384 gadgetlabels[currentgadget] = label;
386 if (currentgadget != (dims->gadgets - 1))
388 while (label[0] != '|')
389 label++;
391 label[0] = '\0';
392 label++;
396 return gadgetlabels;
399 /**********************************************************************************************/
401 /**********************************************************************************************/
403 /* format the supplied text string by using the supplied args */
404 static STRPTR buildeasyreq_formattext(CONST_STRPTR textformat,
405 APTR args,
406 APTR *nextargptr,
407 struct IntuitionBase *IntuitionBase)
409 STRPTR buffer;
410 ULONG len = 0;
412 RawDoFmt(textformat, args, (VOID_FUNC)RAWFMTFUNC_COUNT, &len);
414 buffer = AllocVec(len + 1, MEMF_ANY | MEMF_CLEAR);
415 if (!buffer) return NULL;
417 *nextargptr = RawDoFmt(textformat, args, (VOID_FUNC)RAWFMTFUNC_STRING, buffer);
419 return buffer;
422 /**********************************************************************************************/
424 /* calculate dimensions of the requester */
425 static BOOL buildeasyreq_calculatedims(struct reqdims *dims,
426 struct Screen *scr,
427 STRPTR formattedtext,
428 STRPTR *gadgetlabels,
429 struct IntuitionBase *IntuitionBase)
431 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
432 STRPTR textline;
433 int textlines, line; /* number of lines in es_TextFormat */
434 int currentgadget = 0;
435 UWORD textboxwidth = 0, gadgetswidth; /* width of upper/lower part */
437 /* calculate height of requester */
438 dims->fontheight = scr->RastPort.Font->tf_YSize;
439 dims->fontxheight = dims->fontheight - scr->RastPort.Font->tf_Baseline;
440 if (dims->fontxheight < 1) dims->fontxheight = 1;
442 textlines = charsinstring(formattedtext, '\n') + 1;
443 dims->textheight = TEXTBOXBORDER_Y +
444 textlines * (dims->fontheight + dims->fontxheight) - dims->fontxheight +
445 TEXTBOXBORDER_Y;
446 dims->height = scr->WBorTop + dims->fontheight + 1 +
447 OUTERSPACING_Y +
448 dims->textheight +
449 TEXTGADGETSPACING +
450 /* Width of gadgets is not counted here. It's counted in buildeasyreq_makegadgets(). */
451 OUTERSPACING_Y +
452 scr->WBorBottom;
454 /* calculate width of text-box */
455 textline = formattedtext;
456 for (line = 0; line<textlines; line++)
458 int linelen; /* length of current text line */
459 UWORD linewidth; /* width (pixel) of current text line */
461 if (line == (textlines - 1))
462 linelen = strlen(textline);
463 else
465 linelen = 0;
466 while (textline[linelen] != '\n')
467 linelen++;
469 linewidth = TextLength(&scr->RastPort, textline, linelen);
470 if (linewidth > textboxwidth)
471 textboxwidth = linewidth;
472 textline = textline + linelen + 1;
474 textboxwidth += TEXTBOXBORDER_X * 2;
476 /* calculate width of gadgets */
477 dims->gadgetwidth = 0;
478 while (gadgetlabels[currentgadget])
480 UWORD gadgetwidth; /* width of current gadget */
482 gadgetwidth = TextLength(&scr->RastPort, gadgetlabels[currentgadget],
483 strlen(gadgetlabels[currentgadget]));
484 if (gadgetwidth > dims->gadgetwidth)
485 dims->gadgetwidth = gadgetwidth;
486 currentgadget++;
489 dims->gadgetwidth += BUTTONBORDER_X * 2;
490 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * dims->gadgets - GADGETGADGETSPACING;
492 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_calculatedims: Textbox %u gadgets %u\n", textboxwidth, gadgetswidth));
494 /* calculate width of requester and position of requester text */
495 dims->textleft = scr->WBorLeft + OUTERSPACING_X + TEXTBOXBORDER_X;
496 if (textboxwidth > gadgetswidth)
498 dims->width = textboxwidth;
500 else
502 dims->textleft += (gadgetswidth - textboxwidth) / 2;
503 dims->width = gadgetswidth;
505 dims->width += OUTERSPACING_X * 2 + scr->WBorLeft + scr->WBorRight;
507 if (dims->width > scr->Width)
509 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_calculatedims: Too wide (requester %u, screen %u)\n", dims->width, scr->Width));
510 dims->width = scr->Width;
513 return TRUE;
516 /**********************************************************************************************/
518 /* make all the gadgets */
519 static struct Gadget *buildeasyreq_makegadgets(struct reqdims *dims,
520 STRPTR *gadgetlabels,
521 struct Screen *scr,
522 struct IntuitionBase *IntuitionBase)
524 UWORD gadgetheight = dims->fontheight + BUTTONBORDER_Y * 2;
525 struct Gadget *gadgetlist, *thisgadget = NULL;
526 struct Image *gadgetframe;
527 WORD currentgadget;
528 UWORD xoffset, yoffset, spacing, gadgetswidth, gadgetsheight, ngadgets, nrows;
529 UWORD x, y;
530 struct DrawInfo *dri;
532 if (gadgetlabels[0] == NULL)
533 return NULL;
535 gadgetframe = (struct Image *)NewObject(NULL, FRAMEICLASS, IA_FrameType, FRAME_BUTTON,
536 IA_Width , dims->gadgetwidth,
537 IA_Height , gadgetheight,
538 TAG_DONE);
540 if (!gadgetframe)
541 return NULL;
543 ngadgets = dims->gadgets;
544 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * ngadgets - GADGETGADGETSPACING;
545 spacing = dims->width - scr->WBorLeft - scr->WBorRight - OUTERSPACING_X * 2;
547 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Gadgets width %u, avalable space %u\n", gadgetswidth, spacing));
550 * At this point 'spacing' holds total width of inner space available for use by gadgets.
551 * If gadgets would occupy more space than we have (window/screen is too narrow),
552 * we will rearrange gadgets in several rows.
553 * First we need to calculate how many gadgets per row will fit on the screen.
555 while (gadgetswidth > spacing)
557 if (ngadgets == 1)
559 /* Only one gadget left? Too bad... */
560 break;
563 ngadgets--;
564 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * ngadgets - GADGETGADGETSPACING;
565 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Trying %u gadgets per row, width %u\n", ngadgets, gadgetswidth));
568 nrows = dims->gadgets / ngadgets;
569 if (nrows * ngadgets < dims->gadgets)
570 nrows++;
572 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Gadgets arranged in %u rows\n", nrows));
574 /* Now calculate spacing between gadgets */
575 if (ngadgets > 1)
576 spacing = (spacing - dims->gadgetwidth) / (ngadgets - 1);
578 dri = GetScreenDrawInfo(scr);
580 /* Now we know how much space our gadgets will occupy. Add the required height to the requester. */
581 gadgetheight += GADGETGADGETSPACING_Y;
582 gadgetsheight = nrows * gadgetheight - GADGETGADGETSPACING_Y;
583 dims->height += gadgetsheight;
585 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Resulting requester height: %u\n", dims->height));
587 /* Check if the resulting height fits on the screen. */
588 if (dims->height > scr->Height)
590 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Too high (screen %u)\n", scr->Height));
592 /* Decrease height of the requester at the expense of textbox */
593 dims->height = scr->Height;
594 dims->textheight = dims->height - scr->WBorTop - dims->fontheight - 1 -
595 OUTERSPACING_Y -
596 TEXTGADGETSPACING -
597 gadgetsheight -
598 OUTERSPACING_Y -
599 scr->WBorBottom;
602 gadgetlist = NULL;
603 currentgadget = 0;
604 yoffset = dims->height - scr->WBorBottom - OUTERSPACING_Y - gadgetsheight;
606 for (y = 0; y < nrows; y++)
608 xoffset = scr->WBorLeft + OUTERSPACING_X;
609 if (ngadgets == 1)
610 xoffset += (spacing - dims->gadgetwidth) / 2;
612 for (x = 0; x < ngadgets; x++)
614 WORD gadgetid = (currentgadget == (dims->gadgets - 1)) ? 0 : currentgadget + 1;
616 thisgadget = NewObject(NULL, FRBUTTONCLASS, GA_ID , gadgetid,
617 GA_Previous , thisgadget,
618 GA_Left , xoffset,
619 GA_Top , yoffset,
620 GA_Image , gadgetframe,
621 GA_RelVerify, TRUE,
622 GA_DrawInfo ,dri,
623 TAG_DONE);
624 if (currentgadget == 0)
625 gadgetlist = thisgadget;
627 if (!thisgadget)
629 intrequest_freegadgets(gadgetlist, IntuitionBase);
630 return NULL;
633 SetAttrs(thisgadget, GA_Text, gadgetlabels[currentgadget++], TAG_DONE);
635 if (currentgadget == dims->gadgets)
638 * The last row can be incomplete, if number of gadgets does not
639 * divide on number of rows.
641 break;
644 xoffset += spacing;
646 yoffset += gadgetheight;
649 FreeScreenDrawInfo(scr, dri);
651 return gadgetlist;
654 /**********************************************************************************************/
656 static int charsinstring(CONST_STRPTR string, char c)
658 int count = 0;
660 while (string[0])
662 if (string[0] == c)
663 count++;
664 string++;
666 return count;
669 /**********************************************************************************************/