some fixes to accented characters
[tangerine.git] / rom / intuition / strgadgets.c
blob129666e66815a7e947737ef7d660524329f075c7
1 /*
2 Copyright © 1995-2003, 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 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 WORD numfit, max_disppos, numchars;
106 struct TextExtent te;
107 BOOL cursor_at_end;
109 cursor_at_end = (strinfo->BufferPos == strinfo->NumChars);
111 EnterFunc(bug("MaxDispPos(current length: %d, bufferpos=%d)\n", strinfo->NumChars, strinfo->BufferPos));
113 D(bug("cursor_at_end: %d\n", cursor_at_end));
115 if (cursor_at_end) /* Cursor at end of string ? */
117 D(bug("Making cursor last char\n"));
118 numchars = strinfo->NumChars + 1; /* Take cursor into account */
120 /* This has allready been done by UpdateDisp() which called us
121 strinfo->Buffer[strinfo->NumChars] = 0x20;
125 else
128 numchars = strinfo->NumChars;
132 /* Find the amount of characters that fit into the bbox, counting
133 ** from the last character in the buffer and forward,
135 numfit = TextFit(rp,
136 &(strinfo->Buffer[numchars - 1]),
137 numchars, &te, NULL,
138 -1, bbox->Width, rp->Font->tf_YSize);
141 max_disppos = numchars - numfit;
143 /* if ((max_disppos > 0) && (!cursor_at_end))
144 max_disppos --;
147 D(bug("Numchars w/cursor: %d, Numfit: %d, maxdisppos=%d bbox->Width = %d te->te_Width = %d\n",
148 numchars, numfit, max_disppos, bbox->Width, te.te_Width));
150 ReturnInt("MaxDispPos", WORD, max_disppos);
153 /*****************************************************************************************/
155 void UpdateDisp(struct Gadget *gad,
156 struct BBox *bbox,
157 struct RastPort *rp,
158 struct IntuitionBase *IntuitionBase)
162 struct TextExtent te;
163 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
164 STRPTR dispstr;
166 EnterFunc(bug("UpdateDisp(gad=%p, bbox=%p, rp=%p)\n",
167 gad, bbox, rp));
169 /* If the cursor is at the trailing \0, insert a SPACE instead */
170 if (strinfo->BufferPos == strinfo->NumChars)
171 strinfo->Buffer[strinfo->NumChars] = 0x20;
173 /* In this function we check if the cursor has gone outside
174 ** of the visible area (because of application setting
175 ** strinfo->BufferPos or strinfo->DispPos to a different value, or
176 ** because of user input).
177 ** This is made a bit difficult by the rule (R), that there
178 ** should NOT be available space on the right, and characters
179 ** scrolled out at the left, at the same time.
180 ** We have 3 possible scenarios:
181 ** 1) Cursor to the left of DispPos:
182 ** Set DispPos to the lowest of BufferPos and the
183 ** maximum allowed disppos (according to (R) ).
184 ** 2) Cursor to the right of visible area:
185 ** Set dispose sou that the cursor is the last visible character.
186 ** This afheres to (R).
187 ** 3) Cursor inside visible area. Do a check on rule (R),
188 ** and if DispPos > max allowed, then adjust it down,
189 ** so that the last character in the buffer becomes last character
190 ** displayed. (The cursor will still be visible after adjustion)
194 /* 1) Cursor to the left of visible area */
195 if (strinfo->BufferPos < strinfo->DispPos)
197 WORD max_disppos;
199 max_disppos = MaxDispPos(strinfo, bbox, rp, IntuitionBase);
200 strinfo->DispPos = MIN(strinfo->BufferPos, max_disppos);
202 else /* Cursor equal to the right of disppos [ 2) or 3) ] */
204 UWORD strsize;
206 /* How many pixels are there from current 1st displayed to the cursor ? */
207 strsize = TextLength(rp,
208 strinfo->Buffer + strinfo->DispPos,
209 strinfo->BufferPos - strinfo->DispPos + 1);
211 /* 2) More than fits into the gadget ? */
212 if (strsize > bbox->Width)
214 /* Compute new DispPos such that the cursor is at the right */
215 strinfo->DispPos = strinfo->BufferPos
216 - TextFit(rp,
217 &(strinfo->Buffer[strinfo->BufferPos]),
218 strinfo->NumChars, &te, NULL, -1,
219 bbox->Width, rp->Font->tf_YSize)
220 + 1;
222 D(bug("cursor right of visible area, new disppos: %d\n", strinfo->DispPos));
224 else /* 3). Cursor inside gadget */
226 WORD max_disppos;
228 max_disppos = MaxDispPos(strinfo, bbox, rp, IntuitionBase);
229 if (strinfo->DispPos > max_disppos)
230 strinfo->DispPos = max_disppos;
232 } /* if (cursor inside or to the right of visible area )*/
236 /* Update the DispCount */
237 /* It might be necessary with special handling for centre aligned gads */
238 dispstr = &(strinfo->Buffer[strinfo->DispPos]);
239 strinfo->DispCount = TextFit(rp, dispstr,
240 strinfo->NumChars - strinfo->DispPos,
241 &te, NULL, 1,
242 bbox->Width,
243 rp->Font->tf_YSize);
245 /* 0-terminate string */
246 strinfo->Buffer[strinfo->NumChars] = 0x00;
247 ReturnVoid("UpdateDisp");
250 /*****************************************************************************************/
252 STATIC UWORD GetTextLeft(struct Gadget *gad,
253 struct BBox *bbox,
254 struct RastPort *rp,
255 struct IntuitionBase *IntuitionBase)
257 /* Gets left position of text in the string gadget */
259 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
260 UWORD text_left = 0;
261 STRPTR dispstr = &(strinfo->Buffer[strinfo->DispPos]);
262 UWORD dispstrlen;
263 BOOL cursor_at_end;
265 cursor_at_end = (strinfo->BufferPos == strinfo->NumChars);
267 dispstrlen = strinfo->NumChars - strinfo->DispPos;
269 /* Calcluate start offset of gadget text */
270 switch (gad->Activation & STRALIGNMASK)
272 case GACT_STRINGLEFT:
273 #warning FIXME: is this default: correct?
274 default:
275 text_left = bbox->Left;
276 break;
278 case GACT_STRINGCENTER:
280 WORD textwidth = TextLength(rp, dispstr, dispstrlen);
282 if (cursor_at_end) textwidth += TextLength(rp, cursorkey, CURSORKEYLEN);
283 text_left = bbox->Left + ((bbox->Width - textwidth) / 2);
285 break;
287 case GACT_STRINGRIGHT:
289 WORD textwidth = TextLength(rp, dispstr, dispstrlen);
291 if (cursor_at_end) textwidth += TextLength(rp, cursorkey, CURSORKEYLEN);
292 text_left = bbox->Left + (bbox->Width - 1 - textwidth);
294 break;
296 return (text_left);
299 /*****************************************************************************************/
301 STATIC UWORD GetTextRight(struct Gadget *gad,
302 struct BBox *bbox,
303 struct RastPort *rp,
304 struct IntuitionBase *IntuitionBase)
306 /* Gets right offset of text in the string gadget */
308 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
309 UWORD text_right = 0;
310 STRPTR dispstr = &(strinfo->Buffer[strinfo->DispPos]);
311 UWORD dispstrlen;
312 BOOL cursor_at_end;
314 cursor_at_end = (strinfo->BufferPos == strinfo->NumChars);
316 dispstrlen = strinfo->NumChars - strinfo->DispPos;
318 /* Calcluate start offset of gadget text */
319 switch (gad->Activation & STRALIGNMASK)
321 case GACT_STRINGLEFT:
322 #warning FIXME: is this default: correct?
323 default:
324 text_right = bbox->Left + TextLength(rp, dispstr, dispstrlen);
325 break;
327 case GACT_STRINGCENTER:
329 WORD textwidth = TextLength(rp, dispstr, dispstrlen);
331 if (cursor_at_end) textwidth += TextLength(rp, cursorkey, CURSORKEYLEN);
332 text_right = bbox->Left + bbox->Width - 1 - ((bbox->Width - textwidth) / 2);
334 break;
336 case GACT_STRINGRIGHT:
337 text_right = bbox->Left + bbox->Width - 1;
338 break;
340 return (text_right);
343 /*****************************************************************************************/
345 STATIC VOID GetPensAndFont(struct Gadget *gad,
346 UWORD *pens,
347 struct Window *win,
348 struct RastPort *rp,
349 struct IntuitionBase *IntuitionBase)
352 struct DrawInfo *dri = GetScreenDrawInfo(win->WScreen);
353 BOOL docursor = FALSE;
355 SetFont(rp, dri->dri_Font);
357 if (gad->Flags & GFLG_STRINGEXTEND)
359 struct StringExtend *strext;
361 strext = ((struct StringInfo *)gad->SpecialInfo)->Extension;
363 if (strext->Font)
365 SetFont(rp, strext->Font);
368 if ((gad->Flags & GFLG_SELECTED) == GFLG_SELECTED)
370 pens[STRTEXTPEN] = strext->ActivePens[0];
371 pens[STRBACKPEN] = strext->ActivePens[1];
373 else
375 pens[STRTEXTPEN] = strext->Pens[0];
376 pens[STRBACKPEN] = strext->Pens[1];
380 else
382 /* We don't care to lock the screen because the window we're
383 ** drawn on does this. If the window is moved to another
384 ** public screen we will be called again to rerender (and get new
385 ** valid pens). If the window is closed, and the screen is closed
386 ** we won't be here anymore.
389 /* jDc: set the font to Topaz,8! */
390 if (GetPrivIBase(IntuitionBase)->TopazFont)
392 SetFont(rp,GetPrivIBase(IntuitionBase)->TopazFont);
393 } else {
394 SetFont(rp,GfxBase->DefaultFont);
397 #if 0
398 if ((gad->Flags & GFLG_SELECTED) == GFLG_SELECTED)
400 pens[STRTEXTPEN] = dri->dri_Pens[TEXTPEN];
401 pens[STRBACKPEN] = dri->dri_Pens[BACKGROUNDPEN];
404 else
406 #endif
407 pens[STRTEXTPEN] = dri->dri_Pens[TEXTPEN];
408 pens[STRBACKPEN] = dri->dri_Pens[BACKGROUNDPEN];
409 #if 0
411 #endif
414 pens[CURSORPEN] = dri->dri_Pens[FILLPEN];
416 /* do some protection against stupid apps so we don't get into white text on white background pb */
417 if (pens[STRTEXTPEN] == pens[STRBACKPEN])
419 if (pens[STRTEXTPEN] != 0)
421 pens[STRBACKPEN] = 0;
422 if (pens[STRTEXTPEN] != 3) docursor = TRUE;
424 else
426 pens[STRTEXTPEN] = 1;
427 pens[STRBACKPEN] = 0;
428 docursor = TRUE;
432 if ((pens[CURSORPEN] == pens[STRTEXTPEN]) || (pens[CURSORPEN] == pens[STRBACKPEN]))
434 pens[CURSORPEN] = (docursor ? 3 : ((pens[STRTEXTPEN] == 2) ? 2 : 1));
437 FreeScreenDrawInfo(win->WScreen, dri);
439 return;
442 /*****************************************************************************************/
444 ULONG HandleStrInput( struct Gadget *gad,
445 struct GadgetInfo *ginfo,
446 struct InputEvent *ievent,
447 UWORD *imsgcode,
448 struct IntuitionBase *IntuitionBase)
450 struct SGWork sgw;
451 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
452 struct StringExtend *strext = NULL;
453 ULONG command = 0;
455 EnterFunc(bug("HandleStrInput(gad=%p, ginfo=%p, ievent=%p)\n",
456 gad, ginfo, ievent));
458 if ((ievent->ie_Class == IECLASS_TIMER)) return 0;
460 D(bug("Gadget text: %s\n", strinfo->Buffer));
462 if (!ginfo)
463 ReturnInt("HandleStrInput", ULONG, 0UL);
465 UpdateStringInfo(gad);
467 /* Initialize SGWork */
468 sgw.Gadget = gad;
469 sgw.StringInfo = strinfo;
470 sgw.WorkBuffer = strinfo->Buffer; /* default */
471 sgw.PrevBuffer = strinfo->Buffer;
472 sgw.Modes = 0;
473 sgw.IEvent = ievent;
474 sgw.Code = 0;
475 sgw.BufferPos = strinfo->BufferPos;
476 sgw.NumChars = strinfo->NumChars;
477 sgw.Actions = 0;
478 sgw.LongInt = strinfo->LongInt;
479 sgw.GadgetInfo = ginfo;
480 sgw.EditOp = EO_NOOP;
482 if (gad->Flags & GFLG_STRINGEXTEND)
484 D(bug("HandleStrInput: Extended gadget\n"));
485 strext = strinfo->Extension;
486 if (strext->WorkBuffer)
488 sgw.WorkBuffer = strext->WorkBuffer;
489 /* The edit hook gets *copy* of the current buffer contents */
490 strcpy(sgw.WorkBuffer, strinfo->Buffer);
492 sgw.Modes = strext->InitialModes;
495 switch (ievent->ie_Class)
497 case IECLASS_RAWMOUSE:
498 if (ievent->ie_Code == SELECTDOWN)
500 command = SGH_CLICK;
501 sgw.Actions = SGA_USE | SGA_REDISPLAY;
502 D(bug("HandleStrInput: RAWMOUSE event\n"));
504 break;
506 case IECLASS_RAWKEY:
508 UBYTE buf;
510 D(bug("HandleStrInput: RAWKEY event\n"));
511 if (ievent->ie_Code & IECODE_UP_PREFIX)
513 D(bug("HandleStrInput: filter UP event\n"));
515 else
517 command = SGH_KEY;
518 sgw.Actions = SGA_USE;
519 if (1 == MapRawKey(sgw.IEvent, &buf, 1, strinfo->AltKeyMap))
521 D(bug("HandleStrInput: sgw.Code 0x%lx\n",buf));
522 sgw.Code = (UWORD)buf;
525 break;
530 if (!command)
531 ReturnInt("HandleStrInput", ULONG , 0UL);
533 /* Call the global editing hook */
535 D(bug("calling global hook, Buffer=%s, WorkBuffer=%s\n",
536 strinfo->Buffer, sgw.WorkBuffer));
537 CallHookPkt(GetPrivIBase(IntuitionBase)->GlobalEditHook, &sgw, &command);
539 /* If there is a local edit hook, run it */
540 if (strext)
542 if (strext->EditHook)
544 D(bug("calling local edit hook\n"));
545 CallHookPkt(strext->EditHook, &sgw, &command);
549 /* Copy possibly changed stuff into stringgad */
550 if (sgw.Actions & SGA_USE)
552 if (strext)
554 if (strext->WorkBuffer)
555 strcpy(strinfo->Buffer, strext->WorkBuffer);
558 strinfo->BufferPos = sgw.BufferPos;
559 strinfo->NumChars = sgw.NumChars;
560 strinfo->LongInt = sgw.LongInt;
562 #if 0
563 if (gad->Activation & GACT_LONGINT)
565 kprintf("strinfo->LongInt = %d\n",strinfo->LongInt);
568 else
570 kprintf("strinfo->Buffer = \"%s\"\n",strinfo->Buffer);
573 #endif
576 if (sgw.Actions & SGA_BEEP)
578 D(bug("SGA_BEEP not yet implemented. (lack of DisplayBeep())\n"));
581 if (sgw.Actions & (SGA_END | SGA_NEXTACTIVE | SGA_PREVACTIVE))
583 gad->Flags &= ~GFLG_SELECTED;
584 *imsgcode = sgw.Code;
585 D(bug("HandleStrInput: SGA_END\n"));
588 if (sgw.Actions & SGA_REDISPLAY)
590 D(bug("HandleStrInput: SGA_REDISPLAY\n"));
591 /* Hack for making strgclass work */
592 if ((gad->GadgetType & GTYP_GTYPEMASK) == GTYP_CUSTOMGADGET)
594 struct RastPort *rp;
595 D(bug("HandleStrInput: Rerendering boopsi gadget\n"));
597 if ((rp = ObtainGIRPort(ginfo)) != NULL)
599 struct gpRender method;
601 method.MethodID = GM_RENDER;
602 method.gpr_GInfo = ginfo;
603 method.gpr_RPort = rp;
604 method.gpr_Redraw = GREDRAW_UPDATE;
606 Custom_DoMethodA(gad, (Msg)&method);
608 ReleaseGIRPort(rp);
610 } /* if gadget is a strgclass object */
611 else
613 D(bug("HandleStrInput: Rerendering intuition gadget\n"));
614 RefreshStrGadget(gad, ginfo->gi_Window, ginfo->gi_Requester, IntuitionBase);
618 ReturnInt("HandleStrInput", ULONG, sgw.Actions);
621 /*****************************************************************************************/
623 STATIC ULONG DoSGHClick(struct SGWork *sgw, struct IntuitionBase *IntuitionBase)
626 struct Gadget *gad;
627 struct StringInfo *strinfo;
628 struct BBox bbox;
630 struct TextFont *oldfont;
631 struct RastPort *rp;
632 struct Window *window;
633 struct Requester *req;
635 UWORD text_left, text_right;
636 WORD mousex;
638 window = sgw->GadgetInfo->gi_Window;
639 req = sgw->GadgetInfo->gi_Requester;
641 GetGadgetDomain(sgw->Gadget, window->WScreen, window, NULL, (struct IBox *)&bbox);
642 mousex = window->MouseX - bbox.Left;
644 EnterFunc(bug("DoSGHClick(sgw=%p)\n", sgw));
646 D(bug("Gadget text: %s\n", sgw->WorkBuffer));
648 rp = sgw->GadgetInfo->gi_RastPort;
649 oldfont = rp->Font;
650 gad = sgw->Gadget;
651 strinfo = (struct StringInfo *)gad->SpecialInfo;
653 CalcBBox(window, req, gad, &bbox);
656 struct DrawInfo *dri;
658 dri = GetScreenDrawInfo(window->WScreen);
659 SetFont(rp, dri->dri_Font);
660 FreeScreenDrawInfo(window->WScreen, dri);
663 if (gad->Flags & GFLG_STRINGEXTEND)
665 struct StringExtend *strext = strinfo->Extension;
667 if (strext->Font)
669 SetFont(rp, strext->Font);
673 /* If we are made active, save contents to undobuffer (if any exists) */
674 if (!(gad->Flags & GFLG_SELECTED))
677 if (strinfo->UndoBuffer)
679 D(bug("sghclick: saving into undo buffer\n"));
680 strcpy(strinfo->UndoBuffer, strinfo->Buffer);
682 gad->Flags |= GFLG_SELECTED;
685 /* Get left & righ offsets of strgad text */
686 text_left = GetTextLeft (gad, &bbox, rp, IntuitionBase);
687 text_right = GetTextRight(gad, &bbox, rp, IntuitionBase);
689 D(bug("sghclick: text_left=%d, text_right=%d\n", text_left, text_right));
690 D(bug("sghclick: disppos=%d, dispcount=%d, cursor=%d\n",
691 strinfo->DispPos, strinfo->DispCount, sgw->BufferPos));
692 D(bug("Gadget text: %s\n", sgw->WorkBuffer));
694 /* Check if mouseclick is inside displayed text */
695 if ((mousex >= text_left) && (mousex <= text_right))
697 /* Find new cursor pos. Uses TextFit() to handle proportional fonts. */
699 struct TextExtent te;
700 STRPTR dispstr = strinfo->Buffer + strinfo->DispPos;
702 sgw->BufferPos = strinfo->DispPos
703 + TextFit(rp, dispstr, sgw->NumChars - strinfo->DispPos,
704 &te, NULL, 1,
705 mousex - text_left, rp->Font->tf_YSize);
706 D(bug("sghclick: click inside text.\n"));
708 else /* Click not inside text */
710 if (mousex < text_left)
712 /* Click on empty space at left. Set cursor to first visible */
713 sgw->BufferPos = strinfo->DispPos;
714 D(bug("sghclick: click left of text.\n"));
716 else
718 /* Click on empty space at right. Set cursor to last visible */
719 sgw->BufferPos = strinfo->DispPos + strinfo->DispCount;
720 D(bug("sghclick: click right of text.\n"));
723 } /* if (click is on text or not) */
725 D(bug("sghclick: new cursor position: %d\n", sgw->BufferPos));
727 sgw->Actions = (SGA_USE|SGA_REDISPLAY);
728 sgw->EditOp = EO_MOVECURSOR;
730 SetFont(rp, oldfont);
732 D(bug("Gadget text: %s\n", sgw->WorkBuffer));
734 ReturnInt ("DoSGHClick", ULONG, 1);
737 /*****************************************************************************************/
739 VOID MoveCharsLeft(STRPTR str, UWORD first, UWORD last, UWORD steps)
741 register UWORD i;
743 for (i = first; i <= last; i ++)
745 str[i - steps] = str[i];
747 str[last] = 0;
750 /*****************************************************************************************/
752 STATIC ULONG DoSGHKey(struct SGWork *sgw, struct IntuitionBase *IntuitionBase)
755 struct Gadget *gad;
756 struct StringInfo *strinfo;
757 UBYTE letter;
758 ULONG qual;
760 EnterFunc(bug("DoSGHKey(sgw=%p)\n", sgw));
762 gad = sgw->Gadget;
763 strinfo = sgw->StringInfo;
765 qual = sgw->IEvent->ie_Qualifier;
767 D(bug("sghkey: RawKey 0x%lx, sgw_Code 0x%lx\n",sgw->IEvent->ie_Code,sgw->Code));
769 sgw->EditOp = EO_NOOP;
771 D(bug("sghkey: qual 0x%lx ic_Flags 0x%lx Modes 0x%lx\n",
772 qual,
773 GetPrivIBase(IntuitionBase)->IControlPrefs.ic_Flags,
774 sgw->Modes));
776 if (sgw->Code == 0)
778 /* RAW Keys */
780 letter = sgw->IEvent->ie_Code;
782 if ((letter == CURSORLEFT) && (!(qual & SHIFT)))
784 D(bug("sghkey: CURSOR_LEFT\n"));
785 if (sgw->BufferPos > 0)
787 sgw->EditOp = EO_MOVECURSOR;
788 sgw->BufferPos --;
791 else if ((letter == CURSORRIGHT) && (!(qual & SHIFT)))
794 D(bug("sghkey: CURSOR_RIGHT\n"));
795 if (sgw->BufferPos < sgw->NumChars)
797 sgw->EditOp = EO_MOVECURSOR;
798 sgw->BufferPos ++;
802 else if ( ((letter == CURSORLEFT) && (qual & SHIFT)) ||
803 (letter == HOMERAW) )
805 if (sgw->BufferPos > 0)
807 sgw->BufferPos = 0;
808 sgw->EditOp = EO_MOVECURSOR;
811 else if ( ((letter == CURSORRIGHT) && (qual & SHIFT)) ||
812 (letter == ENDRAW) )
814 if (sgw->BufferPos < sgw->NumChars)
816 sgw->BufferPos = sgw->NumChars;
817 sgw->EditOp = EO_MOVECURSOR;
820 else if ((letter == TABRAW) && (qual & SHIFT))
822 D(bug("sghkey: SHIFT TAB\n"));
823 sgw->EditOp = EO_SPECIAL; /* FIXME: ??? is this correct ??? */
824 sgw->Code = 9;
825 sgw->Actions = (SGA_USE|SGA_PREVACTIVE);
827 else if (letter == HELPRAW)
831 else if (qual & IEQUALIFIER_RCOMMAND)
833 /* ANSI key but pressed together with right Amiga key */
834 #if 0
835 sgw->EditOp = EO_SPECIAL; /* FIXME: ??? is this correct ??? */
836 sgw->Actions = (SGA_USE|SGA_REUSE|SGA_END);
837 #endif
838 letter = ToUpper(sgw->Code);
840 /* stegerg: URGENTCHECMKE. Why disabled for AROS? */
841 #ifndef __MORPHOS__
842 #warning we need to handle RAMIGA-Q,RAMIGA-X here
843 #else
844 if(letter == 'Q')
846 sgw->EditOp = EO_RESET;
848 if (strinfo->UndoBuffer)
850 D(bug("sghclick: saving into undo buffer\n"));
851 stccpy(strinfo->UndoBuffer, sgw->WorkBuffer,strinfo->MaxChars);
852 sgw->BufferPos = strinfo->UndoPos;
853 sgw->NumChars = strlen(sgw->WorkBuffer);
856 else
857 if(letter == 'X')
859 /* RCmd-X clears the input buffer. In fixed field mode
860 * jump cursor to the start of the buffer
862 D(bug("sghkey: CTRL-X\n"));
864 if (sgw->Modes & SGM_FIXEDFIELD)
866 D(bug("sghkey: SGM_FIXEDFIELD\n"));
867 sgw->BufferPos = 0;
868 sgw->EditOp = EO_MOVECURSOR;
870 else
872 sgw->BufferPos = 0;
873 sgw->WorkBuffer[sgw->BufferPos] = '\0';
874 sgw->NumChars = sgw->BufferPos;
875 sgw->EditOp = EO_CLEAR;
878 #endif
880 else
882 /* ANSI key */
884 letter = sgw->Code;
886 if ((qual & IEQUALIFIER_CONTROL) &&
887 (GetPrivIBase(IntuitionBase)->IControlPrefs.ic_Flags & ICF_STRGAD_FILTER) &&
888 !(sgw->Modes & SGM_NOFILTER))
890 /* ANSI key but pressed together with the control key */
892 D(bug("sghkey: CTRL pressed..filtering on\n"));
894 if (letter == CTRL_A)
896 /* CTRL-A jump cursor to start of buffer */
897 D(bug("sghkey: CTRL-A\n"));
898 sgw->BufferPos = 0;
899 sgw->EditOp = EO_MOVECURSOR;
901 else
902 if (letter == CTRL_B)
904 /* CTRL-B move the cursor back one char */
905 D(bug("sghkey: CTRL-B\n"));
906 if (sgw->BufferPos > 0)
908 sgw->BufferPos--;
909 sgw->EditOp = EO_MOVECURSOR;
912 else
913 if (letter == CTRL_D)
915 /* CTRL-D delete current char */
916 D(bug("sghkey: CTRL-D\n"));
917 if (sgw->BufferPos != sgw->NumChars)
919 MoveCharsLeft(sgw->WorkBuffer, sgw->BufferPos + 1, sgw->NumChars - 1, 1);
920 sgw->NumChars --;
921 sgw->EditOp = EO_DELFORWARD;
924 else
925 if (letter == CTRL_E)
927 /* CTRL-E move the cursor to the end of the line */
928 D(bug("sghkey: CTRL-E\n"));
929 if (sgw->BufferPos != sgw->NumChars)
931 sgw->BufferPos = sgw->NumChars;
932 sgw->EditOp = EO_MOVECURSOR;
935 else
936 if (letter == CTRL_F)
938 /* CTRL-F move the cursor forward one char */
939 D(bug("sghkey: CTRL-F\n"));
940 if (sgw->BufferPos != sgw->NumChars)
942 sgw->BufferPos++;
943 sgw->EditOp = EO_MOVECURSOR;
946 else
947 if (letter == CTRL_H)
949 /* CTRL-H Delete the character to the left of the cursor
950 * In fixed field mode, move cursor to previous character
952 D(bug("sghkey: CTRL-A\n"));
953 if (sgw->Modes & SGM_FIXEDFIELD)
955 D(bug("sghkey: SGM_FIXEDFIELD\n"));
956 if (sgw->BufferPos > 0)
958 sgw->BufferPos--;
959 sgw->EditOp = EO_MOVECURSOR;
962 else
964 if (sgw->BufferPos > 0)
966 int len;
967 len = sgw->NumChars - sgw->BufferPos;
968 memcpy(&sgw->WorkBuffer[sgw->BufferPos-1],&sgw->WorkBuffer[sgw->BufferPos],len);
970 sgw->BufferPos--;
971 sgw->WorkBuffer[sgw->BufferPos + len] = 0;
972 sgw->NumChars--;
973 sgw->EditOp = EO_DELBACKWARD;
977 else
978 if (letter == CTRL_K)
980 /* CTRL-K Delete from the character under the cursor to the end
981 * of the string
983 D(bug("sghkey: CTRL-K\n"));
984 sgw->WorkBuffer[sgw->BufferPos] = 0;
985 sgw->NumChars = sgw->BufferPos;
986 sgw->EditOp = EO_DELFORWARD;
988 else
989 if (letter == CTRL_M)
991 /* CTRL-M Equivalent to Return or Enter
993 D(bug("sghkey: CTRL-M\n"));
994 sgw->EditOp = EO_ENTER;
995 sgw->Code = 0;
996 sgw->Actions = (SGA_USE|SGA_END);
998 else
999 if (letter == CTRL_W)
1001 /* CTRL-W Delete the previous word. In fixed field mode, jump
1002 * cursor to the start of the previous word
1004 D(bug("sghkey: CTRL-W\n"));
1005 if (sgw->Modes & SGM_FIXEDFIELD)
1007 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1009 else
1011 if (sgw->BufferPos > 0)
1013 int len;
1014 int pos;
1016 * search space
1018 for (pos=sgw->BufferPos-1;pos >= 0;pos--)
1020 if (sgw->WorkBuffer[pos] == ' ')
1022 break;
1025 len = sgw->NumChars - sgw->BufferPos;
1026 memcpy(&sgw->WorkBuffer[pos],&sgw->WorkBuffer[sgw->BufferPos],len);
1028 sgw->NumChars -= sgw->BufferPos - pos;
1029 sgw->BufferPos = pos;
1030 sgw->WorkBuffer[sgw->BufferPos + len] = 0;
1031 sgw->EditOp = EO_DELBACKWARD;
1035 else
1036 if (letter == CTRL_U)
1038 /* CTRL-U Delete from the character to the left of the cursor
1039 * to the start of the buffer. In fixed field mode, jump cursor to the start
1040 * of the buffer
1042 D(bug("sghkey: CTRL-U\n"));
1043 if (sgw->Modes & SGM_FIXEDFIELD)
1045 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1046 sgw->BufferPos = 0;
1047 sgw->EditOp = EO_MOVECURSOR;
1049 else
1051 if (sgw->BufferPos > 0)
1053 int len;
1054 len = sgw->NumChars - sgw->BufferPos;
1055 memcpy(&sgw->WorkBuffer[0],&sgw->WorkBuffer[sgw->BufferPos],len);
1057 sgw->BufferPos = 0;
1058 sgw->WorkBuffer[len] = 0;
1059 sgw->NumChars = len;
1060 sgw->EditOp = EO_DELBACKWARD;
1064 else
1065 if (letter == CTRL_X)
1067 /* CTRL-X clears the input buffer (like right amiga-x). In fixed field mode
1068 * jump cursor to the start of the buffer
1070 D(bug("sghkey: CTRL-X\n"));
1071 if (sgw->Modes & SGM_FIXEDFIELD)
1073 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1074 sgw->BufferPos = 0;
1075 sgw->EditOp = EO_MOVECURSOR;
1077 else
1079 sgw->BufferPos = 0;
1080 sgw->WorkBuffer[sgw->BufferPos] = 0;
1081 sgw->NumChars = sgw->BufferPos;
1082 sgw->EditOp = EO_CLEAR;
1085 else
1086 if (letter == CTRL_Z)
1088 /* CTRL-Z Jump cursor to the end of the buffer
1090 D(bug("sghkey: CTRL-Z\n"));
1091 sgw->BufferPos = sgw->NumChars;
1092 sgw->EditOp = EO_MOVECURSOR;
1095 else
1096 if (letter == BACKSPACE)
1098 if (sgw->BufferPos != 0)
1100 UWORD first = sgw->BufferPos;
1101 UWORD last = sgw->NumChars - 1;
1102 UWORD steps;
1103 if (qual & SHIFT)
1105 steps = sgw->BufferPos;
1107 sgw->BufferPos = 0;
1108 sgw->NumChars -= steps;
1110 else
1112 sgw->NumChars --;
1113 sgw->BufferPos --;
1114 steps = 1;
1116 MoveCharsLeft(sgw->WorkBuffer, first, last, steps);
1117 sgw->EditOp = EO_DELBACKWARD;
1120 else if (letter == DELETE)
1122 /* Check whether cursor is at the trailing 0 */
1123 if (sgw->BufferPos != sgw->NumChars)
1125 if (qual & SHIFT)
1127 sgw->WorkBuffer[sgw->BufferPos] = 0;
1128 sgw->NumChars = sgw->BufferPos;
1130 else
1132 MoveCharsLeft(sgw->WorkBuffer, sgw->BufferPos + 1, sgw->NumChars - 1, 1);
1133 sgw->NumChars --;
1135 sgw->EditOp = EO_DELFORWARD;
1138 else if (letter == RETURN)
1140 D(bug("sghkey: ENTER\n"));
1141 sgw->EditOp = EO_ENTER;
1142 sgw->Code = 0;
1143 sgw->Actions = (SGA_USE|SGA_END);
1145 else if (letter == TAB)
1147 D(bug("sghkey: TAB\n"));
1148 sgw->EditOp = EO_SPECIAL; /* FIXME: ??? is this correct ??? */
1149 sgw->Actions = (SGA_USE|SGA_NEXTACTIVE);
1151 else
1154 /* Validity check of letter */
1155 if (gad->Activation & GACT_LONGINT)
1157 if (letter == '-')
1159 if ((sgw->BufferPos != 0) || ((sgw->NumChars > 0) && (sgw->WorkBuffer[0] == '-')))
1160 sgw->EditOp = EO_BADFORMAT;
1163 else if ((letter < 0x30) || (letter > 0x39))
1165 sgw->EditOp = EO_BADFORMAT;
1167 else if (sgw->WorkBuffer[sgw->BufferPos] == '-')
1169 sgw->EditOp = EO_BADFORMAT;
1172 else /* Integer gadget ? */
1174 /* Is key a printable character ? */
1175 #warning Locale should be used here...
1176 if ((letter & 0x60) == 0)
1178 sgw->EditOp = EO_BADFORMAT;
1180 } /* if (integer or string gadget) */
1182 if (sgw->EditOp != EO_BADFORMAT)
1185 if ((sgw->Modes & SGM_REPLACE) && (sgw->WorkBuffer[sgw->BufferPos]))
1187 D(bug("sghkey: replacing char at pos %d\n", sgw->BufferPos));
1189 sgw->WorkBuffer[sgw->BufferPos] = letter;
1190 sgw->EditOp = EO_REPLACECHAR;
1192 if (sgw->BufferPos < strinfo->MaxChars - 1)
1193 sgw->BufferPos ++;
1196 else
1198 /* Insert mode. Check if there is space for one more character
1199 ** NOTE: MaxChars inludes traing \0, so therefore the '- 1'
1201 if (sgw->NumChars < (strinfo->MaxChars - 1))
1203 register UWORD i;
1205 D(bug("sghkey: inserting char at pos %d\n", sgw->BufferPos));
1206 /* Move characters to the right of insertion point one step to the right */
1207 for (i = sgw->NumChars; i > sgw->BufferPos; i --)
1209 sgw->WorkBuffer[i] = sgw->WorkBuffer[i - 1];
1212 /* Insert letter */
1213 sgw->WorkBuffer[i] = letter;
1214 sgw->EditOp = EO_INSERTCHAR;
1215 sgw->NumChars ++;
1216 sgw->BufferPos ++;
1219 else
1221 sgw->EditOp = EO_NOOP;
1222 } /* if (enough space for ione mor letter) */
1223 } /* if (Replace or Insert mode) */
1224 } /* If (user pressed valid letter) */
1225 } /* Vanilla key but not backspace, delete, ... */
1226 } /* if (key or scancode) */
1228 /* Null-terminate the new string */
1229 sgw->WorkBuffer[sgw->NumChars] = 0;
1231 if (sgw->EditOp != EO_NOOP)
1232 sgw->Actions |= (SGA_USE|SGA_REDISPLAY);
1234 /* Integer gadget ? */
1235 if ((sgw->Actions & SGA_USE) && (gad->Activation & GACT_LONGINT))
1237 sgw->LongInt = atol(sgw->WorkBuffer);
1238 D(bug("Updated string number to %d\n", sgw->LongInt));
1241 ReturnInt ("DoSGHKey", ULONG, 1);
1244 /*****************************************************************************************/
1246 AROS_UFH3(ULONG, GlobalEditFunc,
1247 AROS_UFHA(struct Hook *, hook, A0),
1248 AROS_UFHA(struct SGWork *, sgw, A2),
1249 AROS_UFHA(ULONG *, command, A1)
1252 AROS_USERFUNC_INIT
1254 ULONG retcode = 0;
1256 switch (*command)
1258 case SGH_CLICK:
1259 retcode = DoSGHClick(sgw, (struct IntuitionBase *)hook->h_Data);
1260 break;
1262 case SGH_KEY:
1263 retcode = DoSGHKey (sgw, (struct IntuitionBase *)hook->h_Data);
1264 break;
1267 return retcode;
1269 AROS_USERFUNC_EXIT
1272 /*****************************************************************************************/
1274 VOID RefreshStrGadget(struct Gadget *gad,
1275 struct Window *win,
1276 struct Requester *req,
1277 struct IntuitionBase *IntuitionBase)
1279 struct GadgetInfo gi;
1280 struct RastPort *rp;
1282 EnterFunc(bug("RefreshStrGadget(gad=%p, win=%s)\n", gad, win->Title));
1284 SetupGInfo(&gi, win, req, gad, IntuitionBase);
1286 if ((rp = ObtainGIRPort(&gi)))
1288 if (gad->GadgetRender)
1290 if (gad->Flags & GFLG_GADGIMAGE)
1292 DrawImage(rp,
1293 (struct Image *)gad->GadgetRender,
1294 gad->LeftEdge,
1295 gad->TopEdge);
1297 else
1299 DrawBorder(rp,
1300 (struct Border *)gad->GadgetRender,
1301 gad->LeftEdge,
1302 gad->TopEdge);
1305 ReleaseGIRPort(rp);
1307 UpdateStrGadget(gad, win, req, IntuitionBase);
1309 ReturnVoid("RefreshStrGadget");
1312 /*****************************************************************************************/
1314 VOID UpdateStringInfo(struct Gadget *gad)
1316 /* Updates the stringinfo in case user has set some fields */
1318 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
1320 EnterFunc(bug("UpdateStringInfo(gad=%p)\n", gad));
1322 #if 0
1323 if (gad->Activation & GACT_LONGINT)
1325 if ((strinfo->NumChars != 0) || (strinfo->LongInt != 0))
1327 /* NOTE: The max number of chars written INCLUDES trailing \0 */
1328 snprintf(strinfo->Buffer, strinfo->MaxChars, "%d", strinfo->LongInt);
1331 #endif
1333 strinfo->NumChars = strlen(strinfo->Buffer);
1335 if (strinfo->BufferPos > strinfo->NumChars)
1337 strinfo->BufferPos = strinfo->NumChars;
1340 D(bug("%s gadget contains buffer %s of length %d\n",
1341 (gad->Activation & GACT_LONGINT) ? "Integer" : "String",
1342 strinfo->Buffer, strinfo->NumChars));
1344 ReturnVoid("UpdateStringInfo");
1347 /*****************************************************************************************/
1349 VOID UpdateStrGadget(struct Gadget *gad,
1350 struct Window *win,
1351 struct Requester *req,
1352 struct IntuitionBase *IntuitionBase)
1354 struct GadgetInfo gi;
1355 struct BBox bbox;
1356 struct StringInfo *strinfo = (struct StringInfo *)gad->SpecialInfo;
1357 UWORD text_left;
1358 UWORD text_top;
1359 struct RastPort *rp;
1360 STRPTR dispstr;
1361 UWORD dispstrlen;
1362 UWORD pens[NUMPENS];
1364 EnterFunc(bug("UpdateStrGadget(current text=%s)\n", strinfo->Buffer));
1366 SetupGInfo(&gi, win, req, gad, IntuitionBase);
1368 rp = ObtainGIRPort(&gi);
1369 if (!rp) return;
1371 GetPensAndFont(gad, pens, win, rp, IntuitionBase);
1373 CalcBBox(win, req, gad, &bbox);
1375 /* Update the stringinfo struct in case of user change */
1376 UpdateStringInfo(gad);
1378 /* Update the DispPos and DispCount fields so that the gadget renders properly */
1379 UpdateDisp(gad, &bbox, rp, IntuitionBase);
1382 dispstr = strinfo->Buffer + strinfo->DispPos;
1383 dispstrlen = MIN(strinfo->DispCount, strinfo->NumChars - strinfo->DispPos);
1385 /* Clear the background */
1386 SetAPen(rp, pens[STRBACKPEN]);
1387 SetDrMd(rp, JAM1);
1389 RectFill(rp,
1390 bbox.Left,
1391 bbox.Top,
1392 bbox.Left + bbox.Width - 1,
1393 bbox.Top + bbox.Height - 1);
1395 text_left = GetTextLeft(gad, &bbox, rp, IntuitionBase);
1398 /* Write the text into the gadget */
1399 SetABPenDrMd(rp, pens[STRTEXTPEN], pens[STRBACKPEN], JAM2);
1401 text_top = bbox.Top
1402 + ((bbox.Height - rp->Font->tf_YSize) >> 1)
1403 + rp->Font->tf_Baseline;
1405 Move(rp, text_left, text_top);
1407 D(bug("usg: Writing text %s of length %d at (%d, %d)\n",
1408 dispstr, strinfo->DispCount, text_left, text_top));
1410 Text(rp, dispstr, strinfo->DispCount);
1412 if (gad->Flags & GFLG_SELECTED)
1414 UWORD cursoroffset = strinfo->BufferPos - strinfo->DispPos;
1415 /* Render cursor */
1416 // SetAfPt(rp,NULL,0);
1417 D(bug("usg: Number of characters: %d\n", strinfo->NumChars));
1420 text_left += TextLength(rp, dispstr, cursoroffset);
1422 #if 1
1423 if (strinfo->BufferPos < strinfo->NumChars)
1425 SetABPenDrMd(rp, pens[STRTEXTPEN], pens[CURSORPEN], JAM2);
1426 Move(rp, text_left, text_top);
1427 Text(rp,
1428 dispstr + cursoroffset,
1429 1 );
1431 else
1433 struct TextExtent te;
1435 SetABPenDrMd(rp, pens[STRTEXTPEN], pens[CURSORPEN], JAM2|INVERSVID);
1436 TextExtent(rp, cursorkey, CURSORKEYLEN,&te);
1438 RectFill(rp,
1439 text_left+te.te_Extent.MinX,
1440 text_top+te.te_Extent.MinY,
1441 text_left+te.te_Extent.MaxX,
1442 text_top+te.te_Extent.MaxY);
1444 #else
1445 Move(rp, text_left, text_top);
1446 Text(rp,
1447 ((strinfo->BufferPos < strinfo->NumChars)
1448 ? dispstr + cursoroffset
1449 : cursorkey),
1450 1 );
1451 #endif
1453 } /* if (gadget selected => render cursor) */
1455 if (gad->Flags & GFLG_DISABLED )
1457 struct DrawInfo *dri = GetScreenDrawInfo(win->WScreen);
1459 RenderDisabledPattern(rp, dri, bbox.Left,
1460 bbox.Top,
1461 bbox.Left + bbox.Width - 1,
1462 bbox.Top + bbox.Height - 1,
1463 IntuitionBase );
1465 if (dri) FreeScreenDrawInfo(win->WScreen, dri);
1468 ReleaseGIRPort(rp);
1470 ReturnVoid("UpdateStrGadget");