2 Copyright © 1995-2003, 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 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
;
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;
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,
136 &(strinfo
->Buffer
[numchars
- 1]),
138 -1, bbox
->Width
, rp
->Font
->tf_YSize
);
141 max_disppos
= numchars
- numfit
;
143 /* if ((max_disppos > 0) && (!cursor_at_end))
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
,
158 struct IntuitionBase
*IntuitionBase
)
162 struct TextExtent te
;
163 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
166 EnterFunc(bug("UpdateDisp(gad=%p, bbox=%p, rp=%p)\n",
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
)
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) ] */
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
217 &(strinfo
->Buffer
[strinfo
->BufferPos
]),
218 strinfo
->NumChars
, &te
, NULL
, -1,
219 bbox
->Width
, rp
->Font
->tf_YSize
)
222 D(bug("cursor right of visible area, new disppos: %d\n", strinfo
->DispPos
));
224 else /* 3). Cursor inside gadget */
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
,
245 /* 0-terminate string */
246 strinfo
->Buffer
[strinfo
->NumChars
] = 0x00;
247 ReturnVoid("UpdateDisp");
250 /*****************************************************************************************/
252 STATIC UWORD
GetTextLeft(struct Gadget
*gad
,
255 struct IntuitionBase
*IntuitionBase
)
257 /* Gets left position of text in the string gadget */
259 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
261 STRPTR dispstr
= &(strinfo
->Buffer
[strinfo
->DispPos
]);
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?
275 text_left
= bbox
->Left
;
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);
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
);
299 /*****************************************************************************************/
301 STATIC UWORD
GetTextRight(struct Gadget
*gad
,
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
]);
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?
324 text_right
= bbox
->Left
+ TextLength(rp
, dispstr
, dispstrlen
);
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);
336 case GACT_STRINGRIGHT
:
337 text_right
= bbox
->Left
+ bbox
->Width
- 1;
343 /*****************************************************************************************/
345 STATIC VOID
GetPensAndFont(struct Gadget
*gad
,
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
;
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];
375 pens
[STRTEXTPEN
] = strext
->Pens
[0];
376 pens
[STRBACKPEN
] = strext
->Pens
[1];
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
);
394 SetFont(rp
,GfxBase
->DefaultFont
);
398 if ((gad
->Flags
& GFLG_SELECTED
) == GFLG_SELECTED
)
400 pens
[STRTEXTPEN
] = dri
->dri_Pens
[TEXTPEN
];
401 pens
[STRBACKPEN
] = dri
->dri_Pens
[BACKGROUNDPEN
];
407 pens
[STRTEXTPEN
] = dri
->dri_Pens
[TEXTPEN
];
408 pens
[STRBACKPEN
] = dri
->dri_Pens
[BACKGROUNDPEN
];
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
;
426 pens
[STRTEXTPEN
] = 1;
427 pens
[STRBACKPEN
] = 0;
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
);
442 /*****************************************************************************************/
444 ULONG
HandleStrInput( struct Gadget
*gad
,
445 struct GadgetInfo
*ginfo
,
446 struct InputEvent
*ievent
,
448 struct IntuitionBase
*IntuitionBase
)
451 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
452 struct StringExtend
*strext
= NULL
;
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
));
463 ReturnInt("HandleStrInput", ULONG
, 0UL);
465 UpdateStringInfo(gad
);
467 /* Initialize SGWork */
469 sgw
.StringInfo
= strinfo
;
470 sgw
.WorkBuffer
= strinfo
->Buffer
; /* default */
471 sgw
.PrevBuffer
= strinfo
->Buffer
;
475 sgw
.BufferPos
= strinfo
->BufferPos
;
476 sgw
.NumChars
= strinfo
->NumChars
;
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
)
501 sgw
.Actions
= SGA_USE
| SGA_REDISPLAY
;
502 D(bug("HandleStrInput: RAWMOUSE event\n"));
510 D(bug("HandleStrInput: RAWKEY event\n"));
511 if (ievent
->ie_Code
& IECODE_UP_PREFIX
)
513 D(bug("HandleStrInput: filter UP event\n"));
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
;
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 */
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
)
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
;
563 if (gad
->Activation
& GACT_LONGINT
)
565 kprintf("strinfo->LongInt = %d\n",strinfo
->LongInt
);
570 kprintf("strinfo->Buffer = \"%s\"\n",strinfo
->Buffer
);
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
)
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
);
610 } /* if gadget is a strgclass object */
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
)
627 struct StringInfo
*strinfo
;
630 struct TextFont
*oldfont
;
632 struct Window
*window
;
633 struct Requester
*req
;
635 UWORD text_left
, text_right
;
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
;
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
;
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
,
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"));
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
)
743 for (i
= first
; i
<= last
; i
++)
745 str
[i
- steps
] = str
[i
];
750 /*****************************************************************************************/
752 STATIC ULONG
DoSGHKey(struct SGWork
*sgw
, struct IntuitionBase
*IntuitionBase
)
756 struct StringInfo
*strinfo
;
760 EnterFunc(bug("DoSGHKey(sgw=%p)\n", sgw
));
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",
773 GetPrivIBase(IntuitionBase
)->IControlPrefs
.ic_Flags
,
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
;
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
;
802 else if ( ((letter
== CURSORLEFT
) && (qual
& SHIFT
)) ||
803 (letter
== HOMERAW
) )
805 if (sgw
->BufferPos
> 0)
808 sgw
->EditOp
= EO_MOVECURSOR
;
811 else if ( ((letter
== CURSORRIGHT
) && (qual
& SHIFT
)) ||
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 ??? */
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 */
835 sgw
->EditOp
= EO_SPECIAL
; /* FIXME: ??? is this correct ??? */
836 sgw
->Actions
= (SGA_USE
|SGA_REUSE
|SGA_END
);
838 letter
= ToUpper(sgw
->Code
);
840 /* stegerg: URGENTCHECMKE. Why disabled for AROS? */
842 #warning we need to handle RAMIGA-Q,RAMIGA-X here
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
);
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"));
868 sgw
->EditOp
= EO_MOVECURSOR
;
873 sgw
->WorkBuffer
[sgw
->BufferPos
] = '\0';
874 sgw
->NumChars
= sgw
->BufferPos
;
875 sgw
->EditOp
= EO_CLEAR
;
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"));
899 sgw
->EditOp
= EO_MOVECURSOR
;
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)
909 sgw
->EditOp
= EO_MOVECURSOR
;
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);
921 sgw
->EditOp
= EO_DELFORWARD
;
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
;
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
)
943 sgw
->EditOp
= EO_MOVECURSOR
;
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)
959 sgw
->EditOp
= EO_MOVECURSOR
;
964 if (sgw
->BufferPos
> 0)
967 len
= sgw
->NumChars
- sgw
->BufferPos
;
968 memcpy(&sgw
->WorkBuffer
[sgw
->BufferPos
-1],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
971 sgw
->WorkBuffer
[sgw
->BufferPos
+ len
] = 0;
973 sgw
->EditOp
= EO_DELBACKWARD
;
978 if (letter
== CTRL_K
)
980 /* CTRL-K Delete from the character under the cursor to the end
983 D(bug("sghkey: CTRL-K\n"));
984 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
985 sgw
->NumChars
= sgw
->BufferPos
;
986 sgw
->EditOp
= EO_DELFORWARD
;
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
;
996 sgw
->Actions
= (SGA_USE
|SGA_END
);
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"));
1011 if (sgw
->BufferPos
> 0)
1018 for (pos
=sgw
->BufferPos
-1;pos
>= 0;pos
--)
1020 if (sgw
->WorkBuffer
[pos
] == ' ')
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
;
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
1042 D(bug("sghkey: CTRL-U\n"));
1043 if (sgw
->Modes
& SGM_FIXEDFIELD
)
1045 D(bug("sghkey: SGM_FIXEDFIELD\n"));
1047 sgw
->EditOp
= EO_MOVECURSOR
;
1051 if (sgw
->BufferPos
> 0)
1054 len
= sgw
->NumChars
- sgw
->BufferPos
;
1055 memcpy(&sgw
->WorkBuffer
[0],&sgw
->WorkBuffer
[sgw
->BufferPos
],len
);
1058 sgw
->WorkBuffer
[len
] = 0;
1059 sgw
->NumChars
= len
;
1060 sgw
->EditOp
= EO_DELBACKWARD
;
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"));
1075 sgw
->EditOp
= EO_MOVECURSOR
;
1080 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
1081 sgw
->NumChars
= sgw
->BufferPos
;
1082 sgw
->EditOp
= EO_CLEAR
;
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
;
1096 if (letter
== BACKSPACE
)
1098 if (sgw
->BufferPos
!= 0)
1100 UWORD first
= sgw
->BufferPos
;
1101 UWORD last
= sgw
->NumChars
- 1;
1105 steps
= sgw
->BufferPos
;
1108 sgw
->NumChars
-= steps
;
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
)
1127 sgw
->WorkBuffer
[sgw
->BufferPos
] = 0;
1128 sgw
->NumChars
= sgw
->BufferPos
;
1132 MoveCharsLeft(sgw
->WorkBuffer
, sgw
->BufferPos
+ 1, sgw
->NumChars
- 1, 1);
1135 sgw
->EditOp
= EO_DELFORWARD
;
1138 else if (letter
== RETURN
)
1140 D(bug("sghkey: ENTER\n"));
1141 sgw
->EditOp
= EO_ENTER
;
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
);
1154 /* Validity check of letter */
1155 if (gad
->Activation
& GACT_LONGINT
)
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)
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))
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];
1213 sgw
->WorkBuffer
[i
] = letter
;
1214 sgw
->EditOp
= EO_INSERTCHAR
;
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
)
1259 retcode
= DoSGHClick(sgw
, (struct IntuitionBase
*)hook
->h_Data
);
1263 retcode
= DoSGHKey (sgw
, (struct IntuitionBase
*)hook
->h_Data
);
1272 /*****************************************************************************************/
1274 VOID
RefreshStrGadget(struct Gadget
*gad
,
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
)
1293 (struct Image
*)gad
->GadgetRender
,
1300 (struct Border
*)gad
->GadgetRender
,
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
));
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
);
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
,
1351 struct Requester
*req
,
1352 struct IntuitionBase
*IntuitionBase
)
1354 struct GadgetInfo gi
;
1356 struct StringInfo
*strinfo
= (struct StringInfo
*)gad
->SpecialInfo
;
1359 struct RastPort
*rp
;
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
);
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
]);
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
);
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
;
1416 // SetAfPt(rp,NULL,0);
1417 D(bug("usg: Number of characters: %d\n", strinfo
->NumChars
));
1420 text_left
+= TextLength(rp
, dispstr
, cursoroffset
);
1423 if (strinfo
->BufferPos
< strinfo
->NumChars
)
1425 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[CURSORPEN
], JAM2
);
1426 Move(rp
, text_left
, text_top
);
1428 dispstr
+ cursoroffset
,
1433 struct TextExtent te
;
1435 SetABPenDrMd(rp
, pens
[STRTEXTPEN
], pens
[CURSORPEN
], JAM2
|INVERSVID
);
1436 TextExtent(rp
, cursorkey
, CURSORKEYLEN
,&te
);
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
);
1445 Move(rp
, text_left
, text_top
);
1447 ((strinfo
->BufferPos
< strinfo
->NumChars
)
1448 ? dispstr
+ cursoroffset
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
,
1461 bbox
.Left
+ bbox
.Width
- 1,
1462 bbox
.Top
+ bbox
.Height
- 1,
1465 if (dri
) FreeScreenDrawInfo(win
->WScreen
, dri
);
1470 ReturnVoid("UpdateStrGadget");