2 Copyright © 1995-2011, 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
);
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
;
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];
380 pens
[STRTEXTPEN
] = strext
->Pens
[0];
381 pens
[STRBACKPEN
] = strext
->Pens
[1];
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
);
399 SetFont(rp
,GfxBase
->DefaultFont
);
403 if ((gad
->Flags
& GFLG_SELECTED
) == GFLG_SELECTED
)
405 pens
[STRTEXTPEN
] = dri
->dri_Pens
[TEXTPEN
];
406 pens
[STRBACKPEN
] = dri
->dri_Pens
[BACKGROUNDPEN
];
412 pens
[STRTEXTPEN
] = dri
->dri_Pens
[TEXTPEN
];
413 pens
[STRBACKPEN
] = dri
->dri_Pens
[BACKGROUNDPEN
];
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
;
431 pens
[STRTEXTPEN
] = 1;
432 pens
[STRBACKPEN
] = 0;
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
);
447 /*****************************************************************************************/
449 ULONG
HandleStrInput( struct Gadget
*gad
,
450 struct GadgetInfo
*ginfo
,
451 struct InputEvent
*ievent
,
453 struct IntuitionBase
*IntuitionBase
)
455 struct Library
*UtilityBase
= GetPrivIBase(IntuitionBase
)->UtilityBase
;
456 struct Library
*KeymapBase
= GetPrivIBase(IntuitionBase
)->KeymapBase
;
458 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
459 struct StringExtend
*strext
= NULL
;
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
));
470 ReturnInt("HandleStrInput", ULONG
, 0UL);
472 UpdateStringInfo(gad
);
474 /* Initialize SGWork */
476 sgw
.StringInfo
= strinfo
;
477 sgw
.WorkBuffer
= strinfo
->Buffer
; /* default */
478 sgw
.PrevBuffer
= strinfo
->Buffer
;
482 sgw
.BufferPos
= strinfo
->BufferPos
;
483 sgw
.NumChars
= strinfo
->NumChars
;
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
)
508 sgw
.Actions
= SGA_USE
| SGA_REDISPLAY
;
509 D(bug("HandleStrInput: RAWMOUSE event\n"));
517 D(bug("HandleStrInput: RAWKEY event\n"));
518 if (ievent
->ie_Code
& IECODE_UP_PREFIX
)
520 D(bug("HandleStrInput: filter UP event\n"));
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
;
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 */
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
)
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
;
570 if (gad
->Activation
& GACT_LONGINT
)
572 kprintf("strinfo->LongInt = %d\n",strinfo
->LongInt
);
577 kprintf("strinfo->Buffer = \"%s\"\n",strinfo
->Buffer
);
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
)
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
);
617 } /* if gadget is a strgclass object */
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
;
635 struct StringInfo
*strinfo
;
638 struct TextFont
*oldfont
;
640 struct Window
*window
;
641 struct Requester
*req
;
643 UWORD text_left
, text_right
;
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
;
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
;
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
,
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"));
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
)
751 for (i
= first
; i
<= last
; i
++)
753 str
[i
- steps
] = str
[i
];
758 /*****************************************************************************************/
760 STATIC ULONG
DoSGHKey(struct SGWork
*sgw
, struct IntuitionBase
*IntuitionBase
)
763 struct Library
*UtilityBase
= GetPrivIBase(IntuitionBase
)->UtilityBase
;
765 struct StringInfo
*strinfo
;
769 EnterFunc(bug("DoSGHKey(sgw=%p)\n", sgw
));
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",
782 GetPrivIBase(IntuitionBase
)->IControlPrefs
.ic_Flags
,
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
;
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
;
811 else if ( ((letter
== CURSORLEFT
) && (qual
& SHIFT
)) ||
812 (letter
== HOMERAW
) )
814 if (sgw
->BufferPos
> 0)
817 sgw
->EditOp
= EO_MOVECURSOR
;
820 else if ( ((letter
== CURSORRIGHT
) && (qual
& SHIFT
)) ||
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 ??? */
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 */
844 sgw
->EditOp
= EO_SPECIAL
; /* FIXME: ??? is this correct ??? */
845 sgw
->Actions
= (SGA_USE
|SGA_REUSE
|SGA_END
);
847 letter
= ToUpper(sgw
->Code
);
849 /* stegerg: URGENTCHECMKE. Why disabled for AROS? */
851 /* FIXME: we need to handle RAMIGA-Q,RAMIGA-X here */
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
);
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"));
877 sgw
->EditOp
= EO_MOVECURSOR
;
882 sgw
->WorkBuffer
[sgw
->BufferPos
] = '\0';
883 sgw
->NumChars
= sgw
->BufferPos
;
884 sgw
->EditOp
= EO_CLEAR
;
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"));
908 sgw
->EditOp
= EO_MOVECURSOR
;
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)
918 sgw
->EditOp
= EO_MOVECURSOR
;
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);
930 sgw
->EditOp
= EO_DELFORWARD
;
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
;
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
)
952 sgw
->EditOp
= EO_MOVECURSOR
;
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)
968 sgw
->EditOp
= EO_MOVECURSOR
;
973 if (sgw
->BufferPos
> 0)
976 len
= sgw
->NumChars
- sgw
->BufferPos
;
977 memcpy(&sgw
->WorkBuffer
[sgw
->BufferPos
-1],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
980 sgw
->WorkBuffer
[sgw
->BufferPos
+ len
] = 0;
982 sgw
->EditOp
= EO_DELBACKWARD
;
987 if (letter
== CTRL_K
)
989 /* CTRL-K Delete from the character under the cursor to the end
992 D(bug("sghkey: CTRL-K\n"));
993 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
994 sgw
->NumChars
= sgw
->BufferPos
;
995 sgw
->EditOp
= EO_DELFORWARD
;
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
;
1005 sgw
->Actions
= (SGA_USE
|SGA_END
);
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"));
1020 if (sgw
->BufferPos
> 0)
1027 for (pos
=sgw
->BufferPos
-1;pos
>= 0;pos
--)
1029 if (sgw
->WorkBuffer
[pos
] == ' ')
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
;
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
1051 D(bug("sghkey: CTRL-U\n"));
1052 if (sgw
->Modes
& SGM_FIXEDFIELD
)
1054 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1056 sgw
->EditOp
= EO_MOVECURSOR
;
1060 if (sgw
->BufferPos
> 0)
1063 len
= sgw
->NumChars
- sgw
->BufferPos
;
1064 memcpy(&sgw
->WorkBuffer
[0],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
1067 sgw
->WorkBuffer
[len
] = 0;
1068 sgw
->NumChars
= len
;
1069 sgw
->EditOp
= EO_DELBACKWARD
;
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"));
1084 sgw
->EditOp
= EO_MOVECURSOR
;
1089 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
1090 sgw
->NumChars
= sgw
->BufferPos
;
1091 sgw
->EditOp
= EO_CLEAR
;
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
;
1105 if (letter
== BACKSPACE
)
1107 if (sgw
->BufferPos
!= 0)
1109 UWORD first
= sgw
->BufferPos
;
1110 UWORD last
= sgw
->NumChars
- 1;
1114 steps
= sgw
->BufferPos
;
1117 sgw
->NumChars
-= steps
;
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
)
1136 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
1137 sgw
->NumChars
= sgw
->BufferPos
;
1141 MoveCharsLeft(sgw
->WorkBuffer
, sgw
->BufferPos
+ 1, sgw
->NumChars
- 1, 1);
1144 sgw
->EditOp
= EO_DELFORWARD
;
1147 else if (letter
== RETURN
)
1149 D(bug("sghkey: ENTER\n"));
1150 sgw
->EditOp
= EO_ENTER
;
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
);
1163 /* Validity check of letter */
1164 if (gad
->Activation
& GACT_LONGINT
)
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)
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))
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];
1222 sgw
->WorkBuffer
[i
] = letter
;
1223 sgw
->EditOp
= EO_INSERTCHAR
;
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
)
1268 retcode
= DoSGHClick(sgw
, (struct IntuitionBase
*)hook
->h_Data
);
1272 retcode
= DoSGHKey (sgw
, (struct IntuitionBase
*)hook
->h_Data
);
1281 /*****************************************************************************************/
1283 VOID
RefreshStrGadget(struct Gadget
*gad
,
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
)
1302 (struct Image
*)gad
->GadgetRender
,
1309 (struct Border
*)gad
->GadgetRender
,
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
));
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
);
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
,
1360 struct Requester
*req
,
1361 struct IntuitionBase
*IntuitionBase
)
1363 struct GfxBase
*GfxBase
= GetPrivIBase(IntuitionBase
)->GfxBase
;
1364 struct GadgetInfo gi
;
1366 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
1369 struct RastPort
*rp
;
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
);
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
]);
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
);
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
;
1424 // SetAfPt(rp,NULL,0);
1425 D(bug("usg: Number of characters: %d\n", strinfo
->NumChars
));
1428 text_left
+= TextLength(rp
, dispstr
, cursoroffset
);
1431 if (strinfo
->BufferPos
< strinfo
->NumChars
)
1433 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[CURSORPEN
], JAM2
);
1434 Move(rp
, text_left
, text_top
);
1436 dispstr
+ cursoroffset
,
1441 struct TextExtent te
;
1443 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[CURSORPEN
], JAM2
|INVERSVID
);
1444 TextExtent(rp
, cursorkey
, CURSORKEYLEN
,&te
);
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
);
1453 Move(rp
, text_left
, text_top
);
1455 ((strinfo
->BufferPos
< strinfo
->NumChars
)
1456 ? dispstr
+ cursoroffset
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
,
1469 bbox
.Left
+ bbox
.Width
- 1,
1470 bbox
.Top
+ bbox
.Height
- 1,
1473 if (dri
) FreeScreenDrawInfo(win
->WScreen
, dri
);
1478 ReturnVoid("UpdateStrGadget");