Keep AROS_BSTR macros within an #ifdef __AROS__ block.
[AROS.git] / workbench / classes / zune / betterstring / mcc / HandleInput.c
blobef1b2f99e32a6d887f91ff5ae07317c893b246cd
1 /***************************************************************************
3 BetterString.mcc - A better String gadget MUI Custom Class
4 Copyright (C) 1997-2000 Allan Odgaard
5 Copyright (C) 2005-2009 by BetterString.mcc Open Source Team
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 BetterString class Support Site: http://www.sf.net/projects/bstring-mcc/
19 $Id$
21 ***************************************************************************/
23 #include <string.h>
24 #include <stdlib.h>
26 #include <clib/alib_protos.h>
27 #include <clib/macros.h>
28 #include <proto/exec.h>
29 #include <proto/graphics.h>
30 #include <proto/intuition.h>
31 #include <proto/muimaster.h>
32 #include <proto/keymap.h>
33 #include <proto/layers.h>
34 #include <proto/locale.h>
35 #include <proto/dos.h>
37 #include "private.h"
39 #include "SDI_stdarg.h"
41 #define BlockEnabled(data) (isFlagSet((data)->Flags, FLG_BlockEnabled) && (data)->BlockStart != (data)->BlockStop)
43 #if defined(__amigaos4__) || defined(__MORPHOS__)
44 static int VARARGS68K MySPrintf(char *buf, const char *fmt, ...)
46 VA_LIST args;
48 VA_START(args, fmt);
49 RawDoFmt(fmt, VA_ARG(args, void *), NULL, (STRPTR)buf);
50 VA_END(args);
52 return(strlen(buf));
54 #elif defined(__AROS__)
55 #define MySPrintf __sprintf /* from amiga lib */
56 #else
57 static int STDARGS MySPrintf(char *buf, const char *fmt, ...)
59 static const UWORD PutCharProc[2] = {0x16C0,0x4E75};
60 /* dirty hack to avoid assembler part :-)
61 16C0: move.b d0,(a3)+
62 4E75: rts */
63 va_list args;
65 va_start(args, fmt);
66 RawDoFmt(fmt, args, (void (*)(void))PutCharProc, (STRPTR)buf);
67 va_end(args);
69 return(strlen(buf));
71 #endif
73 static void AddToUndo(struct InstData *data)
75 if(data->Undo)
76 SharedPoolFree(data->Undo);
78 if((data->Undo = (STRPTR)SharedPoolAlloc(strlen(data->Contents)+1)))
80 strlcpy(data->Undo, data->Contents, strlen(data->Contents)+1);
81 data->UndoPos = data->BufferPos;
82 clearFlag(data->Flags, FLG_RedoAvailable);
86 static WORD AlignOffset(Object *obj, struct InstData *data)
88 struct MUI_AreaData *ad = muiAreaData(obj);
89 struct TextFont *font = data->Font ? data->Font : ad->mad_Font;
90 WORD width = ad->mad_Box.Width - ad->mad_subwidth;
91 WORD offset = 0;
93 if(data->Alignment != MUIV_String_Format_Left)
95 STRPTR text = data->Contents+data->DisplayPos;
96 UWORD StrLength = strlen(text);
97 UWORD length, textlength, crsr_width;
98 struct TextExtent tExtend;
100 SetFont(&data->rport, font);
101 length = TextFit(&data->rport, text, StrLength, &tExtend, NULL, 1, width, font->tf_YSize);
102 textlength = TextLength(&data->rport, text, length);
104 crsr_width = isFlagSet(data->Flags, FLG_Active) ? TextLength(&data->rport, (*(data->Contents+data->BufferPos) == '\0') ? (char *)"n" : (char *)(data->Contents+data->BufferPos), 1) : 0;
105 if(crsr_width && BlockEnabled(data) == FALSE && data->BufferPos == data->DisplayPos+StrLength)
107 textlength += crsr_width;
110 switch(data->Alignment)
112 case MUIV_String_Format_Center:
113 offset = (width - textlength)/2;
114 break;
115 case MUIV_String_Format_Right:
116 offset = (width - textlength);
117 break;
120 return(offset);
123 static BOOL Reject(UBYTE code, STRPTR reject)
125 if(reject)
127 while(*reject)
129 if(code == *reject++)
130 return(FALSE);
133 return(TRUE);
136 static BOOL Accept(UBYTE code, STRPTR accept)
138 return(accept ? !Reject(code, accept) : TRUE);
141 static UWORD DecimalValue(UBYTE code)
143 if(code >= '0' && code <= '9')
144 return(code - '0');
145 if(code >= 'a' && code <= 'f')
146 return(code - 'a' + 10);
147 if(code >= 'A' && code <= 'F')
148 return(code - 'A' + 10);
150 return(0);
153 static BOOL IsHex(UBYTE code)
155 return(
156 (code >= '0' && code <= '9') ||
157 (code >= 'a' && code <= 'f') ||
158 (code >= 'A' && code <= 'F') ? TRUE : FALSE);
161 static LONG FindDigit(struct InstData *data)
163 WORD pos = data->BufferPos;
165 if(IsDigit(data->locale, *(data->Contents+pos)))
167 while(pos > 0 && IsDigit(data->locale, *(data->Contents+pos-1)))
168 pos--;
170 else
172 while(*(data->Contents+pos) != '\0' && !IsDigit(data->locale, *(data->Contents+pos)))
173 pos++;
176 if(*(data->Contents+pos) == '\0')
178 pos = data->BufferPos;
179 while(pos && !IsDigit(data->locale, *(data->Contents+pos)))
180 pos--;
182 while(pos > 0 && IsDigit(data->locale, *(data->Contents+pos-1)))
183 pos--;
185 if(!pos && !IsDigit(data->locale, *data->Contents))
187 pos = -1;
190 return(pos);
193 static UWORD NextWord(STRPTR text, UWORD x, struct Locale *locale)
195 while(IsAlNum(locale, (UBYTE)text[x]))
196 x++;
198 while(text[x] != '\0' && !IsAlNum(locale, (UBYTE)text[x]))
199 x++;
201 return(x);
204 static UWORD PrevWord(STRPTR text, UWORD x, struct Locale *locale)
206 if(x)
207 x--;
209 while(x && !IsAlNum(locale, (UBYTE)text[x]))
210 x--;
212 while(x > 0 && IsAlNum(locale, (UBYTE)text[x-1]))
213 x--;
215 return(x);
218 void strcpyback(STRPTR dest, STRPTR src)
220 UWORD length;
222 length = strlen(src)+1;
223 dest = dest + length;
224 src = src + length;
226 length++;
227 while(--length)
229 *--dest = *--src;
233 void DeleteBlock(struct InstData *data)
235 AddToUndo(data);
237 if(BlockEnabled(data) == TRUE)
239 UWORD Blk_Start, Blk_Width;
240 Blk_Start = (data->BlockStart < data->BlockStop) ? data->BlockStart : data->BlockStop;
241 Blk_Width = abs(data->BlockStop-data->BlockStart);
242 strcpy(data->Contents+Blk_Start, data->Contents+Blk_Start+Blk_Width);
243 data->BufferPos = Blk_Start;
247 static void CopyBlock(struct InstData *data)
249 ENTER();
251 if(isFlagClear(data->Flags, FLG_Secret))
253 UWORD Blk_Start, Blk_Width;
254 //struct IFFHandle *iff;
256 if(BlockEnabled(data) == TRUE)
258 Blk_Start = (data->BlockStart < data->BlockStop) ? data->BlockStart : data->BlockStop;
259 Blk_Width = abs(data->BlockStop-data->BlockStart);
261 else
263 Blk_Start = 0;
264 Blk_Width = strlen(data->Contents);
267 StringToClipboard(&data->Contents[Blk_Start], Blk_Width);
270 LEAVE();
273 static void CutBlock(struct InstData *data)
275 ENTER();
277 AddToUndo(data);
279 if(BlockEnabled(data) == TRUE)
281 CopyBlock(data);
282 DeleteBlock(data);
283 clearFlag(data->Flags, FLG_BlockEnabled);
285 else
287 *data->Contents = '\0';
288 data->BufferPos = 0;
291 LEAVE();
294 static void Paste(struct InstData *data)
296 STRPTR str;
297 LONG length;
299 ENTER();
301 // clear the selection
302 DeleteBlock(data);
304 ClipboardToString(&str, &length);
305 if(str != NULL && length > 0)
307 if(data->MaxLength != 0 && strlen(data->Contents) + length > (ULONG)data->MaxLength - 1)
309 DisplayBeep(NULL);
310 length = data->MaxLength - 1 - strlen(data->Contents);
313 data->Contents = (STRPTR)SharedPoolExpand(data->Contents, length);
314 strcpyback(data->Contents + data->BufferPos + length, data->Contents + data->BufferPos);
315 memcpy(data->Contents + data->BufferPos, str, length);
316 data->BufferPos += length;
318 SharedPoolFree(str);
321 LEAVE();
324 static void UndoRedo(struct InstData *data)
326 STRPTR oldcontents = data->Contents;
327 UWORD oldpos = data->BufferPos;
329 ENTER();
331 data->Contents = data->Undo;
332 data->Undo = oldcontents;
334 if(isFlagSet(data->Flags, FLG_RedoAvailable))
335 clearFlag(data->Flags, FLG_RedoAvailable);
336 else
337 setFlag(data->Flags, FLG_RedoAvailable);
339 clearFlag(data->Flags, FLG_BlockEnabled);
340 data->BufferPos = data->UndoPos;
341 data->UndoPos = oldpos;
343 LEAVE();
346 static void RevertToOriginal(struct InstData *data)
348 STRPTR oldcontents = data->Contents;
350 ENTER();
352 data->Contents = data->Original;
353 data->Original = oldcontents;
354 setFlag(data->Flags, FLG_Original);
355 clearFlag(data->Flags, FLG_BlockEnabled);
356 data->BufferPos = strlen(data->Contents);
358 LEAVE();
361 static BOOL ToggleCaseChar(struct InstData *data)
363 UBYTE key = *(data->Contents+data->BufferPos);
364 BOOL result = FALSE;
366 ENTER();
368 if(data->BufferPos < strlen(data->Contents))
370 *(data->Contents+data->BufferPos) = IsLower(data->locale, key) ? ConvToUpper(data->locale, key) : ConvToLower(data->locale, key);
371 data->BufferPos++;
372 result = TRUE;
375 RETURN(result);
376 return result;
379 static BOOL ToggleCaseWord(struct InstData *data)
381 UWORD Stop = NextWord(data->Contents, data->BufferPos, data->locale);
382 BOOL result = FALSE;
384 ENTER();
386 while(data->BufferPos < Stop)
388 UBYTE key = *(data->Contents+data->BufferPos);
390 *(data->Contents+data->BufferPos) = IsLower(data->locale, key) ? ConvToUpper(data->locale, key) : ConvToLower(data->locale, key);
391 data->BufferPos++;
392 result = TRUE;
395 RETURN(result);
396 return result;
399 static BOOL IncreaseNearNumber(struct InstData *data)
401 LONG pos;
402 BOOL result = FALSE;
404 ENTER();
406 if((pos = FindDigit(data)) >= 0)
408 LONG cut;
409 ULONG res;
411 if((cut = StrToLong(data->Contents+pos, (LONG *)&res)))
413 char string[12];
414 char format[12];
416 res++;
417 MySPrintf(format, "%%0%ldlu", cut);
418 MySPrintf(string, format, res);
419 Overwrite(string, pos, cut, data);
420 result = TRUE;
424 RETURN(result);
425 return result;
428 static BOOL DecreaseNearNumber(struct InstData *data)
430 LONG pos;
431 BOOL result = FALSE;
433 ENTER();
435 if((pos = FindDigit(data)) >= 0)
437 LONG cut;
438 ULONG res;
440 if((cut = StrToLong(data->Contents+pos, (LONG *)&res)))
442 if(res)
444 char *format;
445 char string[12];
446 char format2[12];
448 format = &format2[0];
449 MySPrintf(format, "%%0%ldlu", cut);
450 res--;
451 MySPrintf(string, format, res);
452 Overwrite(string, pos, cut, data);
453 result = TRUE;
458 RETURN(result);
459 return result;
462 static BOOL HexToDec(struct InstData *data)
464 LONG cut = 0;
465 UWORD pos = data->BufferPos;
466 ULONG res = 0;
467 BOOL result = FALSE;
469 ENTER();
471 while(pos && IsHex(*(data->Contents+pos-1)))
472 pos--;
474 while(IsHex(*(data->Contents+pos+cut)))
476 res = (result << 4) + DecimalValue(*(data->Contents+pos+cut));
477 cut++;
480 if(cut)
482 char string[12];
484 MySPrintf(string, "%lu", res);
485 Overwrite(string, pos, cut, data);
486 result = TRUE;
489 RETURN(result);
490 return result;
493 static BOOL DecToHex(struct InstData *data)
495 LONG pos;
496 BOOL result = FALSE;
498 ENTER();
500 if((pos = FindDigit(data)) >= 0)
502 LONG cut;
503 ULONG res;
505 if((cut = StrToLong(data->Contents+pos, (LONG *)&res)))
507 const char *format = "%lx";
508 char string[12];
510 MySPrintf(string, format, res);
511 Overwrite(string, pos, cut, data);
512 result = TRUE;
516 RETURN(result);
517 return result;
520 ULONG ConvertKey(struct IntuiMessage *imsg)
522 struct InputEvent event;
523 unsigned char code = 0;
525 event.ie_NextEvent = NULL;
526 event.ie_Class = IECLASS_RAWKEY;
527 event.ie_SubClass = 0;
528 event.ie_Code = imsg->Code;
529 event.ie_Qualifier = imsg->Qualifier;
530 event.ie_EventAddress = (APTR *) *((IPTR *)imsg->IAddress);
532 MapRawKey(&event, (STRPTR)&code, 1, NULL);
533 return(code);
536 IPTR mDoAction(struct IClass *cl, Object *obj, struct MUIP_BetterString_DoAction *msg)
538 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
539 IPTR result = FALSE;
540 BOOL edited = FALSE;
542 ENTER();
544 D(DBF_INPUT, "DoAction(%ld)", msg->action);
546 switch(msg->action)
548 case MUIV_BetterString_DoAction_Cut:
550 CutBlock(data);
551 edited = TRUE;
552 result = TRUE;
554 break;
556 case MUIV_BetterString_DoAction_Copy:
558 CopyBlock(data);
559 clearFlag(data->Flags, FLG_BlockEnabled);
560 result = TRUE;
562 break;
564 case MUIV_BetterString_DoAction_Paste:
566 Paste(data);
567 clearFlag(data->Flags, FLG_BlockEnabled);
568 edited = TRUE;
569 result = TRUE;
571 break;
573 case MUIV_BetterString_DoAction_Delete:
575 DeleteBlock(data);
576 clearFlag(data->Flags, FLG_BlockEnabled);
577 edited = TRUE;
578 result = TRUE;
580 break;
582 case MUIV_BetterString_DoAction_SelectAll:
584 data->BlockStart = 0;
585 data->BlockStop = strlen(data->Contents);
586 setFlag(data->Flags, FLG_BlockEnabled);
587 result = TRUE;
589 break;
591 case MUIV_BetterString_DoAction_SelectNone:
593 clearFlag(data->Flags, FLG_BlockEnabled);
594 result = TRUE;
596 break;
598 case MUIV_BetterString_DoAction_Undo:
599 case MUIV_BetterString_DoAction_Redo:
601 if(data->Undo &&
602 (((msg->action == MUIV_BetterString_DoAction_Redo) && isFlagSet(data->Flags, FLG_RedoAvailable)) ||
603 ((msg->action == MUIV_BetterString_DoAction_Undo) && isFlagClear(data->Flags, FLG_RedoAvailable))))
605 UndoRedo(data);
606 clearFlag(data->Flags, FLG_BlockEnabled);
607 edited = TRUE;
608 result = TRUE;
611 break;
613 case MUIV_BetterString_DoAction_Revert:
615 RevertToOriginal(data);
616 clearFlag(data->Flags, FLG_BlockEnabled);
617 edited = TRUE;
618 result = TRUE;
620 break;
622 case MUIV_BetterString_DoAction_ToggleCase:
624 edited = result = ToggleCaseChar(data);
625 clearFlag(data->Flags, FLG_BlockEnabled);
627 break;
629 case MUIV_BetterString_DoAction_ToggleCaseWord:
631 edited = result = ToggleCaseWord(data);
632 clearFlag(data->Flags, FLG_BlockEnabled);
634 break;
636 case MUIV_BetterString_DoAction_IncreaseNum:
638 edited = result = IncreaseNearNumber(data);
639 clearFlag(data->Flags, FLG_BlockEnabled);
641 break;
643 case MUIV_BetterString_DoAction_DecreaseNum:
645 edited = result = DecreaseNearNumber(data);
646 clearFlag(data->Flags, FLG_BlockEnabled);
648 break;
650 case MUIV_BetterString_DoAction_HexToDec:
652 edited = result = HexToDec(data);
653 clearFlag(data->Flags, FLG_BlockEnabled);
655 break;
657 case MUIV_BetterString_DoAction_DecToHex:
659 edited = result = DecToHex(data);
660 clearFlag(data->Flags, FLG_BlockEnabled);
662 break;
664 case MUIV_BetterString_DoAction_NextFileComp:
666 edited = result = FileNameComplete(obj, FALSE, data);
667 clearFlag(data->Flags, FLG_BlockEnabled);
669 break;
671 case MUIV_BetterString_DoAction_PrevFileComp:
673 edited = result = FileNameComplete(obj, TRUE, data);
674 clearFlag(data->Flags, FLG_BlockEnabled);
676 break;
679 if(edited == TRUE)
681 struct TagItem tags[] =
683 { MUIA_String_Contents, (IPTR)data->Contents },
684 { TAG_DONE, 0 }
687 DoSuperMethod(cl, obj, OM_SET, tags, NULL);
690 MUI_Redraw(obj, MADF_DRAWUPDATE);
692 RETURN(result);
693 return result;
696 IPTR HandleInput(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
698 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
699 struct MUI_AreaData *ad = muiAreaData(obj);
700 struct TextFont *Font = data->Font ? data->Font : ad->mad_Font;
701 IPTR result = 0;
702 BOOL movement = FALSE;
703 BOOL edited = FALSE;
704 BOOL FNC = FALSE;
705 Object *focus = NULL;
707 ENTER();
709 if(msg->muikey == MUIKEY_UP)
710 focus = data->KeyUpFocus;
711 else if(msg->muikey == MUIKEY_DOWN)
712 focus = data->KeyDownFocus;
714 if(focus && _win(obj))
716 set(_win(obj), MUIA_Window_ActiveObject, focus);
717 result = MUI_EventHandlerRC_Eat;
719 else if(msg->imsg)
721 ULONG StringLength = strlen(data->Contents);
723 if(msg->imsg->Class == IDCMP_RAWKEY &&
724 // msg->imsg->Code >= IECODE_KEY_CODE_FIRST &&
725 msg->imsg->Code <= IECODE_KEY_CODE_LAST)
727 if(isFlagSet(data->Flags, FLG_Active))
729 BOOL input = TRUE;
731 if(isFlagClear(data->Flags, FLG_BlockEnabled))
732 data->BlockStart = data->BufferPos;
734 if(isFlagSet(data->Flags, FLG_NoInput))
736 switch(msg->imsg->Code)
738 case RAWKEY_TAB:
739 case RAWKEY_BACKSPACE:
740 case RAWKEY_DEL:
741 input = FALSE;
742 break;
746 if(input == TRUE)
748 switch(msg->imsg->Code)
750 // Tab
751 case RAWKEY_TAB:
753 if(isFlagSet(data->Flags, FLG_NoShortcuts) || isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_RCOMMAND))
755 RETURN(0);
756 return 0;
759 if(!(edited = FileNameComplete(obj, isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT), data)))
760 DisplayBeep(NULL);
762 FNC = TRUE;
764 break;
766 // Right
767 case RAWKEY_CRSRRIGHT:
769 if(data->BufferPos < StringLength)
771 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT))
773 data->BufferPos = StringLength;
775 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
777 data->BufferPos = NextWord(data->Contents, data->BufferPos, data->locale);
779 else if(BlockEnabled(data) && isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
781 data->BufferPos = MAX(data->BlockStart, data->BlockStop);
783 else
785 data->BufferPos++;
788 movement = TRUE;
790 break;
792 // Left
793 case RAWKEY_CRSRLEFT:
795 if(data->BufferPos)
797 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT))
799 data->BufferPos = 0;
801 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
803 data->BufferPos = PrevWord(data->Contents, data->BufferPos, data->locale);
805 else
807 if(BlockEnabled(data) && isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
808 data->BufferPos = MIN(data->BlockStart, data->BlockStop);
810 if(data->BufferPos)
811 data->BufferPos--;
814 movement = TRUE;
816 break;
818 // Backspace
819 case RAWKEY_BACKSPACE:
821 if(BlockEnabled(data))
823 DeleteBlock(data);
825 else
827 if(data->BufferPos != 0)
829 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT|IEQUALIFIER_CONTROL))
831 AddToUndo(data);
832 strcpy(data->Contents, data->Contents+data->BufferPos);
833 data->BufferPos = 0;
835 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
837 UWORD NewPos = PrevWord(data->Contents, data->BufferPos, data->locale);
839 AddToUndo(data);
840 strcpy(data->Contents+NewPos, data->Contents+data->BufferPos);
841 data->BufferPos = NewPos;
843 else
845 strcpy(data->Contents+data->BufferPos-1, data->Contents+data->BufferPos);
846 data->BufferPos--;
850 edited = TRUE;
852 break;
854 // Delete
855 case RAWKEY_DEL:
857 if(BlockEnabled(data))
859 DeleteBlock(data);
861 else
863 if(data->BufferPos < StringLength)
865 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT) || isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
867 AddToUndo(data);
868 *(data->Contents+data->BufferPos) = '\0';
870 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
872 AddToUndo(data);
873 strcpy(data->Contents+data->BufferPos, data->Contents+NextWord(data->Contents, data->BufferPos, data->locale));
875 else
877 strcpy(data->Contents+data->BufferPos, data->Contents+data->BufferPos+1);
881 edited = TRUE;
883 break;
885 // Home
886 case RAWKEY_HOME:
888 if(data->BufferPos)
889 data->BufferPos = 0;
891 movement = TRUE;
893 break;
895 // End
896 case RAWKEY_END:
898 if(data->BufferPos < StringLength)
899 data->BufferPos = StringLength;
901 movement = TRUE;
903 break;
905 default:
907 if(data->Popup && msg->muikey == MUIKEY_POPUP)
909 DoMethod(data->Popup, MUIM_Popstring_Open);
911 else
913 UBYTE code = ConvertKey(msg->imsg);
915 if((((code >= 32 && code <= 126) || code >= 160) && isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_RCOMMAND)) ||
916 (code && isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL)))
918 if(isFlagClear(data->Flags, FLG_NoInput))
920 DeleteBlock(data);
922 if((data->MaxLength == 0 || (ULONG)data->MaxLength-1 > strlen(data->Contents)) &&
923 Accept(code, data->Accept) && Reject(code, data->Reject))
925 data->Contents = (STRPTR)SharedPoolExpand(data->Contents, 1);
926 strcpyback(data->Contents+data->BufferPos+1, data->Contents+data->BufferPos);
927 *(data->Contents+data->BufferPos) = code;
928 data->BufferPos++;
929 edited = TRUE;
931 else
933 DisplayBeep(NULL);
937 else
939 // if this betterstring object is a read-only object
940 // we only accept a view characters or otherwise reject
941 // the rawkey operation
942 if(isFlagSet(data->Flags, FLG_NoInput))
944 switch(code)
946 case '\r':
947 case 'c':
948 break;
950 default:
951 RETURN(MUI_EventHandlerRC_Eat);
952 return MUI_EventHandlerRC_Eat;
953 break;
957 // check if the user pressed return and if he has activated AdvanceOnCr or not
958 if(code == '\r')
960 if(isFlagClear(data->Flags, FLG_StayActive))
962 ULONG active;
964 if(isFlagSet(data->Flags, FLG_AdvanceOnCr))
966 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT))
967 active = MUIV_Window_ActiveObject_Prev;
968 else
969 active = MUIV_Window_ActiveObject_Next;
971 else
972 active = MUIV_Window_ActiveObject_None;
974 set(_win(obj), MUIA_Window_ActiveObject, active);
977 set(obj, MUIA_String_Acknowledge, data->Contents);
979 RETURN(MUI_EventHandlerRC_Eat);
980 return MUI_EventHandlerRC_Eat;
983 // see if we should skip the default shorcuts or not
984 if(isFlagClear(data->Flags, FLG_NoShortcuts))
986 // depending on the pressed key code
987 // we perform different actions.
988 switch(code)
990 case 'g':
992 edited = ToggleCaseChar(data);
994 break;
996 case 'G':
998 edited = ToggleCaseWord(data);
1000 break;
1002 case 'c':
1003 CopyBlock(data);
1004 break;
1006 case 'x':
1007 CutBlock(data);
1008 edited = TRUE;
1009 break;
1011 case 'v':
1012 Paste(data);
1013 edited = TRUE;
1014 break;
1016 case 'i':
1018 if((edited = IncreaseNearNumber(data)) == FALSE)
1019 DisplayBeep(NULL);
1021 break;
1023 case 'd':
1025 if((edited = DecreaseNearNumber(data)) == FALSE)
1026 DisplayBeep(NULL);
1028 break;
1030 case '#':
1032 if((edited = HexToDec(data)) == FALSE)
1033 DisplayBeep(NULL);
1035 break;
1037 case '$':
1039 if((edited = DecToHex(data)) == FALSE)
1040 DisplayBeep(NULL);
1042 break;
1044 case 'q':
1046 RevertToOriginal(data);
1047 edited = TRUE;
1049 break;
1051 case 'z':
1052 case 'Z':
1054 if(data->Undo && (((code == 'Z') && isFlagSet(data->Flags, FLG_RedoAvailable)) ||
1055 ((code == 'z') && isFlagClear(data->Flags, FLG_RedoAvailable))))
1057 UndoRedo(data);
1058 edited = TRUE;
1060 else
1061 DisplayBeep(NULL);
1063 break;
1065 default:
1066 clearFlag(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT);
1067 RETURN(0);
1068 return 0;
1071 else
1073 clearFlag(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT);
1074 RETURN(0);
1075 return 0;
1080 break;
1084 if(data->FNCBuffer && !FNC)
1086 struct FNCData *fncbuffer = data->FNCBuffer, *fncframe;
1088 while(fncbuffer)
1090 fncframe = fncbuffer;
1091 fncbuffer = fncbuffer->next;
1092 SharedPoolFree(fncframe);
1094 data->FNCBuffer = NULL;
1097 if(movement && isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
1098 setFlag(data->Flags, FLG_BlockEnabled);
1099 else
1100 clearFlag(data->Flags, FLG_BlockEnabled);
1102 if(isFlagSet(data->Flags, FLG_BlockEnabled))
1103 data->BlockStop = data->BufferPos;
1105 if(edited)
1107 struct TagItem tags[] =
1109 { MUIA_String_Contents, (IPTR)data->Contents },
1110 { TAG_DONE, 0 }
1113 DoSuperMethod(cl, obj, OM_SET, tags, NULL);
1116 MUI_Redraw(obj, MADF_DRAWUPDATE);
1117 result = MUI_EventHandlerRC_Eat;
1119 else
1121 if(data->CtrlChar && ConvertKey(msg->imsg) == data->CtrlChar)
1123 set(_win(obj), MUIA_Window_ActiveObject, obj);
1124 result = MUI_EventHandlerRC_Eat;
1128 else
1130 D(DBF_INPUT, "%08lx: keycode: %08lx (%ld) %08lx (%ld)", obj, msg->imsg->Code, isFlagSet(data->Flags, FLG_Active), RAWKEY_TAB, msg->imsg->Code <= IECODE_KEY_CODE_LAST);
1132 // check if the user pressed the TAB key for cycling to the next
1133 // mui object and if this object is part of the cyclechain
1134 if(msg->imsg->Class == IDCMP_RAWKEY && isFlagSet(data->Flags, FLG_Active) && isFlagSet(data->Flags, FLG_FreshActive))
1136 // clear the FreshActive flag
1137 clearFlag(data->Flags, FLG_FreshActive);
1138 // no need to do an DoAction(SelectAll), because this effectively has been
1139 // done during MUIM_GoActive already
1142 // we check if this is a mousemove input message and if
1143 // so we check whether the mouse is currently over our
1144 // texteditor object or not.
1145 if(msg->imsg->Class == IDCMP_MOUSEMOVE)
1147 BOOL isOverObject = FALSE;
1149 D(DBF_INPUT, "IDCMP_MOUSEMOVE");
1150 if(_isinobject(obj, msg->imsg->MouseX, msg->imsg->MouseY))
1152 #if defined(__MORPHOS__)
1153 if(IS_MORPHOS2)
1154 isOverObject = TRUE;
1155 #endif
1157 if(isOverObject == FALSE)
1159 struct Layer_Info *li = &(_screen(obj)->LayerInfo);
1160 struct Layer *layer;
1162 // get the layer that belongs to the current mouse coordinates
1163 LockLayerInfo(li);
1164 layer = WhichLayer(li, _window(obj)->LeftEdge + msg->imsg->MouseX, _window(obj)->TopEdge + msg->imsg->MouseY);
1165 UnlockLayerInfo(li);
1167 // if the mouse is currently over the object and over the object's
1168 // window we go and change the pointer to show the selection pointer
1169 if(layer != NULL && layer->Window == _window(obj))
1170 isOverObject = TRUE;
1174 if(isOverObject == TRUE)
1175 ShowSelectPointer(obj, data);
1176 else
1177 HideSelectPointer(obj, data);
1179 else if(msg->imsg->Class == IDCMP_MOUSEBUTTONS)
1181 D(DBF_INPUT, "IDCMP_MOUSEBUTTONS");
1182 if(msg->imsg->Code == (IECODE_LBUTTON | IECODE_UP_PREFIX))
1184 // forget the pressed mouse button
1185 clearFlag(data->Flags, FLG_MouseButtonDown);
1187 if(isAnyFlagSet(data->ehnode.ehn_Events, /*IDCMP_MOUSEMOVE|*/IDCMP_INTUITICKS))
1189 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
1190 // clearFlag(data->ehnode.ehn_Events, IDCMP_MOUSEMOVE);
1191 clearFlag(data->ehnode.ehn_Events, IDCMP_INTUITICKS);
1192 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
1195 // make sure to select the whole betterstring content in case
1196 // the objec was freshly active and the user pressed the mousebutton
1197 if(isFlagSet(data->Flags, FLG_FreshActive) && BlockEnabled(data) == FALSE &&
1198 ((data->SelectOnActive == TRUE && isFlagClear(data->Flags, FLG_ForceSelectOff)) || isFlagSet(data->Flags, FLG_ForceSelectOn)))
1200 DoMethod(obj, MUIM_BetterString_DoAction, MUIV_BetterString_DoAction_SelectAll);
1203 #ifdef ALLOW_OUTSIDE_MARKING
1204 if(isFlagSet(data->Flags, FLG_Active) && isFlagSet(data->Flags, FLG_DragOutside))
1206 Object *active;
1207 get(_win(obj), MUIA_Window_ActiveObject, &active);
1208 if(obj != active)
1209 E(DBF_STARTUP, "MUI error: %lx, %lx", active, obj);
1211 WORD x = ad->mad_Box.Left + ad->mad_addleft;
1212 WORD y = ad->mad_Box.Top + ad->mad_addtop;
1213 WORD width = ad->mad_Box.Width - ad->mad_subwidth;
1214 WORD height = Font->tf_YSize;
1216 if(!(msg->imsg->MouseX >= x && msg->imsg->MouseX < x+width && msg->imsg->MouseY >= y && msg->imsg->MouseY < y+height))
1218 D(DBF_STARTUP, "Detected LMB+up outside (drag: %ld)", isFlagSet(data->Flags, FLG_DragOutside));
1219 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
1222 #endif
1224 // clear the FreshActive flag
1225 clearFlag(data->Flags, FLG_FreshActive);
1227 else if(msg->imsg->Code == IECODE_LBUTTON)
1229 WORD x = ad->mad_Box.Left + ad->mad_addleft;
1230 WORD y = ad->mad_Box.Top + ad->mad_addtop;
1231 WORD width = ad->mad_Box.Width - ad->mad_subwidth;
1232 WORD height = Font->tf_YSize;
1234 // remember the pressed mouse button
1235 setFlag(data->Flags, FLG_MouseButtonDown);
1237 if(msg->imsg->MouseX >= x && msg->imsg->MouseX < x+width && msg->imsg->MouseY >= y && msg->imsg->MouseY < y+height)
1239 WORD offset = msg->imsg->MouseX - x;
1240 struct TextExtent tExtend;
1242 offset -= AlignOffset(obj, data);
1244 SetFont(&data->rport, Font);
1245 data->BufferPos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, offset+1, Font->tf_YSize);
1247 if(data->BufferPos == data->BufferLastPos &&
1248 DoubleClick(data->StartSecs, data->StartMicros, msg->imsg->Seconds, msg->imsg->Micros))
1250 // on a secret gadget we skip clickcount step 1 as
1251 // it might be misused to guess the words in the gadget.
1252 if(isFlagSet(data->Flags, FLG_Secret) && data->ClickCount == 0)
1253 data->ClickCount++;
1255 data->ClickCount++;
1257 else
1258 data->ClickCount = 0;
1260 // lets save the current bufferpos to the lastpos variable
1261 data->BufferLastPos = data->BufferPos;
1263 data->StartSecs = msg->imsg->Seconds;
1264 data->StartMicros = msg->imsg->Micros;
1266 switch(data->ClickCount)
1268 case 0:
1270 if(isFlagClear(data->Flags, FLG_BlockEnabled) || isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
1271 data->BlockStart = data->BufferPos;
1273 break;
1275 case 1:
1277 if(data->Contents[data->BufferPos] != '\0')
1279 UWORD start = data->BufferPos;
1280 UWORD stop = data->BufferPos;
1281 ULONG alpha = IsAlNum(data->locale, (UBYTE)*(data->Contents+data->BufferPos));
1283 while(start > 0 && alpha == (ULONG)IsAlNum(data->locale, (UBYTE)*(data->Contents+start-1)))
1284 start--;
1286 while(alpha == (ULONG)IsAlNum(data->locale, (UBYTE)*(data->Contents+stop)) && *(data->Contents+stop) != '\0')
1287 stop++;
1289 data->BlockStart = start;
1290 data->BufferPos = stop;
1293 break;
1295 case 2:
1297 data->BlockStart = 0;
1298 data->BufferPos = strlen(data->Contents);
1300 break;
1302 case 3:
1304 data->BlockStart = data->BufferPos;
1305 data->ClickCount = 0;
1307 break;
1309 data->BlockStop = data->BufferPos;
1310 setFlag(data->Flags, FLG_BlockEnabled);
1312 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
1313 // setFlag(data->ehnode.ehn_Events, IDCMP_MOUSEMOVE);
1314 setFlag(data->ehnode.ehn_Events, IDCMP_INTUITICKS);
1315 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
1317 if(isFlagSet(data->Flags, FLG_Active))
1318 MUI_Redraw(obj, MADF_DRAWUPDATE);
1319 else
1320 set(_win(obj), MUIA_Window_ActiveObject, obj);
1322 result = MUI_EventHandlerRC_Eat;
1324 else
1326 data->ClickCount = 0;
1327 if(isFlagSet(data->Flags, FLG_Active) && isFlagClear(data->Flags, FLG_StayActive))
1329 #ifdef ALLOW_OUTSIDE_MARKING
1330 D(DBF_STARTUP, "Clicked outside gadget");
1331 setFlag(data->Flags, FLG_DragOutside);
1333 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
1334 // data->ehnode.ehn_Events |= IDCMP_MOUSEMOVE;
1335 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
1336 #else
1337 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
1338 #endif
1343 else
1345 #ifdef ALLOW_OUTSIDE_MARKING
1346 if(msg->imsg->Class == IDCMP_MOUSEMOVE)
1348 clearFlag(data->Flags, FLG_DragOutside);
1349 D(DBF_STARTUP, "Detected drag");
1351 #endif
1352 if((/*msg->imsg->Class == IDCMP_MOUSEMOVE ||*/ msg->imsg->Class == IDCMP_INTUITICKS) && isFlagSet(data->Flags, FLG_Active))
1354 WORD x, width, mousex;
1355 struct TextExtent tExtend;
1357 x = ad->mad_Box.Left + ad->mad_addleft;
1358 mousex = msg->imsg->MouseX - AlignOffset(obj, data);
1359 width = ad->mad_Box.Width - ad->mad_subwidth;
1361 SetFont(&data->rport, Font);
1363 switch(data->ClickCount)
1365 case 0:
1367 if(mousex < x)
1369 if(data->DisplayPos)
1370 data->DisplayPos--;
1371 data->BufferPos = data->DisplayPos;
1373 else
1375 if(mousex >= x+width)
1377 if(data->DisplayPos < StringLength)
1379 data->DisplayPos++;
1380 data->BufferPos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, ad->mad_Box.Width - ad->mad_subwidth, Font->tf_YSize);
1382 else
1384 data->BufferPos = StringLength;
1387 else
1389 WORD offset = mousex - x;
1391 /* if(offset < 0)
1392 data->BufferPos = 0;
1393 else
1394 */ data->BufferPos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, offset+1, Font->tf_YSize);
1397 data->BlockStop = data->BufferPos;
1398 MUI_Redraw(obj, MADF_DRAWUPDATE);
1400 break;
1402 case 1:
1404 WORD offset = mousex - x;
1405 WORD newpos = 0;
1407 if(mousex < x && data->DisplayPos)
1409 data->DisplayPos--;
1410 newpos = data->DisplayPos;
1412 else
1414 // offset -= AlignOffset(obj, data);
1415 if(offset > 0)
1416 newpos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, offset+1, Font->tf_YSize);
1419 if(newpos >= data->BlockStart)
1421 while(IsAlNum(data->locale, (UBYTE)*(data->Contents+newpos)))
1422 newpos++;
1424 else
1426 while(newpos > 0 && IsAlNum(data->locale, (UBYTE)*(data->Contents+newpos-1)))
1427 newpos--;
1430 if(data->BufferPos != newpos)
1432 data->BlockStop = data->BufferPos = newpos;
1433 MUI_Redraw(obj, MADF_DRAWUPDATE);
1436 break;
1443 RETURN(result);
1444 return result;