2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
7 #define DEBUG_BUILDEASYREQUEST(x)
9 /**********************************************************************************************/
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 /**********************************************************************************************/
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 */
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
, RAWARG args
, struct IntuitionBase
*IntuitionBase
);
48 static STRPTR
buildeasyreq_formattext(CONST_STRPTR textformat
, RAWARG args
, RAWARG
*nextargptr
, struct IntuitionBase
*IntuitionBase
);
49 static BOOL
buildeasyreq_calculatedims(struct reqdims
*dims
,
53 struct IntuitionBase
*IntuitionBase
);
54 static struct Gadget
*buildeasyreq_makegadgets(struct reqdims
*dims
,
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 /*****************************************************************************
68 #include <proto/intuition.h>
69 #include <exec/types.h>
70 #include <intuition/intuition.h>
72 AROS_LH4(struct Window
*, BuildEasyRequestArgs
,
75 AROS_LHA(struct Window
*, RefWindow
, A0
),
76 AROS_LHA(struct EasyStruct
*, easyStruct
, A1
),
77 AROS_LHA(ULONG
, IDCMP
, D0
),
78 AROS_LHA(RAWARG
, Args
, A3
),
81 struct IntuitionBase
*, IntuitionBase
, 99, Intuition
)
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
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
98 Args - The arguments for easyStruct->es_TextFormat.
101 Returns a pointer to the requester. Use this pointer only for calls
102 to SysReqHandler() and FreeSysRequest().
111 EasyRequestArgs(), SysReqHandler(), FreeSysRequest()
115 *****************************************************************************/
119 struct Screen
*scr
= NULL
, *lockedscr
= NULL
;
121 struct Gadget
*gadgets
;
122 CONST_STRPTR reqtitle
;
123 STRPTR formattedtext
;
124 STRPTR
*gadgetlabels
;
126 struct IntRequestUserData
*requserdata
;
129 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: window 0x%p easystruct 0x%p IDCMPFlags 0x08%x args 0x%p\n",
130 RefWindow
, easyStruct
, IDCMP
, Args
));
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 */
149 scr
= RefWindow
->WScreen
;
153 scr
= LockPubScreen(NULL
);
160 /* create everything */
161 formattedtext
= buildeasyreq_formattext(easyStruct
->es_TextFormat
,
165 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: formatted text 0x%p\n", formattedtext
));
168 gadgetlabels
= buildeasyreq_makelabels(&dims
,
169 easyStruct
->es_GadgetFormat
,
172 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: gadget labels 0x%p\n", 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
);
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
));
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
|
206 WFLG_SIMPLE_REFRESH*/ },
210 req
= OpenWindowTagList(NULL
, win_tags
);
212 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: window 0x%p\n", 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
);
231 /* opening requester failed -> free everything */
232 FreeVec(requserdata
);
234 } /* if (requserdata) */
236 intrequest_freegadgets(gadgets
, IntuitionBase
);
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
);
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
},
281 struct DrawInfo
*dri
;
285 dri
= GetScreenDrawInfo(scr
);
289 SetFont(req
->RPort
, dri
->dri_Font
);
291 /* draw background pattern */
292 SetABPenDrMd(req
->RPort
,
293 dri
->dri_Pens
[SHINEPEN
], dri
->dri_Pens
[BACKGROUNDPEN
],
295 SetAfPt(req
->RPort
, BgPattern
, 1);
296 RectFill(req
->RPort
, req
->BorderLeft
,
298 req
->Width
- req
->BorderRight
,
299 req
->Height
- req
->BorderBottom
);
300 SetAfPt(req
->RPort
, NULL
, 0);
303 frame
= (struct Image
*)NewObjectA(NULL
, FRAMEICLASS
, frame_tags
);
306 DrawImageState(req
->RPort
, frame
, 0, 0, IDS_NORMAL
, dri
);
307 DisposeObject((Object
*)frame
);
311 SetABPenDrMd(req
->RPort
,
312 dri
->dri_Pens
[TEXTPEN
], dri
->dri_Pens
[BACKGROUNDPEN
], JAM1
);
313 for (currentline
= 1; text
[0] != '\0'; currentline
++)
318 strend
= strchr(text
, '\n');
321 length
= strend
- text
;
325 length
= strlen(text
);
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
);
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
,
352 struct IntuitionBase
*IntuitionBase
)
354 STRPTR
*gadgetlabels
;
360 /* make room for pointer-array */
361 dims
->gadgets
= charsinstring(labeltext
, '|') + 1;
363 gadgetlabels
= AllocVec((dims
->gadgets
+ 1) * sizeof(STRPTR
), MEMF_ANY
);
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
);
375 FreeVec(gadgetlabels
);
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] != '|')
399 /**********************************************************************************************/
401 /**********************************************************************************************/
403 /* format the supplied text string by using the supplied args */
404 static STRPTR
buildeasyreq_formattext(CONST_STRPTR textformat
,
407 struct IntuitionBase
*IntuitionBase
)
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
);
422 /**********************************************************************************************/
424 /* calculate dimensions of the requester */
425 static BOOL
buildeasyreq_calculatedims(struct reqdims
*dims
,
427 STRPTR formattedtext
,
428 STRPTR
*gadgetlabels
,
429 struct IntuitionBase
*IntuitionBase
)
431 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
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
+
446 dims
->height
= scr
->WBorTop
+ dims
->fontheight
+ 1 +
450 /* Width of gadgets is not counted here. It's counted in buildeasyreq_makegadgets(). */
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
);
466 while (textline
[linelen
] != '\n')
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
;
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
;
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
;
516 /**********************************************************************************************/
518 /* make all the gadgets */
519 static struct Gadget
*buildeasyreq_makegadgets(struct reqdims
*dims
,
520 STRPTR
*gadgetlabels
,
522 struct IntuitionBase
*IntuitionBase
)
524 UWORD gadgetheight
= dims
->fontheight
+ BUTTONBORDER_Y
* 2;
525 struct Gadget
*gadgetlist
, *thisgadget
= NULL
;
526 struct Image
*gadgetframe
;
528 UWORD xoffset
, yoffset
, spacing
, gadgetswidth
, gadgetsheight
, ngadgets
, nrows
;
530 struct DrawInfo
*dri
;
532 if (gadgetlabels
[0] == NULL
)
535 gadgetframe
= (struct Image
*)NewObject(NULL
, FRAMEICLASS
, IA_FrameType
, FRAME_BUTTON
,
536 IA_Width
, dims
->gadgetwidth
,
537 IA_Height
, gadgetheight
,
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
)
559 /* Only one gadget left? Too bad... */
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
)
572 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Gadgets arranged in %u rows\n", nrows
));
574 /* Now calculate spacing between gadgets */
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 -
604 yoffset
= dims
->height
- scr
->WBorBottom
- OUTERSPACING_Y
- gadgetsheight
;
606 for (y
= 0; y
< nrows
; y
++)
608 xoffset
= scr
->WBorLeft
+ OUTERSPACING_X
;
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
,
620 GA_Image
, gadgetframe
,
624 if (currentgadget
== 0)
625 gadgetlist
= thisgadget
;
629 intrequest_freegadgets(gadgetlist
, IntuitionBase
);
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.
646 yoffset
+= gadgetheight
;
649 FreeScreenDrawInfo(scr
, dri
);
654 /**********************************************************************************************/
656 static int charsinstring(CONST_STRPTR string
, char c
)
669 /**********************************************************************************************/