2 Copyright © 1995-2011, 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
, 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
,
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(APTR
, 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()
117 *****************************************************************************/
121 struct Screen
*scr
= NULL
, *lockedscr
= NULL
;
123 struct Gadget
*gadgets
;
124 CONST_STRPTR reqtitle
;
125 STRPTR formattedtext
;
126 STRPTR
*gadgetlabels
;
128 struct IntRequestUserData
*requserdata
;
131 DEBUG_BUILDEASYREQUEST(dprintf("intrequest_buildeasyrequest: window 0x%p easystruct 0x%p IDCMPFlags 0x08%x args 0x%p\n",
132 RefWindow
, easyStruct
, IDCMP
, Args
));
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 */
151 scr
= RefWindow
->WScreen
;
155 scr
= LockPubScreen(NULL
);
162 /* create everything */
163 formattedtext
= buildeasyreq_formattext(easyStruct
->es_TextFormat
,
167 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: formatted text 0x%p\n", formattedtext
));
170 gadgetlabels
= buildeasyreq_makelabels(&dims
,
171 easyStruct
->es_GadgetFormat
,
174 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: gadget labels 0x%p\n", 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
);
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
));
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
|
208 WFLG_SIMPLE_REFRESH*/ },
212 req
= OpenWindowTagList(NULL
, win_tags
);
214 DEBUG_BUILDEASYREQUEST(bug("intrequest_buildeasyrequest: window 0x%p\n", 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
);
233 /* opening requester failed -> free everything */
234 FreeVec(requserdata
);
236 } /* if (requserdata) */
238 intrequest_freegadgets(gadgets
, IntuitionBase
);
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
);
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
},
283 struct DrawInfo
*dri
;
287 dri
= GetScreenDrawInfo(scr
);
291 SetFont(req
->RPort
, dri
->dri_Font
);
293 /* draw background pattern */
294 SetABPenDrMd(req
->RPort
,
295 dri
->dri_Pens
[SHINEPEN
], dri
->dri_Pens
[BACKGROUNDPEN
],
297 SetAfPt(req
->RPort
, BgPattern
, 1);
298 RectFill(req
->RPort
, req
->BorderLeft
,
300 req
->Width
- req
->BorderRight
,
301 req
->Height
- req
->BorderBottom
);
302 SetAfPt(req
->RPort
, NULL
, 0);
305 frame
= (struct Image
*)NewObjectA(NULL
, FRAMEICLASS
, frame_tags
);
308 DrawImageState(req
->RPort
, frame
, 0, 0, IDS_NORMAL
, dri
);
309 DisposeObject((Object
*)frame
);
313 SetABPenDrMd(req
->RPort
,
314 dri
->dri_Pens
[TEXTPEN
], dri
->dri_Pens
[BACKGROUNDPEN
], JAM1
);
315 for (currentline
= 1; text
[0] != '\0'; currentline
++)
320 strend
= strchr(text
, '\n');
323 length
= strend
- text
;
327 length
= strlen(text
);
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
);
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
,
354 struct IntuitionBase
*IntuitionBase
)
356 STRPTR
*gadgetlabels
;
362 /* make room for pointer-array */
363 dims
->gadgets
= charsinstring(labeltext
, '|') + 1;
365 gadgetlabels
= AllocVec((dims
->gadgets
+ 1) * sizeof(STRPTR
), MEMF_ANY
);
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
);
377 FreeVec(gadgetlabels
);
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] != '|')
401 /**********************************************************************************************/
403 /**********************************************************************************************/
405 /* format the supplied text string by using the supplied args */
406 static STRPTR
buildeasyreq_formattext(CONST_STRPTR textformat
,
409 struct IntuitionBase
*IntuitionBase
)
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
);
424 /**********************************************************************************************/
426 /* calculate dimensions of the requester */
427 static BOOL
buildeasyreq_calculatedims(struct reqdims
*dims
,
429 STRPTR formattedtext
,
430 STRPTR
*gadgetlabels
,
431 struct IntuitionBase
*IntuitionBase
)
433 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
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
+
448 dims
->height
= scr
->WBorTop
+ dims
->fontheight
+ 1 +
452 /* Width of gadgets is not counted here. It's counted in buildeasyreq_makegadgets(). */
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
);
468 while (textline
[linelen
] != '\n')
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
;
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
;
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
;
518 /**********************************************************************************************/
520 /* make all the gadgets */
521 static struct Gadget
*buildeasyreq_makegadgets(struct reqdims
*dims
,
522 STRPTR
*gadgetlabels
,
524 struct IntuitionBase
*IntuitionBase
)
526 UWORD gadgetheight
= dims
->fontheight
+ BUTTONBORDER_Y
* 2;
527 struct Gadget
*gadgetlist
, *thisgadget
= NULL
;
528 struct Image
*gadgetframe
;
530 UWORD xoffset
, yoffset
, spacing
, gadgetswidth
, gadgetsheight
, ngadgets
, nrows
;
532 struct DrawInfo
*dri
;
534 if (gadgetlabels
[0] == NULL
)
537 gadgetframe
= (struct Image
*)NewObject(NULL
, FRAMEICLASS
, IA_FrameType
, FRAME_BUTTON
,
538 IA_Width
, dims
->gadgetwidth
,
539 IA_Height
, gadgetheight
,
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
)
561 /* Only one gadget left? Too bad... */
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
)
574 DEBUG_BUILDEASYREQUEST(bug("buildeasyreq_makegadgets: Gadgets arranged in %u rows\n", nrows
));
576 /* Now calculate spacing between gadgets */
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 -
606 yoffset
= dims
->height
- scr
->WBorBottom
- OUTERSPACING_Y
- gadgetsheight
;
608 for (y
= 0; y
< nrows
; y
++)
610 xoffset
= scr
->WBorLeft
+ OUTERSPACING_X
;
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
,
622 GA_Image
, gadgetframe
,
626 if (currentgadget
== 0)
627 gadgetlist
= thisgadget
;
631 intrequest_freegadgets(gadgetlist
, IntuitionBase
);
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.
648 yoffset
+= gadgetheight
;
651 FreeScreenDrawInfo(scr
, dri
);
656 /**********************************************************************************************/
658 static int charsinstring(CONST_STRPTR string
, char c
)
671 /**********************************************************************************************/