when dropping into user mode make sure endian is set
[AROS.git] / workbench / classes / zune / betterstring / mcc / HandleInput.c
bloba200734430efa4af17d2680293d25f725ff3e96f
1 /***************************************************************************
3 BetterString.mcc - A better String gadget MUI Custom Class
4 Copyright (C) 1997-2000 Allan Odgaard
5 Copyright (C) 2005-2013 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 ENTER();
77 FreeContentString(data->Undo);
79 if((data->Undo = AllocContentString(strlen(data->Contents)+1)) != NULL)
81 strlcpy(data->Undo, data->Contents, strlen(data->Contents)+1);
82 data->UndoPos = data->BufferPos;
83 clearFlag(data->Flags, FLG_RedoAvailable);
86 LEAVE();
89 static WORD AlignOffset(Object *obj, struct InstData *data)
91 WORD width = _mwidth(obj);
92 WORD offset = 0;
94 ENTER();
96 if(data->Alignment != MUIV_String_Format_Left)
98 STRPTR text = data->Contents+data->DisplayPos;
99 UWORD StrLength = strlen(text);
100 UWORD length, textlength, crsr_width;
101 struct TextExtent tExtend;
103 SetFont(&data->rport, _font(obj));
104 length = TextFit(&data->rport, text, StrLength, &tExtend, NULL, 1, width, _font(obj)->tf_YSize);
105 textlength = TextLength(&data->rport, text, length);
107 crsr_width = isFlagSet(data->Flags, FLG_Active) ? TextLength(&data->rport, (*(data->Contents+data->BufferPos) == '\0') ? (char *)"n" : (char *)(data->Contents+data->BufferPos), 1) : 0;
108 if(crsr_width && BlockEnabled(data) == FALSE && data->BufferPos == data->DisplayPos+StrLength)
110 textlength += crsr_width;
113 switch(data->Alignment)
115 case MUIV_String_Format_Center:
116 offset = (width - textlength)/2;
117 break;
118 case MUIV_String_Format_Right:
119 offset = (width - textlength);
120 break;
124 RETURN(offset);
125 return offset;
128 static BOOL Reject(UBYTE code, STRPTR reject)
130 BOOL rc = TRUE;
132 ENTER();
134 if(reject != NULL)
136 while(*reject != '\0')
138 if(code == *reject++)
140 rc = FALSE;
141 break;
146 RETURN(rc);
147 return rc;
150 static BOOL Accept(UBYTE code, STRPTR accept)
152 return(accept ? !Reject(code, accept) : TRUE);
155 static UWORD DecimalValue(UBYTE code)
157 if(code >= '0' && code <= '9')
158 return(code - '0');
159 if(code >= 'a' && code <= 'f')
160 return(code - 'a' + 10);
161 if(code >= 'A' && code <= 'F')
162 return(code - 'A' + 10);
164 return(0);
167 static BOOL IsHex(UBYTE code)
169 return(
170 (code >= '0' && code <= '9') ||
171 (code >= 'a' && code <= 'f') ||
172 (code >= 'A' && code <= 'F') ? TRUE : FALSE);
175 static LONG FindDigit(struct InstData *data)
177 WORD pos = data->BufferPos;
179 ENTER();
181 if(IsDigit(data->locale, *(data->Contents+pos)))
183 while(pos > 0 && IsDigit(data->locale, *(data->Contents+pos-1)))
184 pos--;
186 else
188 while(*(data->Contents+pos) != '\0' && !IsDigit(data->locale, *(data->Contents+pos)))
189 pos++;
192 if(*(data->Contents+pos) == '\0')
194 pos = data->BufferPos;
195 while(pos && !IsDigit(data->locale, *(data->Contents+pos)))
196 pos--;
198 while(pos > 0 && IsDigit(data->locale, *(data->Contents+pos-1)))
199 pos--;
201 if(!pos && !IsDigit(data->locale, *data->Contents))
203 pos = -1;
207 RETURN(pos);
208 return pos;
211 static UWORD NextWord(STRPTR text, UWORD x, struct Locale *locale)
213 ENTER();
215 while(IsAlNum(locale, (UBYTE)text[x]))
216 x++;
218 while(text[x] != '\0' && !IsAlNum(locale, (UBYTE)text[x]))
219 x++;
221 RETURN(x);
222 return x;
225 static UWORD PrevWord(STRPTR text, UWORD x, struct Locale *locale)
227 ENTER();
229 if(x)
230 x--;
232 while(x && !IsAlNum(locale, (UBYTE)text[x]))
233 x--;
235 while(x > 0 && IsAlNum(locale, (UBYTE)text[x-1]))
236 x--;
238 RETURN(x);
239 return x;
242 void DeleteBlock(struct InstData *data)
244 ENTER();
246 AddToUndo(data);
248 if(BlockEnabled(data) == TRUE)
250 UWORD Blk_Start, Blk_Width;
252 Blk_Start = (data->BlockStart < data->BlockStop) ? data->BlockStart : data->BlockStop;
253 Blk_Width = abs(data->BlockStop-data->BlockStart);
254 memmove(data->Contents+Blk_Start, data->Contents+Blk_Start+Blk_Width, strlen(data->Contents+Blk_Start+Blk_Width)+1);
255 data->BufferPos = Blk_Start;
258 LEAVE();
261 static void CopyBlock(struct InstData *data)
263 ENTER();
265 if(isFlagClear(data->Flags, FLG_Secret))
267 UWORD Blk_Start, Blk_Width;
268 //struct IFFHandle *iff;
270 if(BlockEnabled(data) == TRUE)
272 Blk_Start = (data->BlockStart < data->BlockStop) ? data->BlockStart : data->BlockStop;
273 Blk_Width = abs(data->BlockStop-data->BlockStart);
275 else
277 Blk_Start = 0;
278 Blk_Width = strlen(data->Contents);
281 StringToClipboard(&data->Contents[Blk_Start], Blk_Width);
284 LEAVE();
287 static void CutBlock(struct InstData *data)
289 ENTER();
291 AddToUndo(data);
293 if(BlockEnabled(data) == TRUE)
295 CopyBlock(data);
296 DeleteBlock(data);
297 clearFlag(data->Flags, FLG_BlockEnabled);
299 else
301 *data->Contents = '\0';
302 data->BufferPos = 0;
305 LEAVE();
308 static void Paste(struct InstData *data)
310 STRPTR str;
311 LONG length;
313 ENTER();
315 if(ClipboardToString(&str, &length) == TRUE)
317 // clear the selection
318 DeleteBlock(data);
320 if(data->MaxLength != 0 && strlen(data->Contents) + length > (ULONG)data->MaxLength - 1)
322 DisplayBeep(NULL);
323 length = data->MaxLength - 1 - strlen(data->Contents);
326 if(ExpandContentString(&data->Contents, length) == TRUE)
328 memmove(data->Contents + data->BufferPos + length, data->Contents + data->BufferPos, strlen(data->Contents + data->BufferPos)+1);
329 memcpy(data->Contents + data->BufferPos, str, length);
330 data->BufferPos += length;
332 else
334 E(DBF_ALWAYS, "content expansion by %ld bytes failed", length);
337 SharedPoolFree(str);
340 LEAVE();
343 static void UndoRedo(struct InstData *data)
345 STRPTR oldcontents;
346 UWORD oldpos;
348 ENTER();
350 // swap content and undo pointers
351 oldcontents = data->Contents;
352 data->Contents = data->Undo;
353 data->Undo = oldcontents;
355 if(isFlagSet(data->Flags, FLG_RedoAvailable))
356 clearFlag(data->Flags, FLG_RedoAvailable);
357 else
358 setFlag(data->Flags, FLG_RedoAvailable);
360 clearFlag(data->Flags, FLG_BlockEnabled);
362 // swap content and undo positions
363 oldpos = data->BufferPos;
364 data->BufferPos = data->UndoPos;
365 data->UndoPos = oldpos;
367 LEAVE();
370 static void RevertToOriginal(struct InstData *data)
372 STRPTR oldcontents;
374 ENTER();
376 // swap content and original pointers
377 oldcontents = data->Contents;
378 data->Contents = data->Original;
379 data->Original = oldcontents;
381 setFlag(data->Flags, FLG_Original);
382 clearFlag(data->Flags, FLG_BlockEnabled);
383 data->BufferPos = strlen(data->Contents);
385 LEAVE();
388 static BOOL ToggleCaseChar(struct InstData *data)
390 UBYTE key = *(data->Contents+data->BufferPos);
391 BOOL result = FALSE;
393 ENTER();
395 if(data->BufferPos < strlen(data->Contents))
397 *(data->Contents+data->BufferPos) = IsLower(data->locale, key) ? ConvToUpper(data->locale, key) : ConvToLower(data->locale, key);
398 data->BufferPos++;
399 result = TRUE;
402 RETURN(result);
403 return result;
406 static BOOL ToggleCaseWord(struct InstData *data)
408 UWORD Stop = NextWord(data->Contents, data->BufferPos, data->locale);
409 BOOL result = FALSE;
411 ENTER();
413 while(data->BufferPos < Stop)
415 UBYTE key = *(data->Contents+data->BufferPos);
417 *(data->Contents+data->BufferPos) = IsLower(data->locale, key) ? ConvToUpper(data->locale, key) : ConvToLower(data->locale, key);
418 data->BufferPos++;
419 result = TRUE;
422 RETURN(result);
423 return result;
426 static BOOL IncreaseNearNumber(struct InstData *data)
428 LONG pos;
429 BOOL result = FALSE;
431 ENTER();
433 if((pos = FindDigit(data)) >= 0)
435 LONG cut;
436 ULONG res;
438 if((cut = StrToLong(data->Contents+pos, (LONG *)&res)))
440 char string[12];
441 char format[12];
443 res++;
444 MySPrintf(format, "%%0%ldlu", cut);
445 MySPrintf(string, format, res);
446 Overwrite(string, pos, cut, data);
447 result = TRUE;
451 RETURN(result);
452 return result;
455 static BOOL DecreaseNearNumber(struct InstData *data)
457 LONG pos;
458 BOOL result = FALSE;
460 ENTER();
462 if((pos = FindDigit(data)) >= 0)
464 LONG cut;
465 ULONG res;
467 if((cut = StrToLong(data->Contents+pos, (LONG *)&res)))
469 if(res)
471 char *format;
472 char string[12];
473 char format2[12];
475 format = &format2[0];
476 MySPrintf(format, "%%0%ldlu", cut);
477 res--;
478 MySPrintf(string, format, res);
479 Overwrite(string, pos, cut, data);
480 result = TRUE;
485 RETURN(result);
486 return result;
489 static BOOL HexToDec(struct InstData *data)
491 LONG cut = 0;
492 UWORD pos = data->BufferPos;
493 ULONG res = 0;
494 BOOL result = FALSE;
496 ENTER();
498 while(pos && IsHex(*(data->Contents+pos-1)))
499 pos--;
501 while(IsHex(*(data->Contents+pos+cut)))
503 res = (result << 4) + DecimalValue(*(data->Contents+pos+cut));
504 cut++;
507 if(cut)
509 char string[12];
511 MySPrintf(string, "%lu", res);
512 Overwrite(string, pos, cut, data);
513 result = TRUE;
516 RETURN(result);
517 return result;
520 static BOOL DecToHex(struct InstData *data)
522 LONG pos;
523 BOOL result = FALSE;
525 ENTER();
527 if((pos = FindDigit(data)) >= 0)
529 LONG cut;
530 ULONG res;
532 if((cut = StrToLong(data->Contents+pos, (LONG *)&res)))
534 const char *format = "%lx";
535 char string[12];
537 MySPrintf(string, format, res);
538 Overwrite(string, pos, cut, data);
539 result = TRUE;
543 RETURN(result);
544 return result;
547 void TriggerNotify(struct IClass *cl, Object *obj)
549 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
550 struct TagItem tags[] =
552 { MUIA_String_Contents, (IPTR)data->Contents },
553 { TAG_DONE, 0 }
556 ENTER();
558 // pass the attribute directly to our superclass as our own
559 // handling of OM_SET will suppress the notification in case
560 // the contents did not change
561 if(isFlagClear(data->Flags, FLG_NoNotify))
563 DoSuperMethod(cl, obj, OM_SET, tags, NULL);
564 clearFlag(data->Flags, FLG_NotifyQueued);
566 else
567 setFlag(data->Flags, FLG_NotifyQueued);
569 LEAVE();
572 ULONG ConvertKey(struct IntuiMessage *imsg)
574 struct InputEvent event;
575 unsigned char code = 0;
577 ENTER();
579 event.ie_NextEvent = NULL;
580 event.ie_Class = IECLASS_RAWKEY;
581 event.ie_SubClass = 0;
582 event.ie_Code = imsg->Code;
583 event.ie_Qualifier = imsg->Qualifier;
584 event.ie_EventAddress = (APTR *) *((IPTR *)imsg->IAddress);
586 MapRawKey(&event, (STRPTR)&code, 1, NULL);
588 RETURN(code);
589 return code;
592 IPTR mDoAction(struct IClass *cl, Object *obj, struct MUIP_BetterString_DoAction *msg)
594 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
595 IPTR result = FALSE;
596 BOOL edited = FALSE;
598 ENTER();
600 D(DBF_INPUT, "DoAction(%ld)");
602 switch(msg->action)
604 case MUIV_BetterString_DoAction_Cut:
606 CutBlock(data);
607 edited = TRUE;
608 result = TRUE;
610 break;
612 case MUIV_BetterString_DoAction_Copy:
614 CopyBlock(data);
615 clearFlag(data->Flags, FLG_BlockEnabled);
616 result = TRUE;
618 break;
620 case MUIV_BetterString_DoAction_Paste:
622 Paste(data);
623 clearFlag(data->Flags, FLG_BlockEnabled);
624 edited = TRUE;
625 result = TRUE;
627 break;
629 case MUIV_BetterString_DoAction_Delete:
631 DeleteBlock(data);
632 clearFlag(data->Flags, FLG_BlockEnabled);
633 edited = TRUE;
634 result = TRUE;
636 break;
638 case MUIV_BetterString_DoAction_SelectAll:
640 data->BlockStart = 0;
641 data->BlockStop = strlen(data->Contents);
642 setFlag(data->Flags, FLG_BlockEnabled);
643 result = TRUE;
645 break;
647 case MUIV_BetterString_DoAction_SelectNone:
649 clearFlag(data->Flags, FLG_BlockEnabled);
650 result = TRUE;
652 break;
654 case MUIV_BetterString_DoAction_Undo:
655 case MUIV_BetterString_DoAction_Redo:
657 if(data->Undo &&
658 (((msg->action == MUIV_BetterString_DoAction_Redo) && isFlagSet(data->Flags, FLG_RedoAvailable)) ||
659 ((msg->action == MUIV_BetterString_DoAction_Undo) && isFlagClear(data->Flags, FLG_RedoAvailable))))
661 UndoRedo(data);
662 clearFlag(data->Flags, FLG_BlockEnabled);
663 edited = TRUE;
664 result = TRUE;
667 break;
669 case MUIV_BetterString_DoAction_Revert:
671 RevertToOriginal(data);
672 clearFlag(data->Flags, FLG_BlockEnabled);
673 edited = TRUE;
674 result = TRUE;
676 break;
678 case MUIV_BetterString_DoAction_ToggleCase:
680 edited = result = ToggleCaseChar(data);
681 clearFlag(data->Flags, FLG_BlockEnabled);
683 break;
685 case MUIV_BetterString_DoAction_ToggleCaseWord:
687 edited = result = ToggleCaseWord(data);
688 clearFlag(data->Flags, FLG_BlockEnabled);
690 break;
692 case MUIV_BetterString_DoAction_IncreaseNum:
694 edited = result = IncreaseNearNumber(data);
695 clearFlag(data->Flags, FLG_BlockEnabled);
697 break;
699 case MUIV_BetterString_DoAction_DecreaseNum:
701 edited = result = DecreaseNearNumber(data);
702 clearFlag(data->Flags, FLG_BlockEnabled);
704 break;
706 case MUIV_BetterString_DoAction_HexToDec:
708 edited = result = HexToDec(data);
709 clearFlag(data->Flags, FLG_BlockEnabled);
711 break;
713 case MUIV_BetterString_DoAction_DecToHex:
715 edited = result = DecToHex(data);
716 clearFlag(data->Flags, FLG_BlockEnabled);
718 break;
720 case MUIV_BetterString_DoAction_NextFileComp:
722 edited = result = FileNameComplete(obj, FALSE, data);
723 clearFlag(data->Flags, FLG_BlockEnabled);
725 break;
727 case MUIV_BetterString_DoAction_PrevFileComp:
729 edited = result = FileNameComplete(obj, TRUE, data);
730 clearFlag(data->Flags, FLG_BlockEnabled);
732 break;
735 MUI_Redraw(obj, MADF_DRAWUPDATE);
737 if(edited == TRUE)
738 TriggerNotify(cl, obj);
740 RETURN(result);
741 return result;
744 IPTR mHandleInput(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
746 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
747 IPTR result = 0;
748 BOOL movement = FALSE;
749 BOOL edited = FALSE;
750 BOOL FNC = FALSE;
752 ENTER();
754 // handle the standard MUI keys first
755 if(msg->muikey != MUIKEY_NONE)
757 switch(msg->muikey)
759 case MUIKEY_UP:
761 if(data->KeyUpFocus != NULL && _win(obj) != NULL)
763 set(_win(obj), MUIA_Window_ActiveObject, data->KeyUpFocus);
764 result = MUI_EventHandlerRC_Eat;
767 break;
769 case MUIKEY_DOWN:
771 if(data->KeyDownFocus != NULL && _win(obj) != NULL)
773 set(_win(obj), MUIA_Window_ActiveObject, data->KeyDownFocus);
774 result = MUI_EventHandlerRC_Eat;
777 break;
779 case MUIKEY_COPY:
781 CopyBlock(data);
782 clearFlag(data->Flags, FLG_BlockEnabled);
783 MUI_Redraw(obj, MADF_DRAWUPDATE);
784 result = MUI_EventHandlerRC_Eat;
786 break;
788 case MUIKEY_CUT:
790 CutBlock(data);
791 clearFlag(data->Flags, FLG_BlockEnabled);
792 MUI_Redraw(obj, MADF_DRAWUPDATE);
793 TriggerNotify(cl, obj);
794 result = MUI_EventHandlerRC_Eat;
796 break;
798 case MUIKEY_PASTE:
800 Paste(data);
801 clearFlag(data->Flags, FLG_BlockEnabled);
802 MUI_Redraw(obj, MADF_DRAWUPDATE);
803 TriggerNotify(cl, obj);
804 result = MUI_EventHandlerRC_Eat;
806 break;
808 case MUIKEY_UNDO:
809 case MUIKEY_REDO:
811 if(data->Undo && ((msg->muikey == MUIKEY_REDO && isFlagSet(data->Flags, FLG_RedoAvailable)) ||
812 (msg->muikey == MUIKEY_UNDO && isFlagClear(data->Flags, FLG_RedoAvailable))))
814 UndoRedo(data);
815 clearFlag(data->Flags, FLG_BlockEnabled);
816 MUI_Redraw(obj, MADF_DRAWUPDATE);
817 TriggerNotify(cl, obj);
818 result = MUI_EventHandlerRC_Eat;
820 else
821 DisplayBeep(NULL);
823 break;
827 if(result == 0 && msg->imsg != NULL)
829 ULONG StringLength = strlen(data->Contents);
831 if(msg->imsg->Class == IDCMP_RAWKEY &&
832 // msg->imsg->Code >= IECODE_KEY_CODE_FIRST &&
833 msg->imsg->Code <= IECODE_KEY_CODE_LAST)
835 if(isFlagSet(data->Flags, FLG_Active))
837 BOOL input = TRUE;
839 if(isFlagClear(data->Flags, FLG_BlockEnabled))
840 data->BlockStart = data->BufferPos;
842 if(isFlagSet(data->Flags, FLG_NoInput))
844 switch(msg->imsg->Code)
846 case RAWKEY_TAB:
847 case RAWKEY_BACKSPACE:
848 case RAWKEY_DEL:
849 input = FALSE;
850 break;
854 if(input == TRUE)
856 switch(msg->imsg->Code)
858 // Tab
859 case RAWKEY_TAB:
861 if(isFlagSet(data->Flags, FLG_NoShortcuts) || isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_RCOMMAND))
863 RETURN(0);
864 return 0;
867 if(!(edited = FileNameComplete(obj, isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT), data)))
868 DisplayBeep(NULL);
870 FNC = TRUE;
872 break;
874 // Right
875 case RAWKEY_CRSRRIGHT:
877 if(data->BufferPos < StringLength)
879 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT))
881 data->BufferPos = StringLength;
883 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
885 data->BufferPos = NextWord(data->Contents, data->BufferPos, data->locale);
887 else if(BlockEnabled(data) && isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
889 data->BufferPos = MAX(data->BlockStart, data->BlockStop);
891 else
893 data->BufferPos++;
896 movement = TRUE;
898 break;
900 // Left
901 case RAWKEY_CRSRLEFT:
903 if(data->BufferPos)
905 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT))
907 data->BufferPos = 0;
909 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
911 data->BufferPos = PrevWord(data->Contents, data->BufferPos, data->locale);
913 else
915 if(BlockEnabled(data) && isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
916 data->BufferPos = MIN(data->BlockStart, data->BlockStop);
918 if(data->BufferPos)
919 data->BufferPos--;
922 movement = TRUE;
924 break;
926 // Backspace
927 case RAWKEY_BACKSPACE:
929 if(BlockEnabled(data))
931 DeleteBlock(data);
933 else
935 if(data->BufferPos != 0)
937 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT|IEQUALIFIER_CONTROL))
939 AddToUndo(data);
940 memmove(data->Contents, data->Contents+data->BufferPos, strlen(data->Contents+data->BufferPos)+1);
941 data->BufferPos = 0;
943 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
945 UWORD NewPos = PrevWord(data->Contents, data->BufferPos, data->locale);
947 AddToUndo(data);
948 memmove(data->Contents+NewPos, data->Contents+data->BufferPos, strlen(data->Contents+data->BufferPos)+1);
949 data->BufferPos = NewPos;
951 else
953 memmove(data->Contents+data->BufferPos-1, data->Contents+data->BufferPos, strlen(data->Contents+data->BufferPos)+1);
954 data->BufferPos--;
958 edited = TRUE;
960 break;
962 // Delete
963 case RAWKEY_DEL:
965 if(BlockEnabled(data))
967 DeleteBlock(data);
969 else
971 if(data->BufferPos < StringLength)
973 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT) || isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
975 AddToUndo(data);
976 *(data->Contents+data->BufferPos) = '\0';
978 else if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RALT|IEQUALIFIER_LALT))
980 STRPTR start = data->Contents+NextWord(data->Contents, data->BufferPos, data->locale);
982 AddToUndo(data);
983 memmove(data->Contents+data->BufferPos, start, strlen(start)+1);
985 else
987 memmove(data->Contents+data->BufferPos, data->Contents+data->BufferPos+1, strlen(data->Contents+data->BufferPos+1)+1);
991 edited = TRUE;
993 break;
995 // Home
996 case RAWKEY_HOME:
998 if(data->BufferPos)
999 data->BufferPos = 0;
1001 movement = TRUE;
1003 break;
1005 // End
1006 case RAWKEY_END:
1008 if(data->BufferPos < StringLength)
1009 data->BufferPos = StringLength;
1011 movement = TRUE;
1013 break;
1015 default:
1017 if(data->Popup && msg->muikey == MUIKEY_POPUP)
1019 DoMethod(data->Popup, MUIM_Popstring_Open);
1021 else
1023 UBYTE code = ConvertKey(msg->imsg);
1025 if((((code >= 32 && code <= 126) || code >= 160) && isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_RCOMMAND)) ||
1026 (code && isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL)))
1028 if(isFlagClear(data->Flags, FLG_NoInput))
1030 DeleteBlock(data);
1032 if((data->MaxLength == 0 || (ULONG)data->MaxLength-1 > strlen(data->Contents)) &&
1033 Accept(code, data->Accept) && Reject(code, data->Reject))
1035 if(ExpandContentString(&data->Contents, 1) == TRUE)
1037 memmove(data->Contents+data->BufferPos+1, data->Contents+data->BufferPos, strlen(data->Contents + data->BufferPos)+1);
1038 *(data->Contents+data->BufferPos) = code;
1039 data->BufferPos++;
1040 edited = TRUE;
1042 else
1044 E(DBF_ALWAYS, "content expansion by %ld bytes failed", 1);
1047 else
1049 DisplayBeep(NULL);
1053 else
1055 // if this betterstring object is a read-only object
1056 // we only accept a view characters or otherwise reject
1057 // the rawkey operation
1058 if(isFlagSet(data->Flags, FLG_NoInput))
1060 switch(code)
1062 case '\r':
1063 case 'c':
1064 break;
1066 default:
1067 RETURN(MUI_EventHandlerRC_Eat);
1068 return MUI_EventHandlerRC_Eat;
1069 break;
1073 // check if the user pressed return and if he has activated AdvanceOnCr or not
1074 if(code == '\r')
1076 if(isFlagClear(data->Flags, FLG_StayActive))
1078 ULONG active;
1080 if(isFlagSet(data->Flags, FLG_AdvanceOnCr))
1082 if(isAnyFlagSet(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT))
1083 active = MUIV_Window_ActiveObject_Prev;
1084 else
1085 active = MUIV_Window_ActiveObject_Next;
1087 else
1088 active = MUIV_Window_ActiveObject_None;
1090 set(_win(obj), MUIA_Window_ActiveObject, active);
1093 set(obj, MUIA_String_Acknowledge, data->Contents);
1095 RETURN(MUI_EventHandlerRC_Eat);
1096 return MUI_EventHandlerRC_Eat;
1099 // see if we should skip the default shorcuts or not
1100 if(isFlagClear(data->Flags, FLG_NoShortcuts))
1102 // depending on the pressed key code
1103 // we perform different actions.
1104 switch(code)
1106 case 'g':
1108 edited = ToggleCaseChar(data);
1110 break;
1112 case 'G':
1114 edited = ToggleCaseWord(data);
1116 break;
1118 case 'c':
1119 CopyBlock(data);
1120 break;
1122 case 'x':
1123 CutBlock(data);
1124 edited = TRUE;
1125 break;
1127 case 'v':
1128 Paste(data);
1129 edited = TRUE;
1130 break;
1132 case 'i':
1134 if((edited = IncreaseNearNumber(data)) == FALSE)
1135 DisplayBeep(NULL);
1137 break;
1139 case 'd':
1141 if((edited = DecreaseNearNumber(data)) == FALSE)
1142 DisplayBeep(NULL);
1144 break;
1146 case '#':
1148 if((edited = HexToDec(data)) == FALSE)
1149 DisplayBeep(NULL);
1151 break;
1153 case '$':
1155 if((edited = DecToHex(data)) == FALSE)
1156 DisplayBeep(NULL);
1158 break;
1160 case 'q':
1162 RevertToOriginal(data);
1163 edited = TRUE;
1165 break;
1167 case 'z':
1168 case 'Z':
1170 if(data->Undo && (((code == 'Z') && isFlagSet(data->Flags, FLG_RedoAvailable)) ||
1171 ((code == 'z') && isFlagClear(data->Flags, FLG_RedoAvailable))))
1173 UndoRedo(data);
1174 edited = TRUE;
1176 else
1177 DisplayBeep(NULL);
1179 break;
1181 default:
1182 clearFlag(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT);
1183 RETURN(0);
1184 return 0;
1187 else
1189 clearFlag(msg->imsg->Qualifier, IEQUALIFIER_RSHIFT);
1190 RETURN(0);
1191 return 0;
1196 break;
1200 if(data->FNCBuffer && !FNC)
1202 struct FNCData *fncbuffer = data->FNCBuffer, *fncframe;
1204 while(fncbuffer)
1206 fncframe = fncbuffer;
1207 fncbuffer = fncbuffer->next;
1208 SharedPoolFree(fncframe);
1210 data->FNCBuffer = NULL;
1213 if(movement && isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
1214 setFlag(data->Flags, FLG_BlockEnabled);
1215 else
1216 clearFlag(data->Flags, FLG_BlockEnabled);
1218 if(isFlagSet(data->Flags, FLG_BlockEnabled))
1219 data->BlockStop = data->BufferPos;
1221 MUI_Redraw(obj, MADF_DRAWUPDATE);
1223 if(edited == TRUE)
1224 TriggerNotify(cl, obj);
1226 result = MUI_EventHandlerRC_Eat;
1228 else
1230 if(data->CtrlChar && ConvertKey(msg->imsg) == data->CtrlChar)
1232 set(_win(obj), MUIA_Window_ActiveObject, obj);
1233 result = MUI_EventHandlerRC_Eat;
1237 else
1239 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);
1241 // check if the user pressed the TAB key for cycling to the next
1242 // mui object and if this object is part of the cyclechain
1243 if(msg->imsg->Class == IDCMP_RAWKEY && isFlagSet(data->Flags, FLG_Active) && isFlagSet(data->Flags, FLG_FreshActive))
1245 // clear the FreshActive flag
1246 clearFlag(data->Flags, FLG_FreshActive);
1247 // no need to do an DoAction(SelectAll), because this effectively has been
1248 // done during MUIM_GoActive already
1251 // we check if this is a mousemove input message and if
1252 // so we check whether the mouse is currently over our
1253 // texteditor object or not.
1254 if(msg->imsg->Class == IDCMP_MOUSEMOVE)
1256 BOOL isOverObject = FALSE;
1258 D(DBF_INPUT, "IDCMP_MOUSEMOVE");
1259 if(_isinobject(obj, msg->imsg->MouseX, msg->imsg->MouseY))
1261 #if defined(__MORPHOS__)
1262 if(IS_MORPHOS2)
1263 isOverObject = TRUE;
1264 #endif
1266 if(isOverObject == FALSE)
1268 struct Layer_Info *li = &(_screen(obj)->LayerInfo);
1269 struct Layer *layer;
1271 // get the layer that belongs to the current mouse coordinates
1272 LockLayerInfo(li);
1273 layer = WhichLayer(li, _window(obj)->LeftEdge + msg->imsg->MouseX, _window(obj)->TopEdge + msg->imsg->MouseY);
1274 UnlockLayerInfo(li);
1276 // if the mouse is currently over the object and over the object's
1277 // window we go and change the pointer to show the selection pointer
1278 if(layer != NULL && layer->Window == _window(obj))
1279 isOverObject = TRUE;
1283 if(isOverObject == TRUE)
1284 ShowSelectPointer(obj, data);
1285 else
1286 HideSelectPointer(obj, data);
1288 else if(msg->imsg->Class == IDCMP_MOUSEBUTTONS)
1290 D(DBF_INPUT, "IDCMP_MOUSEBUTTONS");
1291 if(msg->imsg->Code == (IECODE_LBUTTON | IECODE_UP_PREFIX))
1293 // forget the pressed mouse button
1294 clearFlag(data->Flags, FLG_MouseButtonDown);
1296 if(isAnyFlagSet(data->ehnode.ehn_Events, /*IDCMP_MOUSEMOVE|*/IDCMP_INTUITICKS))
1298 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
1299 // clearFlag(data->ehnode.ehn_Events, IDCMP_MOUSEMOVE);
1300 clearFlag(data->ehnode.ehn_Events, IDCMP_INTUITICKS);
1301 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
1304 // make sure to select the whole content in case the object was freshly activated
1305 // and the user just released the mousebutton (no matter if inside or outside)
1306 if(isFlagSet(data->Flags, FLG_FreshActive) && BlockEnabled(data) == FALSE &&
1307 ((data->SelectOnActive == TRUE && isFlagClear(data->Flags, FLG_ForceSelectOff)) || isFlagSet(data->Flags, FLG_ForceSelectOn)))
1309 DoMethod(obj, MUIM_BetterString_DoAction, MUIV_BetterString_DoAction_SelectAll);
1312 #ifdef ALLOW_OUTSIDE_MARKING
1313 if(isFlagSet(data->Flags, FLG_Active) && isFlagSet(data->Flags, FLG_DragOutside))
1315 Object *active;
1316 get(_win(obj), MUIA_Window_ActiveObject, &active);
1317 if(obj != active)
1318 E(DBF_STARTUP, "MUI error: %lx, %lx", active, obj);
1320 WORD x = _mleft(obj);
1321 WORD y = _mtop(obj);
1322 WORD width = _mwidth(obj);
1323 WORD height = _font(obj)->tf_YSize;
1325 if(!(msg->imsg->MouseX >= x && msg->imsg->MouseX < x+width && msg->imsg->MouseY >= y && msg->imsg->MouseY < y+height))
1327 D(DBF_STARTUP, "Detected LMB+up outside (drag: %ld)", isFlagSet(data->Flags, FLG_DragOutside));
1328 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
1331 #endif
1333 // clear the FreshActive flag
1334 clearFlag(data->Flags, FLG_FreshActive);
1336 else if(msg->imsg->Code == IECODE_LBUTTON)
1338 WORD x = _mleft(obj);
1339 WORD y = _mtop(obj);
1340 WORD width = _mwidth(obj);
1341 WORD height = _font(obj)->tf_YSize;
1343 // remember the pressed mouse button
1344 setFlag(data->Flags, FLG_MouseButtonDown);
1346 if(msg->imsg->MouseX >= x && msg->imsg->MouseX < x+width && msg->imsg->MouseY >= y && msg->imsg->MouseY < y+height)
1348 WORD offset = msg->imsg->MouseX - x;
1349 struct TextExtent tExtend;
1351 offset -= AlignOffset(obj, data);
1353 SetFont(&data->rport, _font(obj));
1354 data->BufferPos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, offset+1, _font(obj)->tf_YSize);
1356 if(data->BufferPos == data->BufferLastPos &&
1357 DoubleClick(data->StartSecs, data->StartMicros, msg->imsg->Seconds, msg->imsg->Micros))
1359 // on a secret gadget we skip clickcount step 1 as
1360 // it might be misused to guess the words in the gadget.
1361 if(isFlagSet(data->Flags, FLG_Secret) && data->ClickCount == 0)
1362 data->ClickCount++;
1364 data->ClickCount++;
1366 else if((data->SelectOnActive == TRUE && isFlagClear(data->Flags, FLG_ForceSelectOff)) ||
1367 isFlagSet(data->Flags, FLG_ForceSelectOn))
1369 // special handling for the "select on active" feature
1370 // this makes it possible to start a selection upon the first click within
1371 // the object *and* a full selection
1372 data->ClickCount = 3;
1374 else
1376 data->ClickCount = 0;
1379 // lets save the current bufferpos to the lastpos variable
1380 data->BufferLastPos = data->BufferPos;
1382 data->StartSecs = msg->imsg->Seconds;
1383 data->StartMicros = msg->imsg->Micros;
1385 switch(data->ClickCount)
1387 case 0:
1389 if(isFlagClear(data->Flags, FLG_BlockEnabled) || isFlagClear(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
1390 data->BlockStart = data->BufferPos;
1392 break;
1394 case 1:
1396 if(data->Contents[data->BufferPos] != '\0')
1398 UWORD start = data->BufferPos;
1399 UWORD stop = data->BufferPos;
1400 ULONG alpha = IsAlNum(data->locale, (UBYTE)*(data->Contents+data->BufferPos));
1402 while(start > 0 && alpha == (ULONG)IsAlNum(data->locale, (UBYTE)*(data->Contents+start-1)))
1403 start--;
1405 while(alpha == (ULONG)IsAlNum(data->locale, (UBYTE)*(data->Contents+stop)) && *(data->Contents+stop) != '\0')
1406 stop++;
1408 data->BlockStart = start;
1409 data->BufferPos = stop;
1412 break;
1414 case 2:
1416 data->BlockStart = 0;
1417 data->BufferPos = strlen(data->Contents);
1419 break;
1421 case 3:
1423 data->BlockStart = data->BufferPos;
1424 data->ClickCount = 0;
1426 break;
1428 data->BlockStop = data->BufferPos;
1429 setFlag(data->Flags, FLG_BlockEnabled);
1431 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
1432 // setFlag(data->ehnode.ehn_Events, IDCMP_MOUSEMOVE);
1433 setFlag(data->ehnode.ehn_Events, IDCMP_INTUITICKS);
1434 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
1436 if(isFlagSet(data->Flags, FLG_Active))
1437 MUI_Redraw(obj, MADF_DRAWUPDATE);
1438 else
1440 // set the active flag now already
1441 // this will be checked in MUIM_GoActive to distinguish between
1442 // activation by mouse and by keyboard/application
1443 setFlag(data->Flags, FLG_Active);
1444 set(_win(obj), MUIA_Window_ActiveObject, obj);
1447 result = MUI_EventHandlerRC_Eat;
1449 else
1451 data->ClickCount = 0;
1452 if(isFlagSet(data->Flags, FLG_Active) && isFlagClear(data->Flags, FLG_StayActive))
1454 #ifdef ALLOW_OUTSIDE_MARKING
1455 D(DBF_STARTUP, "Clicked outside gadget");
1456 setFlag(data->Flags, FLG_DragOutside);
1458 // DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
1459 // data->ehnode.ehn_Events |= IDCMP_MOUSEMOVE;
1460 // DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
1461 #else
1462 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
1463 #endif
1468 else
1470 #ifdef ALLOW_OUTSIDE_MARKING
1471 if(msg->imsg->Class == IDCMP_MOUSEMOVE)
1473 clearFlag(data->Flags, FLG_DragOutside);
1474 D(DBF_STARTUP, "Detected drag");
1476 #endif
1477 if((/*msg->imsg->Class == IDCMP_MOUSEMOVE ||*/ msg->imsg->Class == IDCMP_INTUITICKS) && isFlagSet(data->Flags, FLG_Active))
1479 WORD x, width, mousex;
1480 struct TextExtent tExtend;
1482 x = _mleft(obj);
1483 mousex = msg->imsg->MouseX - AlignOffset(obj, data);
1484 width = _mwidth(obj);
1486 SetFont(&data->rport, _font(obj));
1488 switch(data->ClickCount)
1490 case 0:
1492 if(mousex < x)
1494 if(data->DisplayPos)
1495 data->DisplayPos--;
1496 data->BufferPos = data->DisplayPos;
1498 else
1500 if(mousex >= x+width)
1502 if(data->DisplayPos < StringLength)
1504 data->DisplayPos++;
1505 data->BufferPos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, _mwidth(obj), _font(obj)->tf_YSize);
1507 else
1509 data->BufferPos = StringLength;
1512 else
1514 WORD offset = mousex - x;
1516 /* if(offset < 0)
1517 data->BufferPos = 0;
1518 else
1519 */ data->BufferPos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, offset+1, _font(obj)->tf_YSize);
1522 data->BlockStop = data->BufferPos;
1523 MUI_Redraw(obj, MADF_DRAWUPDATE);
1525 break;
1527 case 1:
1529 WORD offset = mousex - x;
1530 WORD newpos = 0;
1532 if(mousex < x && data->DisplayPos)
1534 data->DisplayPos--;
1535 newpos = data->DisplayPos;
1537 else
1539 // offset -= AlignOffset(obj, data);
1540 if(offset > 0)
1541 newpos = data->DisplayPos + TextFit(&data->rport, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, &tExtend, NULL, 1, offset+1, _font(obj)->tf_YSize);
1544 if(newpos >= data->BlockStart)
1546 while(IsAlNum(data->locale, (UBYTE)*(data->Contents+newpos)))
1547 newpos++;
1549 else
1551 while(newpos > 0 && IsAlNum(data->locale, (UBYTE)*(data->Contents+newpos-1)))
1552 newpos--;
1555 if(data->BufferPos != newpos)
1557 data->BlockStop = data->BufferPos = newpos;
1558 MUI_Redraw(obj, MADF_DRAWUPDATE);
1561 break;
1568 RETURN(result);
1569 return result;
1572 IPTR mInsert(struct IClass *cl, Object *obj, struct MUIP_BetterString_Insert *msg)
1574 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
1575 UWORD pos;
1577 ENTER();
1579 switch(msg->pos)
1582 case MUIV_BetterString_Insert_StartOfString:
1583 pos = 0;
1584 break;
1587 case MUIV_BetterString_Insert_EndOfString:
1588 pos = strlen(data->Contents);
1589 break;
1591 case MUIV_BetterString_Insert_BufferPos:
1592 pos = data->BufferPos;
1593 break;
1595 default:
1596 pos = msg->pos;
1597 break;
1600 Overwrite(msg->text, pos, 0, data);
1601 clearFlag(data->Flags, FLG_BlockEnabled);
1602 MUI_Redraw(obj, MADF_DRAWUPDATE);
1603 // trigger a notification as we just changed the contents
1604 TriggerNotify(cl, obj);
1606 RETURN(TRUE);
1607 return TRUE;