Update to lasso handling. Adjust scroll amount based on difference between mouse...
[AROS.git] / rom / intuition / buildeasyrequestargs_aros.c
blobaef088600bdafddd02b51ea4e317996450740e5e
1 /*
2 Copyright © 1995-2007, 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) D(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 <intuition/gadgetclass.h>
21 #include <intuition/imageclass.h>
22 #include <intuition/screens.h>
23 #include <graphics/rastport.h>
24 #include <graphics/gfxmacros.h>
25 #include <utility/tagitem.h>
26 #include <aros/debug.h>
27 #include "intuition_intern.h"
29 #define OUTERSPACING_X 4
30 #define OUTERSPACING_Y 4
31 #define GADGETGADGETSPACING 8
32 #define TEXTGADGETSPACING 4
33 #define TEXTBOXBORDER_X 16
34 #define TEXTBOXBORDER_Y 4
35 #define BUTTONBORDER_X 8
36 #define BUTTONBORDER_Y 4
38 /**********************************************************************************************/
40 struct reqdims
42 UWORD width; /* width of the requester */
43 UWORD height; /* height of the requester */
44 UWORD fontheight; /* height of the default font */
45 UWORD fontxheight; /* extra height */
46 UWORD textleft;
47 WORD gadgets; /* number of gadgets */
48 UWORD gadgetwidth; /* width of a gadget */
51 /**********************************************************************************************/
53 static STRPTR *buildeasyreq_makelabels(struct reqdims *dims,STRPTR labeltext, APTR args, struct IntuitionBase *IntuitionBase);
54 static STRPTR buildeasyreq_formattext(STRPTR textformat, APTR args, APTR *nextargptr, struct IntuitionBase *IntuitionBase);
55 static BOOL buildeasyreq_calculatedims(struct reqdims *dims,
56 struct Screen *scr,
57 STRPTR formattedtext,
58 STRPTR *gadgetlabels,
59 struct IntuitionBase *IntuitionBase);
60 static struct Gadget *buildeasyreq_makegadgets(struct reqdims *dims,
61 STRPTR *gadgetlabels,
62 struct Screen *scr,
63 struct IntuitionBase *IntuitionBase);
64 static void buildeasyreq_draw(struct reqdims *dims, STRPTR text,
65 struct Window *win, struct Screen *scr,
66 struct Gadget *gadgets,
67 struct IntuitionBase *IntuitionBase);
69 static int charsinstring(STRPTR string, char c);
71 /*****************************************************************************
73 NAME */
74 #include <proto/intuition.h>
75 #include <exec/types.h>
76 #include <intuition/intuition.h>
78 AROS_LH4(struct Window *, BuildEasyRequestArgs,
80 /* SYNOPSIS */
81 AROS_LHA(struct Window *, RefWindow, A0),
82 AROS_LHA(struct EasyStruct *, easyStruct, A1),
83 AROS_LHA(ULONG , IDCMP, D0),
84 AROS_LHA(APTR , Args, A3),
86 /* LOCATION */
87 struct IntuitionBase *, IntuitionBase, 99, Intuition)
89 /* FUNCTION
90 Opens a requester, which provides one or more choices. The control is
91 returned to the application after the requester was opened. It is
92 handled by subsequent calls to SysReqHandler() and closed by calling
93 FreeSysRequest().
95 INPUTS
96 RefWindow - A reference window. If NULL, the requester opens on
97 the default public screen.
98 easyStruct - The EasyStruct structure (<intuition/intuition.h>),
99 which describes the requester.
100 IDCMP - IDCMP flags, which should satisfy the requester, too. This is
101 useful for requesters, which want to listen to disk changes,
102 etc. Note that this is not a pointer to the flags as in
103 EasyRequestArgs().
104 Args - The arguments for easyStruct->es_TextFormat.
106 RESULT
107 Returns a pointer to the requester. Use this pointer only for calls
108 to SysReqHandler() and FreeSysRequest().
110 NOTES
112 EXAMPLE
114 BUGS
116 SEE ALSO
117 EasyRequestArgs(), SysReqHandler(), FreeSysRequest()
119 INTERNALS
121 HISTORY
123 *****************************************************************************/
125 AROS_LIBFUNC_INIT
127 struct Screen *scr = NULL, *lockedscr = NULL;
128 struct Window *req;
129 struct Gadget *gadgets;
130 STRPTR reqtitle;
131 STRPTR formattedtext;
132 STRPTR *gadgetlabels;
133 struct reqdims dims;
134 struct IntRequestUserData *requserdata;
135 APTR nextarg;
137 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: window 0x%lx easystruct 0x%lx IDCMPFlags 0x%lx args 0x%lx\n",
138 (ULONG) RefWindow,
139 (ULONG) easyStruct,
140 IDCMP,
141 (ULONG) Args));
143 if (!easyStruct)
144 return FALSE;
146 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: easy title <%s> Format <%s> Gadgets <%s>\n",
147 easyStruct->es_Title,
148 easyStruct->es_TextFormat,
149 easyStruct->es_GadgetFormat));
151 /* get requester title */
152 reqtitle = easyStruct->es_Title;
153 if ((!reqtitle) && (RefWindow))
154 reqtitle = RefWindow->Title;
156 if (!reqtitle) reqtitle = "System Request"; /* stegerg: should be localized */
158 /* get screen and screendrawinfo */
159 if (RefWindow)
160 scr = RefWindow->WScreen;
162 if (!scr)
164 scr = LockPubScreen(NULL);
165 if (!scr)
166 return FALSE;
168 lockedscr = scr;
171 /* create everything */
172 formattedtext = buildeasyreq_formattext(easyStruct->es_TextFormat,
173 Args,
174 &nextarg,
175 IntuitionBase);
176 if (formattedtext)
178 gadgetlabels = buildeasyreq_makelabels(&dims,
179 easyStruct->es_GadgetFormat,
180 nextarg,
181 IntuitionBase);
183 if(gadgetlabels)
185 if (buildeasyreq_calculatedims(&dims, scr,
186 formattedtext, gadgetlabels, IntuitionBase))
188 gadgets = buildeasyreq_makegadgets(&dims, gadgetlabels, scr, IntuitionBase);
189 if (gadgets)
191 requserdata = AllocVec(sizeof(struct IntRequestUserData),
192 MEMF_ANY|MEMF_CLEAR);
193 if (requserdata)
195 struct TagItem win_tags[] =
197 { WA_Width , dims.width },
198 { WA_Height , dims.height },
199 { WA_Left , (scr->Width/2) - (dims.width/2) },
200 { WA_Top , (scr->Height/2) - (dims.height/2) },
201 { WA_IDCMP , IDCMP_GADGETUP | IDCMP_RAWKEY | (IDCMP & ~IDCMP_VANILLAKEY) },
202 { WA_Gadgets , (IPTR)gadgets },
203 { WA_Title , (IPTR)reqtitle },
204 { (lockedscr ? WA_PubScreen : WA_CustomScreen), (IPTR)scr },
205 { WA_Flags , WFLG_DRAGBAR |
206 WFLG_DEPTHGADGET |
207 WFLG_ACTIVATE |
208 WFLG_RMBTRAP /*|
209 WFLG_SIMPLE_REFRESH*/ },
210 {TAG_DONE }
213 req = OpenWindowTagList(NULL, win_tags);
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 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: gadgets 0x%lx\n", (ULONG) 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 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 TagItem frame_tags[] =
274 {IA_Left , req->BorderLeft + OUTERSPACING_X },
275 {IA_Top , req->BorderTop + OUTERSPACING_Y },
276 {IA_Width , req->Width - req->BorderLeft - req->BorderRight - OUTERSPACING_X * 2 },
277 {IA_Height , req->Height - req->BorderTop - req->BorderBottom -
278 dims->fontheight - OUTERSPACING_Y * 2 -
279 TEXTGADGETSPACING - BUTTONBORDER_Y * 2 },
280 {IA_Recessed , TRUE },
281 {IA_EdgesOnly , FALSE },
282 {TAG_DONE }
284 struct DrawInfo *dri;
285 struct Image *frame;
286 LONG currentline;
288 dri = GetScreenDrawInfo(scr);
289 if (!dri)
290 return;
292 SetFont(req->RPort, dri->dri_Font);
294 /* draw background pattern */
295 SetABPenDrMd(req->RPort,
296 dri->dri_Pens[SHINEPEN], dri->dri_Pens[BACKGROUNDPEN],
297 JAM1);
298 SetAfPt(req->RPort, BgPattern, 1);
299 RectFill(req->RPort, req->BorderLeft,
300 req->BorderTop,
301 req->Width - req->BorderRight,
302 req->Height - req->BorderBottom);
303 SetAfPt(req->RPort, NULL, 0);
305 /* draw textframe */
306 frame = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
307 if (frame)
309 DrawImageState(req->RPort, frame, 0, 0, IDS_NORMAL, dri);
310 DisposeObject((Object *)frame);
313 /* draw text */
314 SetABPenDrMd(req->RPort,
315 dri->dri_Pens[TEXTPEN], dri->dri_Pens[BACKGROUNDPEN], JAM1);
316 for (currentline = 1; text[0] != '\0'; currentline++)
318 STRPTR strend;
319 int length;
321 strend = strchr(text, '\n');
322 if (strend)
324 length = strend - text;
326 else
328 length = strlen(text);
331 Move(req->RPort,
332 dims->textleft,
333 req->BorderTop + (dims->fontheight + dims->fontxheight) * (currentline - 1) +
334 OUTERSPACING_Y + TEXTBOXBORDER_Y + req->RPort->Font->tf_Baseline);
336 Text(req->RPort, text, length);
338 text += length;
339 if (text[0] == '\n')
340 text++;
343 /* draw gadgets */
344 RefreshGList(gadgets, req, NULL, -1L);
346 FreeScreenDrawInfo(scr, dri);
349 /**********************************************************************************************/
351 AROS_UFH2 (void, EasyReqPutChar,
352 AROS_UFHA(UBYTE, chr, D0),
353 AROS_UFHA(UBYTE **,buffer,A3)
356 AROS_USERFUNC_INIT
358 *(*buffer)++=chr;
360 AROS_USERFUNC_EXIT
363 /**********************************************************************************************/
365 AROS_UFH2 (void, EasyReqCountChar,
366 AROS_UFHA(UBYTE, chr, D0),
367 AROS_UFHA(ULONG *,counter,A3)
370 AROS_USERFUNC_INIT
372 /* shut up the compiler */
373 chr = chr;
375 (*counter)++;
377 AROS_USERFUNC_EXIT
380 /* create an array of gadgetlabels */
381 static STRPTR *buildeasyreq_makelabels(struct reqdims *dims,
382 STRPTR labeltext,
383 APTR args,
384 struct IntuitionBase *IntuitionBase)
386 STRPTR *gadgetlabels;
387 STRPTR label, lab;
388 int currentgadget;
389 ULONG len = 0;
392 /* make room for pointer-array */
393 dims->gadgets = charsinstring(labeltext, '|') + 1;
395 gadgetlabels = AllocVec((dims->gadgets + 1) * sizeof(STRPTR), MEMF_ANY);
396 if (!gadgetlabels)
397 return NULL;
399 gadgetlabels[dims->gadgets] = NULL;
401 /* copy label-string */
402 RawDoFmt(labeltext, args, (VOID_FUNC)AROS_ASMSYMNAME(EasyReqCountChar), &len);
404 label = AllocVec(len + 1, MEMF_ANY);
405 if (!label)
407 FreeVec(gadgetlabels);
408 return NULL;
411 lab = label;
412 RawDoFmt(labeltext, args, (VOID_FUNC)AROS_ASMSYMNAME(EasyReqPutChar), &lab);
414 /* set up the pointers and insert null-bytes */
415 for (currentgadget = 0; currentgadget < dims->gadgets; currentgadget++)
417 gadgetlabels[currentgadget] = label;
419 if (currentgadget != (dims->gadgets - 1))
421 while (label[0] != '|')
422 label++;
424 label[0] = '\0';
425 label++;
429 return gadgetlabels;
432 /**********************************************************************************************/
434 /**********************************************************************************************/
436 /* format the supplied text string by using the supplied args */
437 static STRPTR buildeasyreq_formattext(STRPTR textformat,
438 APTR args,
439 APTR *nextargptr,
440 struct IntuitionBase *IntuitionBase)
442 #if 1
443 STRPTR buffer;
444 STRPTR buf;
445 ULONG len = 0;
447 RawDoFmt(textformat, args, (VOID_FUNC)AROS_ASMSYMNAME(EasyReqCountChar), &len);
449 buffer = AllocVec(len + 1, MEMF_ANY | MEMF_CLEAR);
450 if (!buffer) return NULL;
452 buf = buffer;
453 *nextargptr = RawDoFmt(textformat, args, (VOID_FUNC)AROS_ASMSYMNAME(EasyReqPutChar), &buf);
455 return buffer;
457 #else
458 int len;
459 STRPTR buffer;
461 len = strlen(textformat) + 256;
462 for (;;)
464 buffer = AllocVec(len, MEMF_ANY);
465 if (!buffer)
466 return NULL;
468 if (vsnprintf(buffer, len, textformat, args) < len)
469 return buffer;
471 FreeVec(buffer);
472 len += 256;
474 #endif
478 /**********************************************************************************************/
480 /* calculate dimensions of the requester */
481 static BOOL buildeasyreq_calculatedims(struct reqdims *dims,
482 struct Screen *scr,
483 STRPTR formattedtext,
484 STRPTR *gadgetlabels,
485 struct IntuitionBase *IntuitionBase)
487 STRPTR textline;
488 int textlines, line; /* number of lines in es_TextFormat */
489 int currentgadget = 0;
490 UWORD textboxwidth = 0, gadgetswidth; /* width of upper/lower part */
492 /* calculate height of requester */
493 dims->fontheight = scr->RastPort.Font->tf_YSize;
494 dims->fontxheight = dims->fontheight - scr->RastPort.Font->tf_Baseline;
495 if (dims->fontxheight < 1) dims->fontxheight = 1;
497 textlines = charsinstring(formattedtext, '\n') + 1;
498 dims->height = scr->WBorTop + dims->fontheight + 1 +
499 OUTERSPACING_Y +
500 TEXTBOXBORDER_Y +
501 textlines * (dims->fontheight + dims->fontxheight) - dims->fontxheight +
502 TEXTBOXBORDER_Y +
503 TEXTGADGETSPACING +
504 BUTTONBORDER_Y +
505 dims->fontheight +
506 BUTTONBORDER_Y +
507 OUTERSPACING_Y +
508 scr->WBorBottom;
510 if (dims->height > scr->Height)
511 return FALSE;
513 /* calculate width of text-box */
514 textline = formattedtext;
515 for (line = 0; line<textlines; line++)
517 int linelen; /* length of current text line */
518 UWORD linewidth; /* width (pixel) of current text line */
520 if (line == (textlines - 1))
521 linelen = strlen(textline);
522 else
524 linelen = 0;
525 while (textline[linelen] != '\n')
526 linelen++;
528 linewidth = TextLength(&scr->RastPort, textline, linelen);
529 if (linewidth > textboxwidth)
530 textboxwidth = linewidth;
531 textline = textline + linelen + 1;
533 textboxwidth += TEXTBOXBORDER_X * 2;
535 /* calculate width of gadgets */
536 dims->gadgetwidth = 0;
537 while (gadgetlabels[currentgadget])
539 UWORD gadgetwidth; /* width of current gadget */
541 gadgetwidth = TextLength(&scr->RastPort, gadgetlabels[currentgadget],
542 strlen(gadgetlabels[currentgadget]));
543 if (gadgetwidth > dims->gadgetwidth)
544 dims->gadgetwidth = gadgetwidth;
545 currentgadget++;
547 dims->gadgetwidth += BUTTONBORDER_X * 2;
548 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * dims->gadgets - GADGETGADGETSPACING;
550 /* calculate width of requester and position of requester text */
551 dims->textleft = scr->WBorLeft + OUTERSPACING_X + TEXTBOXBORDER_X;
552 if (textboxwidth > gadgetswidth)
554 dims->width = textboxwidth;
556 else
558 dims->textleft += (gadgetswidth - textboxwidth) / 2;
559 dims->width = gadgetswidth;
561 dims->width += OUTERSPACING_X * 2 + scr->WBorLeft + scr->WBorRight;
563 if (dims->width > scr->Width)
564 return FALSE;
566 return TRUE;
569 /**********************************************************************************************/
571 /* make all the gadgets */
572 static struct Gadget *buildeasyreq_makegadgets(struct reqdims *dims,
573 STRPTR *gadgetlabels,
574 struct Screen *scr,
575 struct IntuitionBase *IntuitionBase)
577 struct TagItem frame_tags[] =
579 {IA_FrameType , FRAME_BUTTON },
580 {IA_Width , dims->gadgetwidth },
581 {IA_Height , dims->fontheight + BUTTONBORDER_Y * 2 },
582 {TAG_DONE }
584 struct Gadget *gadgetlist, *thisgadget = NULL;
585 struct Image *gadgetframe;
586 WORD currentgadget;
587 UWORD xoffset, spacing;
588 struct DrawInfo *dri;
590 if (gadgetlabels[0] == NULL)
591 return NULL;
593 gadgetframe = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
594 if (!gadgetframe)
595 return NULL;
597 spacing = dims->width - scr->WBorLeft - scr->WBorRight - OUTERSPACING_X * 2;
598 xoffset = scr->WBorLeft + OUTERSPACING_X;
600 if (dims->gadgets == 1)
601 xoffset += (spacing - dims->gadgetwidth) / 2;
602 else
603 spacing = (spacing - dims->gadgetwidth) / (dims->gadgets - 1);
605 dri = GetScreenDrawInfo(scr);
607 gadgetlist = NULL;
609 for (currentgadget = 0; gadgetlabels[currentgadget]; currentgadget++)
611 WORD gadgetid = (currentgadget == (dims->gadgets - 1)) ? 0 : currentgadget + 1;
612 struct TagItem gad_tags[] =
614 {GA_ID , gadgetid },
615 {GA_Previous , (IPTR)thisgadget },
616 {GA_Left , xoffset },
617 {GA_Top , dims->height -
618 scr->WBorBottom - dims->fontheight -
619 OUTERSPACING_Y - BUTTONBORDER_Y * 2 },
620 {GA_Image , (IPTR)gadgetframe },
621 {GA_RelVerify , TRUE },
622 {GA_DrawInfo , (IPTR)dri },
623 {TAG_DONE }
625 struct TagItem gad2_tags[] =
627 {GA_Text , (IPTR)gadgetlabels[currentgadget] },
628 {TAG_DONE }
631 thisgadget = NewObjectA(NULL, FRBUTTONCLASS, gad_tags);
633 if (currentgadget == 0)
634 gadgetlist = thisgadget;
636 if (!thisgadget)
638 intrequest_freegadgets(gadgetlist, IntuitionBase);
639 return NULL;
642 SetAttrsA(thisgadget, gad2_tags);
644 xoffset += spacing;
647 FreeScreenDrawInfo(scr, dri);
649 return gadgetlist;
652 /**********************************************************************************************/
654 static int charsinstring(STRPTR string, char c)
656 int count = 0;
658 while (string[0])
660 if (string[0] == c)
661 count++;
662 string++;
664 return count;
667 /**********************************************************************************************/