Improved layout calculation.
[cake.git] / workbench / c / RequestString.c
blob3731d47c44183f65f88b1a03a26c51ae9b8aedb7
1 /*
2 * RequestString
4 * A program which requests a string from the user and prints it on
5 * the standard output.
7 * Written by Peter Bengtsson who does not agree to be held responsible
8 * for any damage or loss resulting from the use of this program.
10 * Use it as you wish for any and all nice things you can think of.
12 * $Id$
16 /******************************************************************************
19 NAME
21 RequestString [STRING] [TEXT] [TITLE] [NOGADS] [WIDTH] [SAFE] [PERSIST]
22 [ENCRYPT] [COMPARE] [PUBSCREEN]
24 SYNOPSIS
26 STRING, TEXT/K, TITLE/K, NOGADS/S, WIDTH/N, SAFE/S, PERSIST/S,
27 ENCRYPT/S, COMPARE/K, PUBSCREEN/K
29 LOCATION
33 FUNCTION
35 Shows a requester with a string gadget for user input.
37 INPUTS
39 STRING -- Initial content of string gadget.
40 TEXT -- Label string.
41 TITLE -- Title string of requester. This also adds dragbar, closegadget
42 and a depthgadget.
43 NOGADS -- Suppress gadgets when TITLE argument is given.
44 WIDTH -- Minimal width as number of characters.
45 SAFE -- Hide user input with "*".
46 PERSIST -- Intuition is blocked until requester is quitted.
47 ENCRYPT -- Encrypt result before returning. Requires that one of these
48 environment variables is set: USER, USERNAME or LOGIN.
49 COMPARE -- If the input string is not equal to the argument
50 of COMPARE return WARN.
51 PUBSCREEN -- Open requester on given pubscreen.
53 RESULT
55 NOTES
56 TODO: improve layout
58 EXAMPLE
60 BUGS
62 SEE ALSO
64 INTERNALS
66 ******************************************************************************/
68 #include <exec/memory.h>
69 #include <graphics/gfxbase.h>
70 #include <utility/tagitem.h>
71 #include <utility/hooks.h>
72 #include <intuition/sghooks.h>
73 #include <intuition/intuition.h>
75 #include <proto/exec.h>
76 #include <proto/dos.h>
77 #include <proto/intuition.h>
78 #include <proto/graphics.h>
79 #include <proto/gadtools.h>
80 #include <clib/alib_protos.h>
82 #include <string.h>
85 AROS_UFP3(ULONG, HookFunc,
86 AROS_UFPA(struct Hook *, TheHook, A0),
87 AROS_UFPA(struct SGWork *, Obj, A2),
88 AROS_UFPA(UBYTE *, Mess, A1));
91 #define TEMPLATE "STRING,TEXT/K,TITLE/K,NOGADS/S,WIDTH/N,SAFE/S,PERSIST/S,ENCRYPT/S,COMPARE/K,PUBSCREEN/K"
93 #define NArgs 10 /* Number of arguments */
95 #define STRING 0
96 #define TEXT 1
97 #define TITLE 2
98 #define NOGADS 3
99 #define WIDTH 4
100 #define SAFE 5
101 #define PERSIST 6
102 #define ENCRYPT 7
103 #define COMPARE 8
104 #define PUBSCREEN 9
106 #define MINWIDTH 8 /* Minimum width of gadget in characters */
108 const char version[] = "\0$VER: RequestString 39.5 (06.07.2009)";
110 int main(void)
112 IPTR ArgList[NArgs];
113 ULONG MsgClass = 0;
114 APTR VisInfo = NULL;
115 char CBuffer[12], UName[48];
116 struct TextExtent TExtent;
117 struct Hook SGHook = { {0} , 0, 0, 0};
118 struct RDArgs *Args = NULL;
119 struct ExtIntuiMessage *EIMess = NULL;
120 struct Gadget *Gad = NULL, *GList = NULL;
121 struct Window *Win = NULL;
122 struct Screen *Scr = NULL;
123 char *ReturnText = NULL;
125 int WWidth = 0, WHeight = 0;
126 int GWidth = 32, GHeight = 0;
127 long TXPos = 0, TYPos = 0;
128 int TLength = 0;
129 int TWidth = 0, THeight = 0;
131 LONG Ret = 20;
133 struct TagItem WindowTags[] =
135 {WA_PubScreen, 0},
136 {WA_Gadgets, 0},
137 {WA_Left, 0},
138 {WA_Top, 0},
139 {WA_Width, 0},
140 {WA_Height, 0},
141 {WA_DragBar, FALSE},
142 {WA_DepthGadget, FALSE},
143 {WA_CloseGadget, FALSE},
144 {WA_Title, 0},
145 {WA_IDCMP, IDCMP_GADGETUP | IDCMP_INACTIVEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_CLOSEWINDOW},
146 {WA_SizeGadget, FALSE},
147 {WA_Activate, TRUE}
150 struct NewGadget StringGad = {10, 5, 80, 15, NULL, NULL, 0, 0, NULL, NULL};
152 memset(ArgList, 0, sizeof(ArgList)); /* Clear the ArgList array */
154 if ((Args = ReadArgs(TEMPLATE, ArgList, NULL)) != NULL)
156 if ((Scr = LockPubScreen((UBYTE *)ArgList[PUBSCREEN])) != NULL)
158 if ((VisInfo = GetVisualInfo(Scr, NULL)) != NULL)
160 if ((Gad = CreateContext(&GList)) != NULL)
162 if (ArgList[WIDTH] != 0)
163 GWidth = *((LONG *)ArgList[WIDTH]);
164 if (GWidth < MINWIDTH)
165 GWidth = MINWIDTH;
167 GHeight = Scr->RastPort.TxHeight + 6;
168 WHeight = GHeight + Scr->WBorTop + Scr->WBorBottom + 8;
170 GWidth = GWidth * Scr->RastPort.TxWidth;
172 /* Forbid()/Permit() around this following poking in GfxBase? */
173 FontExtent(GfxBase->DefaultFont, &TExtent);
175 if (ArgList[TEXT] != 0)
177 TLength = strlen((char *)ArgList[TEXT]);
178 TWidth = TExtent.te_Width * TLength;
179 THeight = TExtent.te_Height;
180 WHeight += THeight;
183 if (GWidth > TWidth)
185 WWidth = GWidth + Scr->WBorLeft + Scr->WBorRight + 6;
187 else
189 WWidth = TWidth + Scr->WBorLeft + Scr->WBorRight + 6;
192 if (WWidth > Scr->Width)
194 WWidth = Scr->Width;
195 if (GWidth + Scr->WBorLeft + Scr->WBorRight > WWidth)
197 GWidth = WWidth - Scr->WBorLeft - Scr->WBorRight;
199 if (TWidth + Scr->WBorLeft + Scr->WBorRight > WWidth)
201 TWidth = WWidth - Scr->WBorLeft - Scr->WBorRight;
205 /* If the window has a title, it will also have a dragbar, closegadget
206 * and a depthgadget.
208 if (ArgList[TITLE] != 0)
210 WindowTags[6].ti_Data = TRUE;
211 if (ArgList[NOGADS] == 0)
213 WindowTags[7].ti_Data = TRUE;
214 WindowTags[8].ti_Data = TRUE;
216 WindowTags[9].ti_Data = ArgList[TITLE];
217 WHeight += Scr->BarHeight;
220 StringGad.ng_VisualInfo = VisInfo;
221 StringGad.ng_Width = GWidth;
222 StringGad.ng_Height = GHeight;
223 StringGad.ng_TopEdge = WHeight - GHeight - Scr->WBorBottom - 3;
224 StringGad.ng_LeftEdge = (WWidth - GWidth) / 2;
226 /* Initialize the Hook if we are using a safe stringgadget.
227 * SGHook.d_Data points to storage space for the string which
228 * will be returned. Memory should be cleared.
231 if (ArgList[SAFE] != 0)
233 SGHook.h_Entry = (HOOKFUNC)HookFunc;
234 /* SGHook.h_SubEntry=NULL; */
235 SGHook.h_Data = AllocVec(98, MEMF_ANY | MEMF_CLEAR); /* Should be made dynamic if possible */
236 if (ArgList[STRING] != 0)
238 int i = -1;
239 strcpy((char *)SGHook.h_Data, (char *)ArgList[STRING]);
240 while (((char *)ArgList[STRING])[++i] != 0)
241 ((char *)ArgList[STRING])[i] = '*';
248 Gad = CreateGadget
250 STRING_KIND,
251 Gad, &StringGad,
252 GTST_EditHook, (ArgList[SAFE] == 0) ? NULL : &SGHook,
253 GTST_String, ArgList[STRING],
254 TAG_END
256 ) != NULL
259 /* Screen Gadget */
260 WindowTags[0].ti_Data = (IPTR)Scr;
261 WindowTags[1].ti_Data = (IPTR)GList;
262 /* Width & Height */
263 WindowTags[4].ti_Data = WWidth;
264 WindowTags[5].ti_Data = WHeight;
265 /* X & Y Pos */
266 WindowTags[2].ti_Data = (Scr->Width-WWidth) >> 1;
267 WindowTags[3].ti_Data = (Scr->Height-WHeight) >> 1;
269 if ((Win = OpenWindowTagList(NULL, WindowTags)) != NULL)
271 /* Is there some (un)informative text in the window? */
273 if (ArgList[TEXT] != 0)
275 /* Colour should rather be selected with thougt to the background of the window, fix this. */
276 SetAPen(Win->RPort, 1);
277 TXPos = (WWidth - TWidth) / 2;
278 TYPos = GfxBase->DefaultFont->tf_Baseline + Win->BorderTop + 1;
279 Move(Win->RPort, TXPos, TYPos);
280 Text(Win->RPort, (char *)ArgList[TEXT], TLength);
285 WaitPort(Win->UserPort);
286 EIMess = (struct ExtIntuiMessage *)GT_GetIMsg(Win->UserPort);
287 MsgClass=EIMess->eim_IntuiMessage.Class;
288 GT_ReplyIMsg((struct IntuiMessage *)EIMess);
290 switch(MsgClass)
292 case IDCMP_ACTIVEWINDOW :
293 ActivateGadget(Gad, Win, NULL);
294 break;
296 case IDCMP_INACTIVEWINDOW :
297 if (ArgList[PERSIST])
299 ScreenToFront(Win->WScreen);
300 WindowToFront(Win);
301 ActivateWindow(Win);
303 break;
305 case IDCMP_REFRESHWINDOW :
306 GT_BeginRefresh(Win);
307 if (ArgList[TEXT] != 0)
309 Move(Win->RPort, TXPos, TYPos);
310 Text(Win->RPort, (char *)ArgList[TEXT], TLength);
312 GT_EndRefresh(Win,TRUE);
313 break;
317 while ((MsgClass != IDCMP_GADGETUP) && (MsgClass != IDCMP_CLOSEWINDOW));
319 GT_GetGadgetAttrs(Gad, Win, NULL, GTST_String, &ReturnText, TAG_END);
321 if (ArgList[SAFE] != 0)
322 ReturnText = (char *)SGHook.h_Data;
324 /* Try to find out who the user is if we are to encrypt the output. */
325 /* I really don't know how to acquire the username, but this might */
326 /* be a good guess of how to do it. */
328 if (ArgList[ENCRYPT] != 0)
330 if (GetVar("USER", UName, 47, 0) == -1)
331 if (GetVar("USERNAME", UName, 47, 0) == -1)
332 if (GetVar("LOGIN", UName, 47, 0) == -1)
333 UName[0] = 0;
334 ACrypt(CBuffer, ReturnText, UName);
335 ReturnText = CBuffer;
338 Printf("\"%s\"\n", ReturnText);
340 /* Here follows the COMPARE parameter. If the input string is not equal
341 * to the argument of COMPARE we return WARN.
344 if (ArgList[COMPARE] != 0)
345 Ret = (strcmp(ReturnText, (char *)ArgList[COMPARE])) ? RETURN_WARN : 0;
346 else
347 Ret = 0;
354 else if (ArgList[PUBSCREEN] != 0)
355 Ret = 10;
357 else
359 PrintFault(IoErr(), "RequestString");
362 /* Clean up. */
363 if (SGHook.h_Data != NULL)
364 FreeVec(SGHook.h_Data);
365 if (Args)
366 FreeArgs(Args);
367 if (Win)
368 CloseWindow(Win);
369 if (GList)
370 FreeGadgets(GList);
371 if (VisInfo)
372 FreeVisualInfo(VisInfo);
373 if (Scr)
374 UnlockPubScreen(NULL, Scr);
376 return Ret;
380 /* EditHook function for safe stringgadgets */
382 AROS_UFH3(ULONG, HookFunc,
383 AROS_UFHA(struct Hook *, TheHook, A0),
384 AROS_UFHA(struct SGWork *, Obj, A2),
385 AROS_UFHA(UBYTE *, Mess, A1))
387 AROS_USERFUNC_INIT
389 int i0,i1;
390 char * const Tmp=(char *)TheHook->h_Data;
392 if (Mess[0] == SGH_KEY)
394 Obj->Actions |= SGA_USE;
396 switch(Obj->EditOp)
398 case EO_DELBACKWARD :
399 i0 = Obj->StringInfo->BufferPos;
400 i1 = Obj->StringInfo->NumChars - Obj->NumChars;
401 strcpy(&Tmp[i0 - i1], &Tmp[i0]);
402 break;
404 case EO_DELFORWARD :
405 i0 = Obj->StringInfo->BufferPos;
406 i1 = Obj->StringInfo->NumChars - Obj->NumChars;
407 strcpy(&Tmp[i0], &Tmp[i0 + i1]);
408 break;
410 case EO_ENTER :
411 /* Exit handling. */
412 break;
414 case EO_RESET :
415 Tmp[0] = 0;
416 break;
418 case EO_INSERTCHAR :
419 if (strlen(Tmp) > 96)
420 Obj->Actions &= ~SGA_USE;
421 i0 = Obj->StringInfo->BufferPos;
422 Obj->WorkBuffer[i0] = '*';
423 i1 = strlen(Tmp) + 1;
424 while (i1-- != i0)
425 Tmp[i1 + 1] = Tmp[i1];
426 Tmp[i0] = Obj->Code;
427 break;
429 case EO_CLEAR :
430 Tmp[0] = 0;
431 break;
433 case EO_BIGCHANGE : /* Not Allowed */
434 case EO_UNDO :
435 case EO_SPECIAL :
436 Obj->Actions &= ~SGA_USE;
437 break;
439 return ~0;
441 else
443 Obj->Actions &= ~ SGA_USE;
444 return 0;
447 return 0;
449 AROS_USERFUNC_EXIT