2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
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() */
21 #include "intuition_intern.h"
22 #include "strgadgets.h"
25 size_t stccpy(char *s1
, const char *s2
, size_t n
);
31 #include <aros/debug.h>
33 /*****************************************************************************************/
40 #define STRALIGNMASK (GACT_STRINGLEFT|GACT_STRINGCENTER|GACT_STRINGRIGHT)
43 #define SHIFT (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)
45 #define HELPRAW 95 /* Raw */
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))
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
;
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;
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,
137 &(strinfo
->Buffer
[numchars
- 1]),
139 -1, bbox
->Width
, rp
->Font
->tf_YSize
);
142 max_disppos
= numchars
- numfit
;
144 /* if ((max_disppos > 0) && (!cursor_at_end))
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
,
159 struct IntuitionBase
*IntuitionBase
)
163 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
164 struct TextExtent te
;
165 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
168 EnterFunc(bug("UpdateDisp(gad=%p, bbox=%p, rp=%p)\n",
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
)
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) ] */
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
219 &(strinfo
->Buffer
[strinfo
->BufferPos
]),
220 strinfo
->NumChars
, &te
, NULL
, -1,
221 bbox
->Width
, rp
->Font
->tf_YSize
)
224 D(bug("cursor right of visible area, new disppos: %d\n", strinfo
->DispPos
));
226 else /* 3). Cursor inside gadget */
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
,
247 /* 0-terminate string */
248 strinfo
->Buffer
[strinfo
->NumChars
] = 0x00;
249 ReturnVoid("UpdateDisp");
252 /*****************************************************************************************/
254 STATIC UWORD
GetTextLeft(struct Gadget
*gad
,
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
;
264 STRPTR dispstr
= &(strinfo
->Buffer
[strinfo
->DispPos
]);
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? */
278 text_left
= bbox
->Left
;
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);
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
);
302 /*****************************************************************************************/
304 STATIC UWORD
GetTextRight(struct Gadget
*gad
,
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
]);
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? */
328 text_right
= bbox
->Left
+ TextLength(rp
, dispstr
, dispstrlen
);
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);
340 case GACT_STRINGRIGHT
:
341 text_right
= bbox
->Left
+ bbox
->Width
- 1;
347 /*****************************************************************************************/
349 STATIC VOID
GetPensAndFont(struct Gadget
*gad
,
353 struct IntuitionBase
*IntuitionBase
)
356 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
357 struct DrawInfo
*dri
= GetScreenDrawInfo(win
->WScreen
);
359 SetFont(rp
, dri
->dri_Font
);
361 if (gad
->Flags
& GFLG_STRINGEXTEND
)
363 struct StringExtend
*strext
;
365 strext
= ((struct StringInfo
*)gad
->SpecialInfo
)->Extension
;
369 SetFont(rp
, strext
->Font
);
372 if ((gad
->Flags
& GFLG_SELECTED
) == GFLG_SELECTED
)
374 pens
[STRTEXTPEN
] = strext
->ActivePens
[0];
375 pens
[STRBACKPEN
] = strext
->ActivePens
[1];
379 pens
[STRTEXTPEN
] = strext
->Pens
[0];
380 pens
[STRBACKPEN
] = strext
->Pens
[1];
386 /* We don't care to lock the screen because the window we're
387 ** drawn on does this. If the window is moved to another
388 ** public screen we will be called again to rerender (and get new
389 ** valid pens). If the window is closed, and the screen is closed
390 ** we won't be here anymore.
393 /* jDc: set the font to Topaz,8! */
394 if (GetPrivIBase(IntuitionBase
)->TopazFont
)
396 SetFont(rp
,GetPrivIBase(IntuitionBase
)->TopazFont
);
398 SetFont(rp
,GfxBase
->DefaultFont
);
402 if ((gad
->Flags
& GFLG_SELECTED
) == GFLG_SELECTED
)
404 pens
[STRTEXTPEN
] = dri
->dri_Pens
[TEXTPEN
];
405 pens
[STRBACKPEN
] = dri
->dri_Pens
[BACKGROUNDPEN
];
411 pens
[STRTEXTPEN
] = dri
->dri_Pens
[TEXTPEN
];
412 pens
[STRBACKPEN
] = dri
->dri_Pens
[BACKGROUNDPEN
];
418 pens
[CURSORPEN
] = dri
->dri_Pens
[FILLPEN
];
420 FreeScreenDrawInfo(win
->WScreen
, dri
);
425 /*****************************************************************************************/
427 ULONG
HandleStrInput( struct Gadget
*gad
,
428 struct GadgetInfo
*ginfo
,
429 struct InputEvent
*ievent
,
431 struct IntuitionBase
*IntuitionBase
)
433 struct Library
*UtilityBase
= GetPrivIBase(IntuitionBase
)->UtilityBase
;
434 struct Library
*KeymapBase
= GetPrivIBase(IntuitionBase
)->KeymapBase
;
436 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
437 struct StringExtend
*strext
= NULL
;
440 EnterFunc(bug("HandleStrInput(gad=%p, ginfo=%p, ievent=%p)\n",
441 gad
, ginfo
, ievent
));
443 if ((ievent
->ie_Class
== IECLASS_TIMER
)) return 0;
445 D(bug("Gadget text: %s\n", strinfo
->Buffer
));
448 ReturnInt("HandleStrInput", ULONG
, 0UL);
450 UpdateStringInfo(gad
);
452 /* Initialize SGWork */
454 sgw
.StringInfo
= strinfo
;
455 sgw
.WorkBuffer
= strinfo
->Buffer
; /* default */
456 sgw
.PrevBuffer
= strinfo
->Buffer
;
460 sgw
.BufferPos
= strinfo
->BufferPos
;
461 sgw
.NumChars
= strinfo
->NumChars
;
463 sgw
.LongInt
= strinfo
->LongInt
;
464 sgw
.GadgetInfo
= ginfo
;
465 sgw
.EditOp
= EO_NOOP
;
467 if (gad
->Flags
& GFLG_STRINGEXTEND
)
469 D(bug("HandleStrInput: Extended gadget\n"));
470 strext
= strinfo
->Extension
;
471 if (strext
->WorkBuffer
)
473 sgw
.WorkBuffer
= strext
->WorkBuffer
;
474 /* The edit hook gets *copy* of the current buffer contents */
475 strcpy(sgw
.WorkBuffer
, strinfo
->Buffer
);
477 sgw
.Modes
= strext
->InitialModes
;
480 switch (ievent
->ie_Class
)
482 case IECLASS_RAWMOUSE
:
483 if (ievent
->ie_Code
== SELECTDOWN
)
486 sgw
.Actions
= SGA_USE
| SGA_REDISPLAY
;
487 D(bug("HandleStrInput: RAWMOUSE event\n"));
495 D(bug("HandleStrInput: RAWKEY event\n"));
496 if (ievent
->ie_Code
& IECODE_UP_PREFIX
)
498 D(bug("HandleStrInput: filter UP event\n"));
503 sgw
.Actions
= SGA_USE
;
504 if (1 == MapRawKey(sgw
.IEvent
, &buf
, 1, strinfo
->AltKeyMap
))
506 D(bug("HandleStrInput: sgw.Code 0x%lx\n",buf
));
507 sgw
.Code
= (UWORD
)buf
;
516 ReturnInt("HandleStrInput", ULONG
, 0UL);
518 /* Call the global editing hook */
520 D(bug("calling global hook, Buffer=%s, WorkBuffer=%s\n",
521 strinfo
->Buffer
, sgw
.WorkBuffer
));
522 CallHookPkt(GetPrivIBase(IntuitionBase
)->GlobalEditHook
, &sgw
, &command
);
524 /* If there is a local edit hook, run it */
527 if (strext
->EditHook
)
529 D(bug("calling local edit hook\n"));
530 CallHookPkt(strext
->EditHook
, &sgw
, &command
);
534 /* Copy possibly changed stuff into stringgad */
535 if (sgw
.Actions
& SGA_USE
)
539 if (strext
->WorkBuffer
)
540 strcpy(strinfo
->Buffer
, strext
->WorkBuffer
);
543 strinfo
->BufferPos
= sgw
.BufferPos
;
544 strinfo
->NumChars
= sgw
.NumChars
;
545 strinfo
->LongInt
= sgw
.LongInt
;
548 if (gad
->Activation
& GACT_LONGINT
)
550 kprintf("strinfo->LongInt = %d\n",strinfo
->LongInt
);
555 kprintf("strinfo->Buffer = \"%s\"\n",strinfo
->Buffer
);
561 if (sgw
.Actions
& SGA_BEEP
)
563 D(bug("SGA_BEEP not yet implemented. (lack of DisplayBeep())\n"));
566 if (sgw
.Actions
& (SGA_END
| SGA_NEXTACTIVE
| SGA_PREVACTIVE
))
568 gad
->Flags
&= ~GFLG_SELECTED
;
569 *imsgcode
= sgw
.Code
;
570 D(bug("HandleStrInput: SGA_END\n"));
573 if (sgw
.Actions
& SGA_REDISPLAY
)
575 D(bug("HandleStrInput: SGA_REDISPLAY\n"));
576 /* Hack for making strgclass work */
577 if ((gad
->GadgetType
& GTYP_GTYPEMASK
) == GTYP_CUSTOMGADGET
)
580 D(bug("HandleStrInput: Rerendering boopsi gadget\n"));
582 if ((rp
= ObtainGIRPort(ginfo
)) != NULL
)
584 struct gpRender method
;
586 method
.MethodID
= GM_RENDER
;
587 method
.gpr_GInfo
= ginfo
;
588 method
.gpr_RPort
= rp
;
589 method
.gpr_Redraw
= GREDRAW_UPDATE
;
591 Custom_DoMethodA(IntuitionBase
, gad
, (Msg
)&method
);
595 } /* if gadget is a strgclass object */
598 D(bug("HandleStrInput: Rerendering intuition gadget\n"));
599 RefreshStrGadget(gad
, ginfo
->gi_Window
, ginfo
->gi_Requester
, IntuitionBase
);
603 ReturnInt("HandleStrInput", ULONG
, sgw
.Actions
);
606 /*****************************************************************************************/
608 STATIC ULONG
DoSGHClick(struct SGWork
*sgw
, struct IntuitionBase
*IntuitionBase
)
611 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
613 struct StringInfo
*strinfo
;
616 struct TextFont
*oldfont
;
618 struct Window
*window
;
619 struct Requester
*req
;
621 UWORD text_left
, text_right
;
624 window
= sgw
->GadgetInfo
->gi_Window
;
625 req
= sgw
->GadgetInfo
->gi_Requester
;
627 GetGadgetDomain(sgw
->Gadget
, window
->WScreen
, window
, NULL
, (struct IBox
*)&bbox
);
628 mousex
= window
->MouseX
- bbox
.Left
;
630 EnterFunc(bug("DoSGHClick(sgw=%p)\n", sgw
));
632 D(bug("Gadget text: %s\n", sgw
->WorkBuffer
));
634 rp
= sgw
->GadgetInfo
->gi_RastPort
;
637 strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
639 CalcBBox(window
, req
, gad
, &bbox
);
642 struct DrawInfo
*dri
;
644 dri
= GetScreenDrawInfo(window
->WScreen
);
645 SetFont(rp
, dri
->dri_Font
);
646 FreeScreenDrawInfo(window
->WScreen
, dri
);
649 if (gad
->Flags
& GFLG_STRINGEXTEND
)
651 struct StringExtend
*strext
= strinfo
->Extension
;
655 SetFont(rp
, strext
->Font
);
659 /* If we are made active, save contents to undobuffer (if any exists) */
660 if (!(gad
->Flags
& GFLG_SELECTED
))
663 if (strinfo
->UndoBuffer
)
665 D(bug("sghclick: saving into undo buffer\n"));
666 strcpy(strinfo
->UndoBuffer
, strinfo
->Buffer
);
668 gad
->Flags
|= GFLG_SELECTED
;
671 /* Get left & righ offsets of strgad text */
672 text_left
= GetTextLeft (gad
, &bbox
, rp
, IntuitionBase
);
673 text_right
= GetTextRight(gad
, &bbox
, rp
, IntuitionBase
);
675 D(bug("sghclick: text_left=%d, text_right=%d\n", text_left
, text_right
));
676 D(bug("sghclick: disppos=%d, dispcount=%d, cursor=%d\n",
677 strinfo
->DispPos
, strinfo
->DispCount
, sgw
->BufferPos
));
678 D(bug("Gadget text: %s\n", sgw
->WorkBuffer
));
680 /* Check if mouseclick is inside displayed text */
681 if ((mousex
>= text_left
) && (mousex
<= text_right
))
683 /* Find new cursor pos. Uses TextFit() to handle proportional fonts. */
685 struct TextExtent te
;
686 STRPTR dispstr
= strinfo
->Buffer
+ strinfo
->DispPos
;
688 sgw
->BufferPos
= strinfo
->DispPos
689 + TextFit(rp
, dispstr
, sgw
->NumChars
- strinfo
->DispPos
,
691 mousex
- text_left
, rp
->Font
->tf_YSize
);
692 D(bug("sghclick: click inside text.\n"));
694 else /* Click not inside text */
696 if (mousex
< text_left
)
698 /* Click on empty space at left. Set cursor to first visible */
699 sgw
->BufferPos
= strinfo
->DispPos
;
700 D(bug("sghclick: click left of text.\n"));
704 /* Click on empty space at right. Set cursor to last visible */
705 sgw
->BufferPos
= strinfo
->DispPos
+ strinfo
->DispCount
;
706 D(bug("sghclick: click right of text.\n"));
709 } /* if (click is on text or not) */
711 D(bug("sghclick: new cursor position: %d\n", sgw
->BufferPos
));
713 sgw
->Actions
= (SGA_USE
|SGA_REDISPLAY
);
714 sgw
->EditOp
= EO_MOVECURSOR
;
716 SetFont(rp
, oldfont
);
718 D(bug("Gadget text: %s\n", sgw
->WorkBuffer
));
720 ReturnInt ("DoSGHClick", ULONG
, 1);
723 /*****************************************************************************************/
725 VOID
MoveCharsLeft(STRPTR str
, UWORD first
, UWORD last
, UWORD steps
)
729 for (i
= first
; i
<= last
; i
++)
731 str
[i
- steps
] = str
[i
];
736 /*****************************************************************************************/
738 STATIC ULONG
DoSGHKey(struct SGWork
*sgw
, struct IntuitionBase
*IntuitionBase
)
741 struct Library
*UtilityBase
= GetPrivIBase(IntuitionBase
)->UtilityBase
;
743 struct StringInfo
*strinfo
;
747 EnterFunc(bug("DoSGHKey(sgw=%p)\n", sgw
));
750 strinfo
= sgw
->StringInfo
;
752 qual
= sgw
->IEvent
->ie_Qualifier
;
754 D(bug("sghkey: RawKey 0x%lx, sgw_Code 0x%lx\n",sgw
->IEvent
->ie_Code
,sgw
->Code
));
756 sgw
->EditOp
= EO_NOOP
;
758 D(bug("sghkey: qual 0x%lx ic_Flags 0x%lx Modes 0x%lx\n",
760 GetPrivIBase(IntuitionBase
)->IControlPrefs
.ic_Flags
,
767 letter
= sgw
->IEvent
->ie_Code
;
769 if ((letter
== CURSORLEFT
) && (!(qual
& SHIFT
)))
771 D(bug("sghkey: CURSOR_LEFT\n"));
772 if (sgw
->BufferPos
> 0)
774 sgw
->EditOp
= EO_MOVECURSOR
;
778 else if ((letter
== CURSORRIGHT
) && (!(qual
& SHIFT
)))
781 D(bug("sghkey: CURSOR_RIGHT\n"));
782 if (sgw
->BufferPos
< sgw
->NumChars
)
784 sgw
->EditOp
= EO_MOVECURSOR
;
789 else if ( ((letter
== CURSORLEFT
) && (qual
& SHIFT
)) ||
790 (letter
== HOMERAW
) )
792 if (sgw
->BufferPos
> 0)
795 sgw
->EditOp
= EO_MOVECURSOR
;
798 else if ( ((letter
== CURSORRIGHT
) && (qual
& SHIFT
)) ||
801 if (sgw
->BufferPos
< sgw
->NumChars
)
803 sgw
->BufferPos
= sgw
->NumChars
;
804 sgw
->EditOp
= EO_MOVECURSOR
;
807 else if ((letter
== TABRAW
) && (qual
& SHIFT
))
809 D(bug("sghkey: SHIFT TAB\n"));
810 sgw
->EditOp
= EO_SPECIAL
; /* FIXME: ??? is this correct ??? */
812 sgw
->Actions
= (SGA_USE
|SGA_PREVACTIVE
);
814 else if (letter
== HELPRAW
)
818 else if (qual
& IEQUALIFIER_RCOMMAND
)
820 /* ANSI key but pressed together with right Amiga key */
822 sgw
->EditOp
= EO_SPECIAL
; /* FIXME: ??? is this correct ??? */
823 sgw
->Actions
= (SGA_USE
|SGA_REUSE
|SGA_END
);
825 letter
= ToUpper(sgw
->Code
);
827 /* stegerg: URGENTCHECMKE. Why disabled for AROS? */
829 /* FIXME: we need to handle RAMIGA-Q,RAMIGA-X here */
833 sgw
->EditOp
= EO_RESET
;
835 if (strinfo
->UndoBuffer
)
837 D(bug("sghclick: saving into undo buffer\n"));
838 stccpy(strinfo
->UndoBuffer
, sgw
->WorkBuffer
,strinfo
->MaxChars
);
839 sgw
->BufferPos
= strinfo
->UndoPos
;
840 sgw
->NumChars
= strlen(sgw
->WorkBuffer
);
846 /* RCmd-X clears the input buffer. In fixed field mode
847 * jump cursor to the start of the buffer
849 D(bug("sghkey: CTRL-X\n"));
851 if (sgw
->Modes
& SGM_FIXEDFIELD
)
853 D(bug("sghkey: SGM_FIXEDFIELD\n"));
855 sgw
->EditOp
= EO_MOVECURSOR
;
860 sgw
->WorkBuffer
[sgw
->BufferPos
] = '\0';
861 sgw
->NumChars
= sgw
->BufferPos
;
862 sgw
->EditOp
= EO_CLEAR
;
873 if ((qual
& IEQUALIFIER_CONTROL
) &&
874 (GetPrivIBase(IntuitionBase
)->IControlPrefs
.ic_Flags
& ICF_STRGAD_FILTER
) &&
875 !(sgw
->Modes
& SGM_NOFILTER
))
877 /* ANSI key but pressed together with the control key */
879 D(bug("sghkey: CTRL pressed..filtering on\n"));
881 if (letter
== CTRL_A
)
883 /* CTRL-A jump cursor to start of buffer */
884 D(bug("sghkey: CTRL-A\n"));
886 sgw
->EditOp
= EO_MOVECURSOR
;
889 if (letter
== CTRL_B
)
891 /* CTRL-B move the cursor back one char */
892 D(bug("sghkey: CTRL-B\n"));
893 if (sgw
->BufferPos
> 0)
896 sgw
->EditOp
= EO_MOVECURSOR
;
900 if (letter
== CTRL_D
)
902 /* CTRL-D delete current char */
903 D(bug("sghkey: CTRL-D\n"));
904 if (sgw
->BufferPos
!= sgw
->NumChars
)
906 MoveCharsLeft(sgw
->WorkBuffer
, sgw
->BufferPos
+ 1, sgw
->NumChars
- 1, 1);
908 sgw
->EditOp
= EO_DELFORWARD
;
912 if (letter
== CTRL_E
)
914 /* CTRL-E move the cursor to the end of the line */
915 D(bug("sghkey: CTRL-E\n"));
916 if (sgw
->BufferPos
!= sgw
->NumChars
)
918 sgw
->BufferPos
= sgw
->NumChars
;
919 sgw
->EditOp
= EO_MOVECURSOR
;
923 if (letter
== CTRL_F
)
925 /* CTRL-F move the cursor forward one char */
926 D(bug("sghkey: CTRL-F\n"));
927 if (sgw
->BufferPos
!= sgw
->NumChars
)
930 sgw
->EditOp
= EO_MOVECURSOR
;
934 if (letter
== CTRL_H
)
936 /* CTRL-H Delete the character to the left of the cursor
937 * In fixed field mode, move cursor to previous character
939 D(bug("sghkey: CTRL-A\n"));
940 if (sgw
->Modes
& SGM_FIXEDFIELD
)
942 D(bug("sghkey: SGM_FIXEDFIELD\n"));
943 if (sgw
->BufferPos
> 0)
946 sgw
->EditOp
= EO_MOVECURSOR
;
951 if (sgw
->BufferPos
> 0)
954 len
= sgw
->NumChars
- sgw
->BufferPos
;
955 memcpy(&sgw
->WorkBuffer
[sgw
->BufferPos
-1],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
958 sgw
->WorkBuffer
[sgw
->BufferPos
+ len
] = 0;
960 sgw
->EditOp
= EO_DELBACKWARD
;
965 if (letter
== CTRL_K
)
967 /* CTRL-K Delete from the character under the cursor to the end
970 D(bug("sghkey: CTRL-K\n"));
971 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
972 sgw
->NumChars
= sgw
->BufferPos
;
973 sgw
->EditOp
= EO_DELFORWARD
;
976 if (letter
== CTRL_M
)
978 /* CTRL-M Equivalent to Return or Enter
980 D(bug("sghkey: CTRL-M\n"));
981 sgw
->EditOp
= EO_ENTER
;
983 sgw
->Actions
= (SGA_USE
|SGA_END
);
986 if (letter
== CTRL_W
)
988 /* CTRL-W Delete the previous word. In fixed field mode, jump
989 * cursor to the start of the previous word
991 D(bug("sghkey: CTRL-W\n"));
992 if (sgw
->Modes
& SGM_FIXEDFIELD
)
994 D(bug("sghkey: SGM_FIXEDFIELD\n"));
998 if (sgw
->BufferPos
> 0)
1005 for (pos
=sgw
->BufferPos
-1;pos
>= 0;pos
--)
1007 if (sgw
->WorkBuffer
[pos
] == ' ')
1012 len
= sgw
->NumChars
- sgw
->BufferPos
;
1013 memcpy(&sgw
->WorkBuffer
[pos
],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
1015 sgw
->NumChars
-= sgw
->BufferPos
- pos
;
1016 sgw
->BufferPos
= pos
;
1017 sgw
->WorkBuffer
[sgw
->BufferPos
+ len
] = 0;
1018 sgw
->EditOp
= EO_DELBACKWARD
;
1023 if (letter
== CTRL_U
)
1025 /* CTRL-U Delete from the character to the left of the cursor
1026 * to the start of the buffer. In fixed field mode, jump cursor to the start
1029 D(bug("sghkey: CTRL-U\n"));
1030 if (sgw
->Modes
& SGM_FIXEDFIELD
)
1032 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1034 sgw
->EditOp
= EO_MOVECURSOR
;
1038 if (sgw
->BufferPos
> 0)
1041 len
= sgw
->NumChars
- sgw
->BufferPos
;
1042 memcpy(&sgw
->WorkBuffer
[0],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
1045 sgw
->WorkBuffer
[len
] = 0;
1046 sgw
->NumChars
= len
;
1047 sgw
->EditOp
= EO_DELBACKWARD
;
1052 if (letter
== CTRL_X
)
1054 /* CTRL-X clears the input buffer (like right amiga-x). In fixed field mode
1055 * jump cursor to the start of the buffer
1057 D(bug("sghkey: CTRL-X\n"));
1058 if (sgw
->Modes
& SGM_FIXEDFIELD
)
1060 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1062 sgw
->EditOp
= EO_MOVECURSOR
;
1067 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
1068 sgw
->NumChars
= sgw
->BufferPos
;
1069 sgw
->EditOp
= EO_CLEAR
;
1073 if (letter
== CTRL_Z
)
1075 /* CTRL-Z Jump cursor to the end of the buffer
1077 D(bug("sghkey: CTRL-Z\n"));
1078 sgw
->BufferPos
= sgw
->NumChars
;
1079 sgw
->EditOp
= EO_MOVECURSOR
;
1083 if (letter
== BACKSPACE
)
1085 if (sgw
->BufferPos
!= 0)
1087 UWORD first
= sgw
->BufferPos
;
1088 UWORD last
= sgw
->NumChars
- 1;
1092 steps
= sgw
->BufferPos
;
1095 sgw
->NumChars
-= steps
;
1103 MoveCharsLeft(sgw
->WorkBuffer
, first
, last
, steps
);
1104 sgw
->EditOp
= EO_DELBACKWARD
;
1107 else if (letter
== DELETE
)
1109 /* Check whether cursor is at the trailing 0 */
1110 if (sgw
->BufferPos
!= sgw
->NumChars
)
1114 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
1115 sgw
->NumChars
= sgw
->BufferPos
;
1119 MoveCharsLeft(sgw
->WorkBuffer
, sgw
->BufferPos
+ 1, sgw
->NumChars
- 1, 1);
1122 sgw
->EditOp
= EO_DELFORWARD
;
1125 else if (letter
== RETURN
)
1127 D(bug("sghkey: ENTER\n"));
1128 sgw
->EditOp
= EO_ENTER
;
1130 sgw
->Actions
= (SGA_USE
|SGA_END
);
1132 else if (letter
== TAB
)
1134 D(bug("sghkey: TAB\n"));
1135 sgw
->EditOp
= EO_SPECIAL
; /* FIXME: ??? is this correct ??? */
1136 sgw
->Actions
= (SGA_USE
|SGA_NEXTACTIVE
);
1141 /* Validity check of letter */
1142 if (gad
->Activation
& GACT_LONGINT
)
1146 if ((sgw
->BufferPos
!= 0) || ((sgw
->NumChars
> 0) && (sgw
->WorkBuffer
[0] == '-')))
1147 sgw
->EditOp
= EO_BADFORMAT
;
1150 else if ((letter
< 0x30) || (letter
> 0x39))
1152 sgw
->EditOp
= EO_BADFORMAT
;
1154 else if (sgw
->WorkBuffer
[sgw
->BufferPos
] == '-')
1156 sgw
->EditOp
= EO_BADFORMAT
;
1159 else /* Integer gadget ? */
1161 /* Is key a printable character ? */
1162 /* FIXME: Locale should be used here... */
1163 if ((letter
& 0x60) == 0)
1165 sgw
->EditOp
= EO_BADFORMAT
;
1167 } /* if (integer or string gadget) */
1169 if (sgw
->EditOp
!= EO_BADFORMAT
)
1172 if ((sgw
->Modes
& SGM_REPLACE
) && (sgw
->WorkBuffer
[sgw
->BufferPos
]))
1174 D(bug("sghkey: replacing char at pos %d\n", sgw
->BufferPos
));
1176 sgw
->WorkBuffer
[sgw
->BufferPos
] = letter
;
1177 sgw
->EditOp
= EO_REPLACECHAR
;
1179 if (sgw
->BufferPos
< strinfo
->MaxChars
- 1)
1185 /* Insert mode. Check if there is space for one more character
1186 ** NOTE: MaxChars inludes traing \0, so therefore the '- 1'
1188 if (sgw
->NumChars
< (strinfo
->MaxChars
- 1))
1192 D(bug("sghkey: inserting char at pos %d\n", sgw
->BufferPos
));
1193 /* Move characters to the right of insertion point one step to the right */
1194 for (i
= sgw
->NumChars
; i
> sgw
->BufferPos
; i
--)
1196 sgw
->WorkBuffer
[i
] = sgw
->WorkBuffer
[i
- 1];
1200 sgw
->WorkBuffer
[i
] = letter
;
1201 sgw
->EditOp
= EO_INSERTCHAR
;
1208 sgw
->EditOp
= EO_NOOP
;
1209 } /* if (enough space for ione mor letter) */
1210 } /* if (Replace or Insert mode) */
1211 } /* If (user pressed valid letter) */
1212 } /* Vanilla key but not backspace, delete, ... */
1213 } /* if (key or scancode) */
1215 /* Null-terminate the new string */
1216 sgw
->WorkBuffer
[sgw
->NumChars
] = 0;
1218 if (sgw
->EditOp
!= EO_NOOP
)
1219 sgw
->Actions
|= (SGA_USE
|SGA_REDISPLAY
);
1221 /* Integer gadget ? */
1222 if ((sgw
->Actions
& SGA_USE
) && (gad
->Activation
& GACT_LONGINT
))
1224 sgw
->LongInt
= atol(sgw
->WorkBuffer
);
1225 D(bug("Updated string number to %d\n", sgw
->LongInt
));
1228 ReturnInt ("DoSGHKey", ULONG
, 1);
1231 /*****************************************************************************************/
1233 AROS_UFH3(ULONG
, GlobalEditFunc
,
1234 AROS_UFHA(struct Hook
*, hook
, A0
),
1235 AROS_UFHA(struct SGWork
*, sgw
, A2
),
1236 AROS_UFHA(ULONG
*, command
, A1
)
1246 retcode
= DoSGHClick(sgw
, (struct IntuitionBase
*)hook
->h_Data
);
1250 retcode
= DoSGHKey (sgw
, (struct IntuitionBase
*)hook
->h_Data
);
1259 /*****************************************************************************************/
1261 VOID
RefreshStrGadget(struct Gadget
*gad
,
1263 struct Requester
*req
,
1264 struct IntuitionBase
*IntuitionBase
)
1266 struct GadgetInfo gi
;
1267 struct RastPort
*rp
;
1269 EnterFunc(bug("RefreshStrGadget(gad=%p, win=%s)\n", gad
, win
->Title
));
1271 SetupGInfo(&gi
, win
, req
, gad
, IntuitionBase
);
1273 if ((rp
= ObtainGIRPort(&gi
)))
1275 if (gad
->GadgetRender
)
1277 if (gad
->Flags
& GFLG_GADGIMAGE
)
1280 (struct Image
*)gad
->GadgetRender
,
1287 (struct Border
*)gad
->GadgetRender
,
1291 /* The gadget can have a linked list of IntuiTexts attached. */
1294 struct IBox container
;
1295 GetGadgetIBox(gad
, &gi
, &container
);
1296 int_PrintIText(rp
, gad
->GadgetText
,
1298 container
.Top
, FALSE
, IntuitionBase
);
1303 UpdateStrGadget(gad
, win
, req
, IntuitionBase
);
1305 ReturnVoid("RefreshStrGadget");
1308 /*****************************************************************************************/
1310 VOID
UpdateStringInfo(struct Gadget
*gad
)
1312 /* Updates the stringinfo in case user has set some fields */
1314 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
1316 EnterFunc(bug("UpdateStringInfo(gad=%p)\n", gad
));
1319 if (gad
->Activation
& GACT_LONGINT
)
1321 if ((strinfo
->NumChars
!= 0) || (strinfo
->LongInt
!= 0))
1323 /* NOTE: The max number of chars written INCLUDES trailing \0 */
1324 snprintf(strinfo
->Buffer
, strinfo
->MaxChars
, "%d", strinfo
->LongInt
);
1329 strinfo
->NumChars
= strlen(strinfo
->Buffer
);
1331 if (strinfo
->BufferPos
> strinfo
->NumChars
)
1333 strinfo
->BufferPos
= strinfo
->NumChars
;
1336 D(bug("%s gadget contains buffer %s of length %d\n",
1337 (gad
->Activation
& GACT_LONGINT
) ? "Integer" : "String",
1338 strinfo
->Buffer
, strinfo
->NumChars
));
1340 ReturnVoid("UpdateStringInfo");
1343 /*****************************************************************************************/
1345 VOID
UpdateStrGadget(struct Gadget
*gad
,
1347 struct Requester
*req
,
1348 struct IntuitionBase
*IntuitionBase
)
1350 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
1351 struct GadgetInfo gi
;
1353 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
1356 struct RastPort
*rp
;
1358 UWORD pens
[NUMPENS
];
1360 EnterFunc(bug("UpdateStrGadget(current text=%s)\n", strinfo
->Buffer
));
1362 SetupGInfo(&gi
, win
, req
, gad
, IntuitionBase
);
1364 rp
= ObtainGIRPort(&gi
);
1367 GetPensAndFont(gad
, pens
, win
, rp
, IntuitionBase
);
1369 CalcBBox(win
, req
, gad
, &bbox
);
1371 /* Update the stringinfo struct in case of user change */
1372 UpdateStringInfo(gad
);
1374 /* Update the DispPos and DispCount fields so that the gadget renders properly */
1375 UpdateDisp(gad
, &bbox
, rp
, IntuitionBase
);
1378 dispstr
= strinfo
->Buffer
+ strinfo
->DispPos
;
1380 /* Clear the background */
1381 SetAPen(rp
, pens
[STRBACKPEN
]);
1387 bbox
.Left
+ bbox
.Width
- 1,
1388 bbox
.Top
+ bbox
.Height
- 1);
1390 text_left
= GetTextLeft(gad
, &bbox
, rp
, IntuitionBase
);
1393 /* Write the text into the gadget */
1394 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[STRBACKPEN
], JAM2
);
1397 + ((bbox
.Height
- rp
->Font
->tf_YSize
) >> 1)
1398 + rp
->Font
->tf_Baseline
;
1400 Move(rp
, text_left
, text_top
);
1402 D(bug("usg: Writing text %s of length %d at (%d, %d)\n",
1403 dispstr
, strinfo
->DispCount
, text_left
, text_top
));
1405 Text(rp
, dispstr
, strinfo
->DispCount
);
1407 if (gad
->Flags
& GFLG_SELECTED
)
1409 UWORD cursoroffset
= strinfo
->BufferPos
- strinfo
->DispPos
;
1411 // SetAfPt(rp,NULL,0);
1412 D(bug("usg: Number of characters: %d\n", strinfo
->NumChars
));
1415 text_left
+= TextLength(rp
, dispstr
, cursoroffset
);
1418 if (strinfo
->BufferPos
< strinfo
->NumChars
)
1420 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[CURSORPEN
], JAM2
);
1421 Move(rp
, text_left
, text_top
);
1423 dispstr
+ cursoroffset
,
1428 struct TextExtent te
;
1430 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[CURSORPEN
], JAM2
|INVERSVID
);
1431 TextExtent(rp
, cursorkey
, CURSORKEYLEN
,&te
);
1434 text_left
+te
.te_Extent
.MinX
,
1435 text_top
+te
.te_Extent
.MinY
,
1436 text_left
+te
.te_Extent
.MaxX
,
1437 text_top
+te
.te_Extent
.MaxY
);
1440 Move(rp
, text_left
, text_top
);
1442 ((strinfo
->BufferPos
< strinfo
->NumChars
)
1443 ? dispstr
+ cursoroffset
1448 } /* if (gadget selected => render cursor) */
1450 if (gad
->Flags
& GFLG_DISABLED
)
1452 struct DrawInfo
*dri
= GetScreenDrawInfo(win
->WScreen
);
1454 RenderDisabledPattern(rp
, dri
, bbox
.Left
,
1456 bbox
.Left
+ bbox
.Width
- 1,
1457 bbox
.Top
+ bbox
.Height
- 1,
1460 if (dri
) FreeScreenDrawInfo(win
->WScreen
, dri
);
1465 ReturnVoid("UpdateStrGadget");