Minor fixes to comments.
[AROS.git] / rom / intuition / strgadgets.c
blob98cfa2deeddf67d54ac82975d8c558632c96bbd4
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4 $Id$
5 */
7 #include <proto/exec.h>
8 #include <proto/intuition.h>
9 #include <proto/graphics.h>
10 #include <proto/utility.h>
11 #include <proto/keymap.h>
12 #include <intuition/screens.h>
13 #include <intuition/cghooks.h>
14 #include <graphics/gfxmacros.h>
15 #include <devices/inputevent.h>
16 #include <aros/asmcall.h>
17 #include <stdlib.h> /* atol() */
18 #include <stdio.h> /* snprintf() */
19 #include <string.h>
21 #include "intuition_intern.h"
22 #include "strgadgets.h"
24 #ifdef __MORPHOS__
25 size_t stccpy(char *s1, const char *s2, size_t n);
26 #endif
28 #undef DEBUG
29 #define SDEBUG 0
30 #define DEBUG 0
31 #include <aros/debug.h>
33 /*****************************************************************************************/
35 #define CURSORPEN 0
36 #define STRBACKPEN 1
37 #define STRTEXTPEN 2
39 #define NUMPENS 3
40 #define STRALIGNMASK (GACT_STRINGLEFT|GACT_STRINGCENTER|GACT_STRINGRIGHT)
42 #define KEYBUFSIZE 10
43 #define SHIFT (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)
45 #define HELPRAW 95 /* Raw */
46 #define CTRL_A 1
47 #define CTRL_B 2
48 #define CTRL_C 3
49 #define CTRL_D 4
50 #define CTRL_E 5
51 #define CTRL_F 6
52 #define CTRL_G 7
53 #define CTRL_H 8
54 #define CTRL_I 9
55 #define CTRL_J 10
56 #define CTRL_K 11
57 #define CTRL_L 12
58 #define CTRL_M 13
59 #define CTRL_N 14
60 #define CTRL_O 15
61 #define CTRL_P 16
62 #define CTRL_Q 17
63 #define CTRL_R 18
64 #define CTRL_S 19
65 #define CTRL_T 20
66 #define CTRL_U 21
67 #define CTRL_V 22
68 #define CTRL_W 23
69 #define CTRL_X 24
70 #define CTRL_Y 25
71 #define CTRL_Z 26
73 #define BACKSPACE 8 /* Vanilla */
74 #define TAB 9 /* Vanilla */
75 #define TABRAW 66 /* Raw */
76 #define RETURN 13 /* Vanilla */
77 #define DELETE 127 /* Vanilla */
78 #define HOMERAW 112 /* Raw */
79 #define ENDRAW 113 /* Raw */
81 /*****************************************************************************************/
83 VOID UpdateStringInfo(struct Gadget *);
85 /*****************************************************************************************/
87 #define CharXSize(char, rp) ((rp->Font->tf_Flags & FPF_PROPORTIONAL) ? \
88 rp->Font->tf_XSize : TextLength(rp, &(char), 1))
91 #undef MIN
92 #define MIN(a, b) ((a < b) ? a : b)
94 /*****************************************************************************************/
96 CONST char cursorkey[] = "_";
97 #define CURSORKEYLEN 1
99 /*****************************************************************************************/
101 STATIC WORD MaxDispPos(struct StringInfo *strinfo, struct BBox *bbox,
102 struct RastPort *rp, struct IntuitionBase *IntuitionBase)
105 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
106 WORD numfit, max_disppos, numchars;
107 struct TextExtent te;
108 BOOL cursor_at_end;
110 cursor_at_end = (strinfo->BufferPos == strinfo->NumChars);
112 EnterFunc(bug("MaxDispPos(current length: %d, bufferpos=%d)\n", strinfo->NumChars, strinfo->BufferPos));
114 D(bug("cursor_at_end: %d\n", cursor_at_end));
116 if (cursor_at_end) /* Cursor at end of string ? */
118 D(bug("Making cursor last char\n"));
119 numchars = strinfo->NumChars + 1; /* Take cursor into account */
121 /* This has allready been done by UpdateDisp() which called us
122 strinfo->Buffer[strinfo->NumChars] = 0x20;
126 else
129 numchars = strinfo->NumChars;
133 /* Find the amount of characters that fit into the bbox, counting
134 ** from the last character in the buffer and forward,
136 numfit = TextFit(rp,
137 &(strinfo->Buffer[numchars - 1]),
138 numchars, &te, NULL,
139 -1, bbox->Width, rp->Font->tf_YSize);
142 max_disppos = numchars - numfit;
144 /* if ((max_disppos > 0) && (!cursor_at_end))
145 max_disppos --;
148 D(bug("Numchars w/cursor: %d, Numfit: %d, maxdisppos=%d bbox->Width = %d te->te_Width = %d\n",
149 numchars, numfit, max_disppos, bbox->Width, te.te_Width));
151 ReturnInt("MaxDispPos", WORD, max_disppos);
154 /*****************************************************************************************/
156 void UpdateDisp(struct Gadget *gad,
157 struct BBox *bbox,
158 struct RastPort *rp,
159 struct IntuitionBase *IntuitionBase)
163 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
164 struct TextExtent te;
165 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
166 STRPTR dispstr;
168 EnterFunc(bug("UpdateDisp(gad=%p, bbox=%p, rp=%p)\n",
169 gad, bbox, rp));
171 /* If the cursor is at the trailing \0, insert a SPACE instead */
172 if (strinfo->BufferPos == strinfo->NumChars)
173 strinfo->Buffer[strinfo->NumChars] = 0x20;
175 /* In this function we check if the cursor has gone outside
176 ** of the visible area (because of application setting
177 ** strinfo->BufferPos or strinfo->DispPos to a different value, or
178 ** because of user input).
179 ** This is made a bit difficult by the rule (R), that there
180 ** should NOT be available space on the right, and characters
181 ** scrolled out at the left, at the same time.
182 ** We have 3 possible scenarios:
183 ** 1) Cursor to the left of DispPos:
184 ** Set DispPos to the lowest of BufferPos and the
185 ** maximum allowed disppos (according to (R) ).
186 ** 2) Cursor to the right of visible area:
187 ** Set dispose sou that the cursor is the last visible character.
188 ** This afheres to (R).
189 ** 3) Cursor inside visible area. Do a check on rule (R),
190 ** and if DispPos > max allowed, then adjust it down,
191 ** so that the last character in the buffer becomes last character
192 ** displayed. (The cursor will still be visible after adjustion)
196 /* 1) Cursor to the left of visible area */
197 if (strinfo->BufferPos < strinfo->DispPos)
199 WORD max_disppos;
201 max_disppos = MaxDispPos(strinfo, bbox, rp, IntuitionBase);
202 strinfo->DispPos = MIN(strinfo->BufferPos, max_disppos);
204 else /* Cursor equal to the right of disppos [ 2) or 3) ] */
206 UWORD strsize;
208 /* How many pixels are there from current 1st displayed to the cursor ? */
209 strsize = TextLength(rp,
210 strinfo->Buffer + strinfo->DispPos,
211 strinfo->BufferPos - strinfo->DispPos + 1);
213 /* 2) More than fits into the gadget ? */
214 if (strsize > bbox->Width)
216 /* Compute new DispPos such that the cursor is at the right */
217 strinfo->DispPos = strinfo->BufferPos
218 - TextFit(rp,
219 &(strinfo->Buffer[strinfo->BufferPos]),
220 strinfo->NumChars, &te, NULL, -1,
221 bbox->Width, rp->Font->tf_YSize)
222 + 1;
224 D(bug("cursor right of visible area, new disppos: %d\n", strinfo->DispPos));
226 else /* 3). Cursor inside gadget */
228 WORD max_disppos;
230 max_disppos = MaxDispPos(strinfo, bbox, rp, IntuitionBase);
231 if (strinfo->DispPos > max_disppos)
232 strinfo->DispPos = max_disppos;
234 } /* if (cursor inside or to the right of visible area )*/
238 /* Update the DispCount */
239 /* It might be necessary with special handling for centre aligned gads */
240 dispstr = &(strinfo->Buffer[strinfo->DispPos]);
241 strinfo->DispCount = TextFit(rp, dispstr,
242 strinfo->NumChars - strinfo->DispPos,
243 &te, NULL, 1,
244 bbox->Width,
245 rp->Font->tf_YSize);
247 /* 0-terminate string */
248 strinfo->Buffer[strinfo->NumChars] = 0x00;
249 ReturnVoid("UpdateDisp");
252 /*****************************************************************************************/
254 STATIC UWORD GetTextLeft(struct Gadget *gad,
255 struct BBox *bbox,
256 struct RastPort *rp,
257 struct IntuitionBase *IntuitionBase)
259 /* Gets left position of text in the string gadget */
261 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
262 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
263 UWORD text_left = 0;
264 STRPTR dispstr = &(strinfo->Buffer[strinfo->DispPos]);
265 UWORD dispstrlen;
266 BOOL cursor_at_end;
268 cursor_at_end = (strinfo->BufferPos == strinfo->NumChars);
270 dispstrlen = strinfo->NumChars - strinfo->DispPos;
272 /* Calcluate start offset of gadget text */
273 switch (gad->Activation & STRALIGNMASK)
275 case GACT_STRINGLEFT:
276 /* FIXME: is this default: correct? */
277 default:
278 text_left = bbox->Left;
279 break;
281 case GACT_STRINGCENTER:
283 WORD textwidth = TextLength(rp, dispstr, dispstrlen);
285 if (cursor_at_end) textwidth += TextLength(rp, cursorkey, CURSORKEYLEN);
286 text_left = bbox->Left + ((bbox->Width - textwidth) / 2);
288 break;
290 case GACT_STRINGRIGHT:
292 WORD textwidth = TextLength(rp, dispstr, dispstrlen);
294 if (cursor_at_end) textwidth += TextLength(rp, cursorkey, CURSORKEYLEN);
295 text_left = bbox->Left + (bbox->Width - 1 - textwidth);
297 break;
299 return (text_left);
302 /*****************************************************************************************/
304 STATIC UWORD GetTextRight(struct Gadget *gad,
305 struct BBox *bbox,
306 struct RastPort *rp,
307 struct IntuitionBase *IntuitionBase)
309 /* Gets right offset of text in the string gadget */
311 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
312 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
313 UWORD text_right = 0;
314 STRPTR dispstr = &(strinfo->Buffer[strinfo->DispPos]);
315 UWORD dispstrlen;
316 BOOL cursor_at_end;
318 cursor_at_end = (strinfo->BufferPos == strinfo->NumChars);
320 dispstrlen = strinfo->NumChars - strinfo->DispPos;
322 /* Calcluate start offset of gadget text */
323 switch (gad->Activation & STRALIGNMASK)
325 case GACT_STRINGLEFT:
326 /* FIXME: is this default: correct? */
327 default:
328 text_right = bbox->Left + TextLength(rp, dispstr, dispstrlen);
329 break;
331 case GACT_STRINGCENTER:
333 WORD textwidth = TextLength(rp, dispstr, dispstrlen);
335 if (cursor_at_end) textwidth += TextLength(rp, cursorkey, CURSORKEYLEN);
336 text_right = bbox->Left + bbox->Width - 1 - ((bbox->Width - textwidth) / 2);
338 break;
340 case GACT_STRINGRIGHT:
341 text_right = bbox->Left + bbox->Width - 1;
342 break;
344 return (text_right);
347 /*****************************************************************************************/
349 STATIC VOID GetPensAndFont(struct Gadget *gad,
350 UWORD *pens,
351 struct Window *win,
352 struct RastPort *rp,
353 struct IntuitionBase *IntuitionBase)
356 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
357 struct DrawInfo *dri = GetScreenDrawInfo(win->WScreen);
358 BOOL docursor = FALSE;
360 SetFont(rp, dri->dri_Font);
362 if (gad->Flags & GFLG_STRINGEXTEND)
364 struct StringExtend *strext;
366 strext = ((struct StringInfo *)gad->SpecialInfo)->Extension;
368 if (strext->Font)
370 SetFont(rp, strext->Font);
373 if ((gad->Flags & GFLG_SELECTED) == GFLG_SELECTED)
375 pens[STRTEXTPEN] = strext->ActivePens[0];
376 pens[STRBACKPEN] = strext->ActivePens[1];
378 else
380 pens[STRTEXTPEN] = strext->Pens[0];
381 pens[STRBACKPEN] = strext->Pens[1];
385 else
387 /* We don't care to lock the screen because the window we're
388 ** drawn on does this. If the window is moved to another
389 ** public screen we will be called again to rerender (and get new
390 ** valid pens). If the window is closed, and the screen is closed
391 ** we won't be here anymore.
394 /* jDc: set the font to Topaz,8! */
395 if (GetPrivIBase(IntuitionBase)->TopazFont)
397 SetFont(rp,GetPrivIBase(IntuitionBase)->TopazFont);
398 } else {
399 SetFont(rp,GfxBase->DefaultFont);
402 #if 0
403 if ((gad->Flags & GFLG_SELECTED) == GFLG_SELECTED)
405 pens[STRTEXTPEN] = dri->dri_Pens[TEXTPEN];
406 pens[STRBACKPEN] = dri->dri_Pens[BACKGROUNDPEN];
409 else
411 #endif
412 pens[STRTEXTPEN] = dri->dri_Pens[TEXTPEN];
413 pens[STRBACKPEN] = dri->dri_Pens[BACKGROUNDPEN];
414 #if 0
416 #endif
419 pens[CURSORPEN] = dri->dri_Pens[FILLPEN];
421 /* do some protection against stupid apps so we don't get into white text on white background pb */
422 if (pens[STRTEXTPEN] == pens[STRBACKPEN])
424 if (pens[STRTEXTPEN] != 0)
426 pens[STRBACKPEN] = 0;
427 if (pens[STRTEXTPEN] != 3) docursor = TRUE;
429 else
431 pens[STRTEXTPEN] = 1;
432 pens[STRBACKPEN] = 0;
433 docursor = TRUE;
437 if ((pens[CURSORPEN] == pens[STRTEXTPEN]) || (pens[CURSORPEN] == pens[STRBACKPEN]))
439 pens[CURSORPEN] = (docursor ? 3 : ((pens[STRTEXTPEN] == 2) ? 2 : 1));
442 FreeScreenDrawInfo(win->WScreen, dri);
444 return;
447 /*****************************************************************************************/
449 ULONG HandleStrInput( struct Gadget *gad,
450 struct GadgetInfo *ginfo,
451 struct InputEvent *ievent,
452 UWORD *imsgcode,
453 struct IntuitionBase *IntuitionBase)
455 struct Library *UtilityBase = GetPrivIBase(IntuitionBase)->UtilityBase;
456 struct Library *KeymapBase = GetPrivIBase(IntuitionBase)->KeymapBase;
457 struct SGWork sgw;
458 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
459 struct StringExtend *strext = NULL;
460 ULONG command = 0;
462 EnterFunc(bug("HandleStrInput(gad=%p, ginfo=%p, ievent=%p)\n",
463 gad, ginfo, ievent));
465 if ((ievent->ie_Class == IECLASS_TIMER)) return 0;
467 D(bug("Gadget text: %s\n", strinfo->Buffer));
469 if (!ginfo)
470 ReturnInt("HandleStrInput", ULONG, 0UL);
472 UpdateStringInfo(gad);
474 /* Initialize SGWork */
475 sgw.Gadget = gad;
476 sgw.StringInfo = strinfo;
477 sgw.WorkBuffer = strinfo->Buffer; /* default */
478 sgw.PrevBuffer = strinfo->Buffer;
479 sgw.Modes = 0;
480 sgw.IEvent = ievent;
481 sgw.Code = 0;
482 sgw.BufferPos = strinfo->BufferPos;
483 sgw.NumChars = strinfo->NumChars;
484 sgw.Actions = 0;
485 sgw.LongInt = strinfo->LongInt;
486 sgw.GadgetInfo = ginfo;
487 sgw.EditOp = EO_NOOP;
489 if (gad->Flags & GFLG_STRINGEXTEND)
491 D(bug("HandleStrInput: Extended gadget\n"));
492 strext = strinfo->Extension;
493 if (strext->WorkBuffer)
495 sgw.WorkBuffer = strext->WorkBuffer;
496 /* The edit hook gets *copy* of the current buffer contents */
497 strcpy(sgw.WorkBuffer, strinfo->Buffer);
499 sgw.Modes = strext->InitialModes;
502 switch (ievent->ie_Class)
504 case IECLASS_RAWMOUSE:
505 if (ievent->ie_Code == SELECTDOWN)
507 command = SGH_CLICK;
508 sgw.Actions = SGA_USE | SGA_REDISPLAY;
509 D(bug("HandleStrInput: RAWMOUSE event\n"));
511 break;
513 case IECLASS_RAWKEY:
515 UBYTE buf;
517 D(bug("HandleStrInput: RAWKEY event\n"));
518 if (ievent->ie_Code & IECODE_UP_PREFIX)
520 D(bug("HandleStrInput: filter UP event\n"));
522 else
524 command = SGH_KEY;
525 sgw.Actions = SGA_USE;
526 if (1 == MapRawKey(sgw.IEvent, &buf, 1, strinfo->AltKeyMap))
528 D(bug("HandleStrInput: sgw.Code 0x%lx\n",buf));
529 sgw.Code = (UWORD)buf;
532 break;
537 if (!command)
538 ReturnInt("HandleStrInput", ULONG , 0UL);
540 /* Call the global editing hook */
542 D(bug("calling global hook, Buffer=%s, WorkBuffer=%s\n",
543 strinfo->Buffer, sgw.WorkBuffer));
544 CallHookPkt(GetPrivIBase(IntuitionBase)->GlobalEditHook, &sgw, &command);
546 /* If there is a local edit hook, run it */
547 if (strext)
549 if (strext->EditHook)
551 D(bug("calling local edit hook\n"));
552 CallHookPkt(strext->EditHook, &sgw, &command);
556 /* Copy possibly changed stuff into stringgad */
557 if (sgw.Actions & SGA_USE)
559 if (strext)
561 if (strext->WorkBuffer)
562 strcpy(strinfo->Buffer, strext->WorkBuffer);
565 strinfo->BufferPos = sgw.BufferPos;
566 strinfo->NumChars = sgw.NumChars;
567 strinfo->LongInt = sgw.LongInt;
569 #if 0
570 if (gad->Activation & GACT_LONGINT)
572 kprintf("strinfo->LongInt = %d\n",strinfo->LongInt);
575 else
577 kprintf("strinfo->Buffer = \"%s\"\n",strinfo->Buffer);
580 #endif
583 if (sgw.Actions & SGA_BEEP)
585 D(bug("SGA_BEEP not yet implemented. (lack of DisplayBeep())\n"));
588 if (sgw.Actions & (SGA_END | SGA_NEXTACTIVE | SGA_PREVACTIVE))
590 gad->Flags &= ~GFLG_SELECTED;
591 *imsgcode = sgw.Code;
592 D(bug("HandleStrInput: SGA_END\n"));
595 if (sgw.Actions & SGA_REDISPLAY)
597 D(bug("HandleStrInput: SGA_REDISPLAY\n"));
598 /* Hack for making strgclass work */
599 if ((gad->GadgetType & GTYP_GTYPEMASK) == GTYP_CUSTOMGADGET)
601 struct RastPort *rp;
602 D(bug("HandleStrInput: Rerendering boopsi gadget\n"));
604 if ((rp = ObtainGIRPort(ginfo)) != NULL)
606 struct gpRender method;
608 method.MethodID = GM_RENDER;
609 method.gpr_GInfo = ginfo;
610 method.gpr_RPort = rp;
611 method.gpr_Redraw = GREDRAW_UPDATE;
613 Custom_DoMethodA(IntuitionBase, gad, (Msg)&method);
615 ReleaseGIRPort(rp);
617 } /* if gadget is a strgclass object */
618 else
620 D(bug("HandleStrInput: Rerendering intuition gadget\n"));
621 RefreshStrGadget(gad, ginfo->gi_Window, ginfo->gi_Requester, IntuitionBase);
625 ReturnInt("HandleStrInput", ULONG, sgw.Actions);
628 /*****************************************************************************************/
630 STATIC ULONG DoSGHClick(struct SGWork *sgw, struct IntuitionBase *IntuitionBase)
633 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
634 struct Gadget *gad;
635 struct StringInfo *strinfo;
636 struct BBox bbox;
638 struct TextFont *oldfont;
639 struct RastPort *rp;
640 struct Window *window;
641 struct Requester *req;
643 UWORD text_left, text_right;
644 WORD mousex;
646 window = sgw->GadgetInfo->gi_Window;
647 req = sgw->GadgetInfo->gi_Requester;
649 GetGadgetDomain(sgw->Gadget, window->WScreen, window, NULL, (struct IBox *)&bbox);
650 mousex = window->MouseX - bbox.Left;
652 EnterFunc(bug("DoSGHClick(sgw=%p)\n", sgw));
654 D(bug("Gadget text: %s\n", sgw->WorkBuffer));
656 rp = sgw->GadgetInfo->gi_RastPort;
657 oldfont = rp->Font;
658 gad = sgw->Gadget;
659 strinfo = (struct StringInfo *)gad->SpecialInfo;
661 CalcBBox(window, req, gad, &bbox);
664 struct DrawInfo *dri;
666 dri = GetScreenDrawInfo(window->WScreen);
667 SetFont(rp, dri->dri_Font);
668 FreeScreenDrawInfo(window->WScreen, dri);
671 if (gad->Flags & GFLG_STRINGEXTEND)
673 struct StringExtend *strext = strinfo->Extension;
675 if (strext->Font)
677 SetFont(rp, strext->Font);
681 /* If we are made active, save contents to undobuffer (if any exists) */
682 if (!(gad->Flags & GFLG_SELECTED))
685 if (strinfo->UndoBuffer)
687 D(bug("sghclick: saving into undo buffer\n"));
688 strcpy(strinfo->UndoBuffer, strinfo->Buffer);
690 gad->Flags |= GFLG_SELECTED;
693 /* Get left & righ offsets of strgad text */
694 text_left = GetTextLeft (gad, &bbox, rp, IntuitionBase);
695 text_right = GetTextRight(gad, &bbox, rp, IntuitionBase);
697 D(bug("sghclick: text_left=%d, text_right=%d\n", text_left, text_right));
698 D(bug("sghclick: disppos=%d, dispcount=%d, cursor=%d\n",
699 strinfo->DispPos, strinfo->DispCount, sgw->BufferPos));
700 D(bug("Gadget text: %s\n", sgw->WorkBuffer));
702 /* Check if mouseclick is inside displayed text */
703 if ((mousex >= text_left) && (mousex <= text_right))
705 /* Find new cursor pos. Uses TextFit() to handle proportional fonts. */
707 struct TextExtent te;
708 STRPTR dispstr = strinfo->Buffer + strinfo->DispPos;
710 sgw->BufferPos = strinfo->DispPos
711 + TextFit(rp, dispstr, sgw->NumChars - strinfo->DispPos,
712 &te, NULL, 1,
713 mousex - text_left, rp->Font->tf_YSize);
714 D(bug("sghclick: click inside text.\n"));
716 else /* Click not inside text */
718 if (mousex < text_left)
720 /* Click on empty space at left. Set cursor to first visible */
721 sgw->BufferPos = strinfo->DispPos;
722 D(bug("sghclick: click left of text.\n"));
724 else
726 /* Click on empty space at right. Set cursor to last visible */
727 sgw->BufferPos = strinfo->DispPos + strinfo->DispCount;
728 D(bug("sghclick: click right of text.\n"));
731 } /* if (click is on text or not) */
733 D(bug("sghclick: new cursor position: %d\n", sgw->BufferPos));
735 sgw->Actions = (SGA_USE|SGA_REDISPLAY);
736 sgw->EditOp = EO_MOVECURSOR;
738 SetFont(rp, oldfont);
740 D(bug("Gadget text: %s\n", sgw->WorkBuffer));
742 ReturnInt ("DoSGHClick", ULONG, 1);
745 /*****************************************************************************************/
747 VOID MoveCharsLeft(STRPTR str, UWORD first, UWORD last, UWORD steps)
749 register UWORD i;
751 for (i = first; i <= last; i ++)
753 str[i - steps] = str[i];
755 str[last] = 0;
758 /*****************************************************************************************/
760 STATIC ULONG DoSGHKey(struct SGWork *sgw, struct IntuitionBase *IntuitionBase)
763 struct Library *UtilityBase = GetPrivIBase(IntuitionBase)->UtilityBase;
764 struct Gadget *gad;
765 struct StringInfo *strinfo;
766 UBYTE letter;
767 ULONG qual;
769 EnterFunc(bug("DoSGHKey(sgw=%p)\n", sgw));
771 gad = sgw->Gadget;
772 strinfo = sgw->StringInfo;
774 qual = sgw->IEvent->ie_Qualifier;
776 D(bug("sghkey: RawKey 0x%lx, sgw_Code 0x%lx\n",sgw->IEvent->ie_Code,sgw->Code));
778 sgw->EditOp = EO_NOOP;
780 D(bug("sghkey: qual 0x%lx ic_Flags 0x%lx Modes 0x%lx\n",
781 qual,
782 GetPrivIBase(IntuitionBase)->IControlPrefs.ic_Flags,
783 sgw->Modes));
785 if (sgw->Code == 0)
787 /* RAW Keys */
789 letter = sgw->IEvent->ie_Code;
791 if ((letter == CURSORLEFT) && (!(qual & SHIFT)))
793 D(bug("sghkey: CURSOR_LEFT\n"));
794 if (sgw->BufferPos > 0)
796 sgw->EditOp = EO_MOVECURSOR;
797 sgw->BufferPos --;
800 else if ((letter == CURSORRIGHT) && (!(qual & SHIFT)))
803 D(bug("sghkey: CURSOR_RIGHT\n"));
804 if (sgw->BufferPos < sgw->NumChars)
806 sgw->EditOp = EO_MOVECURSOR;
807 sgw->BufferPos ++;
811 else if ( ((letter == CURSORLEFT) && (qual & SHIFT)) ||
812 (letter == HOMERAW) )
814 if (sgw->BufferPos > 0)
816 sgw->BufferPos = 0;
817 sgw->EditOp = EO_MOVECURSOR;
820 else if ( ((letter == CURSORRIGHT) && (qual & SHIFT)) ||
821 (letter == ENDRAW) )
823 if (sgw->BufferPos < sgw->NumChars)
825 sgw->BufferPos = sgw->NumChars;
826 sgw->EditOp = EO_MOVECURSOR;
829 else if ((letter == TABRAW) && (qual & SHIFT))
831 D(bug("sghkey: SHIFT TAB\n"));
832 sgw->EditOp = EO_SPECIAL; /* FIXME: ??? is this correct ??? */
833 sgw->Code = 9;
834 sgw->Actions = (SGA_USE|SGA_PREVACTIVE);
836 else if (letter == HELPRAW)
840 else if (qual & IEQUALIFIER_RCOMMAND)
842 /* ANSI key but pressed together with right Amiga key */
843 #if 0
844 sgw->EditOp = EO_SPECIAL; /* FIXME: ??? is this correct ??? */
845 sgw->Actions = (SGA_USE|SGA_REUSE|SGA_END);
846 #endif
847 letter = ToUpper(sgw->Code);
849 /* stegerg: URGENTCHECMKE. Why disabled for AROS? */
850 #ifndef __MORPHOS__
851 /* FIXME: we need to handle RAMIGA-Q,RAMIGA-X here */
852 #else
853 if(letter == 'Q')
855 sgw->EditOp = EO_RESET;
857 if (strinfo->UndoBuffer)
859 D(bug("sghclick: saving into undo buffer\n"));
860 stccpy(strinfo->UndoBuffer, sgw->WorkBuffer,strinfo->MaxChars);
861 sgw->BufferPos = strinfo->UndoPos;
862 sgw->NumChars = strlen(sgw->WorkBuffer);
865 else
866 if(letter == 'X')
868 /* RCmd-X clears the input buffer. In fixed field mode
869 * jump cursor to the start of the buffer
871 D(bug("sghkey: CTRL-X\n"));
873 if (sgw->Modes & SGM_FIXEDFIELD)
875 D(bug("sghkey: SGM_FIXEDFIELD\n"));
876 sgw->BufferPos = 0;
877 sgw->EditOp = EO_MOVECURSOR;
879 else
881 sgw->BufferPos = 0;
882 sgw->WorkBuffer[sgw->BufferPos] = '\0';
883 sgw->NumChars = sgw->BufferPos;
884 sgw->EditOp = EO_CLEAR;
887 #endif
889 else
891 /* ANSI key */
893 letter = sgw->Code;
895 if ((qual & IEQUALIFIER_CONTROL) &&
896 (GetPrivIBase(IntuitionBase)->IControlPrefs.ic_Flags & ICF_STRGAD_FILTER) &&
897 !(sgw->Modes & SGM_NOFILTER))
899 /* ANSI key but pressed together with the control key */
901 D(bug("sghkey: CTRL pressed..filtering on\n"));
903 if (letter == CTRL_A)
905 /* CTRL-A jump cursor to start of buffer */
906 D(bug("sghkey: CTRL-A\n"));
907 sgw->BufferPos = 0;
908 sgw->EditOp = EO_MOVECURSOR;
910 else
911 if (letter == CTRL_B)
913 /* CTRL-B move the cursor back one char */
914 D(bug("sghkey: CTRL-B\n"));
915 if (sgw->BufferPos > 0)
917 sgw->BufferPos--;
918 sgw->EditOp = EO_MOVECURSOR;
921 else
922 if (letter == CTRL_D)
924 /* CTRL-D delete current char */
925 D(bug("sghkey: CTRL-D\n"));
926 if (sgw->BufferPos != sgw->NumChars)
928 MoveCharsLeft(sgw->WorkBuffer, sgw->BufferPos + 1, sgw->NumChars - 1, 1);
929 sgw->NumChars --;
930 sgw->EditOp = EO_DELFORWARD;
933 else
934 if (letter == CTRL_E)
936 /* CTRL-E move the cursor to the end of the line */
937 D(bug("sghkey: CTRL-E\n"));
938 if (sgw->BufferPos != sgw->NumChars)
940 sgw->BufferPos = sgw->NumChars;
941 sgw->EditOp = EO_MOVECURSOR;
944 else
945 if (letter == CTRL_F)
947 /* CTRL-F move the cursor forward one char */
948 D(bug("sghkey: CTRL-F\n"));
949 if (sgw->BufferPos != sgw->NumChars)
951 sgw->BufferPos++;
952 sgw->EditOp = EO_MOVECURSOR;
955 else
956 if (letter == CTRL_H)
958 /* CTRL-H Delete the character to the left of the cursor
959 * In fixed field mode, move cursor to previous character
961 D(bug("sghkey: CTRL-A\n"));
962 if (sgw->Modes & SGM_FIXEDFIELD)
964 D(bug("sghkey: SGM_FIXEDFIELD\n"));
965 if (sgw->BufferPos > 0)
967 sgw->BufferPos--;
968 sgw->EditOp = EO_MOVECURSOR;
971 else
973 if (sgw->BufferPos > 0)
975 int len;
976 len = sgw->NumChars - sgw->BufferPos;
977 memcpy(&sgw->WorkBuffer[sgw->BufferPos-1],&sgw->WorkBuffer[sgw->BufferPos],len);
979 sgw->BufferPos--;
980 sgw->WorkBuffer[sgw->BufferPos + len] = 0;
981 sgw->NumChars--;
982 sgw->EditOp = EO_DELBACKWARD;
986 else
987 if (letter == CTRL_K)
989 /* CTRL-K Delete from the character under the cursor to the end
990 * of the string
992 D(bug("sghkey: CTRL-K\n"));
993 sgw->WorkBuffer[sgw->BufferPos] = 0;
994 sgw->NumChars = sgw->BufferPos;
995 sgw->EditOp = EO_DELFORWARD;
997 else
998 if (letter == CTRL_M)
1000 /* CTRL-M Equivalent to Return or Enter
1002 D(bug("sghkey: CTRL-M\n"));
1003 sgw->EditOp = EO_ENTER;
1004 sgw->Code = 0;
1005 sgw->Actions = (SGA_USE|SGA_END);
1007 else
1008 if (letter == CTRL_W)
1010 /* CTRL-W Delete the previous word. In fixed field mode, jump
1011 * cursor to the start of the previous word
1013 D(bug("sghkey: CTRL-W\n"));
1014 if (sgw->Modes & SGM_FIXEDFIELD)
1016 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1018 else
1020 if (sgw->BufferPos > 0)
1022 int len;
1023 int pos;
1025 * search space
1027 for (pos=sgw->BufferPos-1;pos >= 0;pos--)
1029 if (sgw->WorkBuffer[pos] == ' ')
1031 break;
1034 len = sgw->NumChars - sgw->BufferPos;
1035 memcpy(&sgw->WorkBuffer[pos],&sgw->WorkBuffer[sgw->BufferPos],len);
1037 sgw->NumChars -= sgw->BufferPos - pos;
1038 sgw->BufferPos = pos;
1039 sgw->WorkBuffer[sgw->BufferPos + len] = 0;
1040 sgw->EditOp = EO_DELBACKWARD;
1044 else
1045 if (letter == CTRL_U)
1047 /* CTRL-U Delete from the character to the left of the cursor
1048 * to the start of the buffer. In fixed field mode, jump cursor to the start
1049 * of the buffer
1051 D(bug("sghkey: CTRL-U\n"));
1052 if (sgw->Modes & SGM_FIXEDFIELD)
1054 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1055 sgw->BufferPos = 0;
1056 sgw->EditOp = EO_MOVECURSOR;
1058 else
1060 if (sgw->BufferPos > 0)
1062 int len;
1063 len = sgw->NumChars - sgw->BufferPos;
1064 memcpy(&sgw->WorkBuffer[0],&sgw->WorkBuffer[sgw->BufferPos],len);
1066 sgw->BufferPos = 0;
1067 sgw->WorkBuffer[len] = 0;
1068 sgw->NumChars = len;
1069 sgw->EditOp = EO_DELBACKWARD;
1073 else
1074 if (letter == CTRL_X)
1076 /* CTRL-X clears the input buffer (like right amiga-x). In fixed field mode
1077 * jump cursor to the start of the buffer
1079 D(bug("sghkey: CTRL-X\n"));
1080 if (sgw->Modes & SGM_FIXEDFIELD)
1082 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1083 sgw->BufferPos = 0;
1084 sgw->EditOp = EO_MOVECURSOR;
1086 else
1088 sgw->BufferPos = 0;
1089 sgw->WorkBuffer[sgw->BufferPos] = 0;
1090 sgw->NumChars = sgw->BufferPos;
1091 sgw->EditOp = EO_CLEAR;
1094 else
1095 if (letter == CTRL_Z)
1097 /* CTRL-Z Jump cursor to the end of the buffer
1099 D(bug("sghkey: CTRL-Z\n"));
1100 sgw->BufferPos = sgw->NumChars;
1101 sgw->EditOp = EO_MOVECURSOR;
1104 else
1105 if (letter == BACKSPACE)
1107 if (sgw->BufferPos != 0)
1109 UWORD first = sgw->BufferPos;
1110 UWORD last = sgw->NumChars - 1;
1111 UWORD steps;
1112 if (qual & SHIFT)
1114 steps = sgw->BufferPos;
1116 sgw->BufferPos = 0;
1117 sgw->NumChars -= steps;
1119 else
1121 sgw->NumChars --;
1122 sgw->BufferPos --;
1123 steps = 1;
1125 MoveCharsLeft(sgw->WorkBuffer, first, last, steps);
1126 sgw->EditOp = EO_DELBACKWARD;
1129 else if (letter == DELETE)
1131 /* Check whether cursor is at the trailing 0 */
1132 if (sgw->BufferPos != sgw->NumChars)
1134 if (qual & SHIFT)
1136 sgw->WorkBuffer[sgw->BufferPos] = 0;
1137 sgw->NumChars = sgw->BufferPos;
1139 else
1141 MoveCharsLeft(sgw->WorkBuffer, sgw->BufferPos + 1, sgw->NumChars - 1, 1);
1142 sgw->NumChars --;
1144 sgw->EditOp = EO_DELFORWARD;
1147 else if (letter == RETURN)
1149 D(bug("sghkey: ENTER\n"));
1150 sgw->EditOp = EO_ENTER;
1151 sgw->Code = 0;
1152 sgw->Actions = (SGA_USE|SGA_END);
1154 else if (letter == TAB)
1156 D(bug("sghkey: TAB\n"));
1157 sgw->EditOp = EO_SPECIAL; /* FIXME: ??? is this correct ??? */
1158 sgw->Actions = (SGA_USE|SGA_NEXTACTIVE);
1160 else
1163 /* Validity check of letter */
1164 if (gad->Activation & GACT_LONGINT)
1166 if (letter == '-')
1168 if ((sgw->BufferPos != 0) || ((sgw->NumChars > 0) && (sgw->WorkBuffer[0] == '-')))
1169 sgw->EditOp = EO_BADFORMAT;
1172 else if ((letter < 0x30) || (letter > 0x39))
1174 sgw->EditOp = EO_BADFORMAT;
1176 else if (sgw->WorkBuffer[sgw->BufferPos] == '-')
1178 sgw->EditOp = EO_BADFORMAT;
1181 else /* Integer gadget ? */
1183 /* Is key a printable character ? */
1184 /* FIXME: Locale should be used here... */
1185 if ((letter & 0x60) == 0)
1187 sgw->EditOp = EO_BADFORMAT;
1189 } /* if (integer or string gadget) */
1191 if (sgw->EditOp != EO_BADFORMAT)
1194 if ((sgw->Modes & SGM_REPLACE) && (sgw->WorkBuffer[sgw->BufferPos]))
1196 D(bug("sghkey: replacing char at pos %d\n", sgw->BufferPos));
1198 sgw->WorkBuffer[sgw->BufferPos] = letter;
1199 sgw->EditOp = EO_REPLACECHAR;
1201 if (sgw->BufferPos < strinfo->MaxChars - 1)
1202 sgw->BufferPos ++;
1205 else
1207 /* Insert mode. Check if there is space for one more character
1208 ** NOTE: MaxChars inludes traing \0, so therefore the '- 1'
1210 if (sgw->NumChars < (strinfo->MaxChars - 1))
1212 register UWORD i;
1214 D(bug("sghkey: inserting char at pos %d\n", sgw->BufferPos));
1215 /* Move characters to the right of insertion point one step to the right */
1216 for (i = sgw->NumChars; i > sgw->BufferPos; i --)
1218 sgw->WorkBuffer[i] = sgw->WorkBuffer[i - 1];
1221 /* Insert letter */
1222 sgw->WorkBuffer[i] = letter;
1223 sgw->EditOp = EO_INSERTCHAR;
1224 sgw->NumChars ++;
1225 sgw->BufferPos ++;
1228 else
1230 sgw->EditOp = EO_NOOP;
1231 } /* if (enough space for ione mor letter) */
1232 } /* if (Replace or Insert mode) */
1233 } /* If (user pressed valid letter) */
1234 } /* Vanilla key but not backspace, delete, ... */
1235 } /* if (key or scancode) */
1237 /* Null-terminate the new string */
1238 sgw->WorkBuffer[sgw->NumChars] = 0;
1240 if (sgw->EditOp != EO_NOOP)
1241 sgw->Actions |= (SGA_USE|SGA_REDISPLAY);
1243 /* Integer gadget ? */
1244 if ((sgw->Actions & SGA_USE) && (gad->Activation & GACT_LONGINT))
1246 sgw->LongInt = atol(sgw->WorkBuffer);
1247 D(bug("Updated string number to %d\n", sgw->LongInt));
1250 ReturnInt ("DoSGHKey", ULONG, 1);
1253 /*****************************************************************************************/
1255 AROS_UFH3(ULONG, GlobalEditFunc,
1256 AROS_UFHA(struct Hook *, hook, A0),
1257 AROS_UFHA(struct SGWork *, sgw, A2),
1258 AROS_UFHA(ULONG *, command, A1)
1261 AROS_USERFUNC_INIT
1263 ULONG retcode = 0;
1265 switch (*command)
1267 case SGH_CLICK:
1268 retcode = DoSGHClick(sgw, (struct IntuitionBase *)hook->h_Data);
1269 break;
1271 case SGH_KEY:
1272 retcode = DoSGHKey (sgw, (struct IntuitionBase *)hook->h_Data);
1273 break;
1276 return retcode;
1278 AROS_USERFUNC_EXIT
1281 /*****************************************************************************************/
1283 VOID RefreshStrGadget(struct Gadget *gad,
1284 struct Window *win,
1285 struct Requester *req,
1286 struct IntuitionBase *IntuitionBase)
1288 struct GadgetInfo gi;
1289 struct RastPort *rp;
1291 EnterFunc(bug("RefreshStrGadget(gad=%p, win=%s)\n", gad, win->Title));
1293 SetupGInfo(&gi, win, req, gad, IntuitionBase);
1295 if ((rp = ObtainGIRPort(&gi)))
1297 if (gad->GadgetRender)
1299 if (gad->Flags & GFLG_GADGIMAGE)
1301 DrawImage(rp,
1302 (struct Image *)gad->GadgetRender,
1303 gad->LeftEdge,
1304 gad->TopEdge);
1306 else
1308 DrawBorder(rp,
1309 (struct Border *)gad->GadgetRender,
1310 gad->LeftEdge,
1311 gad->TopEdge);
1314 ReleaseGIRPort(rp);
1316 UpdateStrGadget(gad, win, req, IntuitionBase);
1318 ReturnVoid("RefreshStrGadget");
1321 /*****************************************************************************************/
1323 VOID UpdateStringInfo(struct Gadget *gad)
1325 /* Updates the stringinfo in case user has set some fields */
1327 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
1329 EnterFunc(bug("UpdateStringInfo(gad=%p)\n", gad));
1331 #if 0
1332 if (gad->Activation & GACT_LONGINT)
1334 if ((strinfo->NumChars != 0) || (strinfo->LongInt != 0))
1336 /* NOTE: The max number of chars written INCLUDES trailing \0 */
1337 snprintf(strinfo->Buffer, strinfo->MaxChars, "%d", strinfo->LongInt);
1340 #endif
1342 strinfo->NumChars = strlen(strinfo->Buffer);
1344 if (strinfo->BufferPos > strinfo->NumChars)
1346 strinfo->BufferPos = strinfo->NumChars;
1349 D(bug("%s gadget contains buffer %s of length %d\n",
1350 (gad->Activation & GACT_LONGINT) ? "Integer" : "String",
1351 strinfo->Buffer, strinfo->NumChars));
1353 ReturnVoid("UpdateStringInfo");
1356 /*****************************************************************************************/
1358 VOID UpdateStrGadget(struct Gadget *gad,
1359 struct Window *win,
1360 struct Requester *req,
1361 struct IntuitionBase *IntuitionBase)
1363 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
1364 struct GadgetInfo gi;
1365 struct BBox bbox;
1366 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
1367 UWORD text_left;
1368 UWORD text_top;
1369 struct RastPort *rp;
1370 STRPTR dispstr;
1371 UWORD pens[NUMPENS];
1373 EnterFunc(bug("UpdateStrGadget(current text=%s)\n", strinfo->Buffer));
1375 SetupGInfo(&gi, win, req, gad, IntuitionBase);
1377 rp = ObtainGIRPort(&gi);
1378 if (!rp) return;
1380 GetPensAndFont(gad, pens, win, rp, IntuitionBase);
1382 CalcBBox(win, req, gad, &bbox);
1384 /* Update the stringinfo struct in case of user change */
1385 UpdateStringInfo(gad);
1387 /* Update the DispPos and DispCount fields so that the gadget renders properly */
1388 UpdateDisp(gad, &bbox, rp, IntuitionBase);
1391 dispstr = strinfo->Buffer + strinfo->DispPos;
1393 /* Clear the background */
1394 SetAPen(rp, pens[STRBACKPEN]);
1395 SetDrMd(rp, JAM1);
1397 RectFill(rp,
1398 bbox.Left,
1399 bbox.Top,
1400 bbox.Left + bbox.Width - 1,
1401 bbox.Top + bbox.Height - 1);
1403 text_left = GetTextLeft(gad, &bbox, rp, IntuitionBase);
1406 /* Write the text into the gadget */
1407 SetABPenDrMd(rp, pens[STRTEXTPEN], pens[STRBACKPEN], JAM2);
1409 text_top = bbox.Top
1410 + ((bbox.Height - rp->Font->tf_YSize) >> 1)
1411 + rp->Font->tf_Baseline;
1413 Move(rp, text_left, text_top);
1415 D(bug("usg: Writing text %s of length %d at (%d, %d)\n",
1416 dispstr, strinfo->DispCount, text_left, text_top));
1418 Text(rp, dispstr, strinfo->DispCount);
1420 if (gad->Flags & GFLG_SELECTED)
1422 UWORD cursoroffset = strinfo->BufferPos - strinfo->DispPos;
1423 /* Render cursor */
1424 // SetAfPt(rp,NULL,0);
1425 D(bug("usg: Number of characters: %d\n", strinfo->NumChars));
1428 text_left += TextLength(rp, dispstr, cursoroffset);
1430 #if 1
1431 if (strinfo->BufferPos < strinfo->NumChars)
1433 SetABPenDrMd(rp, pens[STRTEXTPEN], pens[CURSORPEN], JAM2);
1434 Move(rp, text_left, text_top);
1435 Text(rp,
1436 dispstr + cursoroffset,
1437 1 );
1439 else
1441 struct TextExtent te;
1443 SetABPenDrMd(rp, pens[STRTEXTPEN], pens[CURSORPEN], JAM2|INVERSVID);
1444 TextExtent(rp, cursorkey, CURSORKEYLEN,&te);
1446 RectFill(rp,
1447 text_left+te.te_Extent.MinX,
1448 text_top+te.te_Extent.MinY,
1449 text_left+te.te_Extent.MaxX,
1450 text_top+te.te_Extent.MaxY);
1452 #else
1453 Move(rp, text_left, text_top);
1454 Text(rp,
1455 ((strinfo->BufferPos < strinfo->NumChars)
1456 ? dispstr + cursoroffset
1457 : cursorkey),
1458 1 );
1459 #endif
1461 } /* if (gadget selected => render cursor) */
1463 if (gad->Flags & GFLG_DISABLED )
1465 struct DrawInfo *dri = GetScreenDrawInfo(win->WScreen);
1467 RenderDisabledPattern(rp, dri, bbox.Left,
1468 bbox.Top,
1469 bbox.Left + bbox.Width - 1,
1470 bbox.Top + bbox.Height - 1,
1471 IntuitionBase );
1473 if (dri) FreeScreenDrawInfo(win->WScreen, dri);
1476 ReleaseGIRPort(rp);
1478 ReturnVoid("UpdateStrGadget");