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/
21 ***************************************************************************/
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>
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
, ...)
49 RawDoFmt(fmt
, VA_ARG(args
, void *), NULL
, (STRPTR
)buf
);
54 #elif defined(__AROS__)
55 #define MySPrintf __sprintf /* from amiga lib */
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 :-)
66 RawDoFmt(fmt
, args
, (void (*)(void))PutCharProc
, (STRPTR
)buf
);
73 static void AddToUndo(struct InstData
*data
)
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
;
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;
115 case MUIV_String_Format_Right
:
116 offset
= (width
- textlength
);
123 static BOOL
Reject(UBYTE code
, STRPTR reject
)
129 if(code
== *reject
++)
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')
145 if(code
>= 'a' && code
<= 'f')
146 return(code
- 'a' + 10);
147 if(code
>= 'A' && code
<= 'F')
148 return(code
- 'A' + 10);
153 static BOOL
IsHex(UBYTE code
)
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)))
172 while(*(data
->Contents
+pos
) != '\0' && !IsDigit(data
->locale
, *(data
->Contents
+pos
)))
176 if(*(data
->Contents
+pos
) == '\0')
178 pos
= data
->BufferPos
;
179 while(pos
&& !IsDigit(data
->locale
, *(data
->Contents
+pos
)))
182 while(pos
> 0 && IsDigit(data
->locale
, *(data
->Contents
+pos
-1)))
185 if(!pos
&& !IsDigit(data
->locale
, *data
->Contents
))
193 static UWORD
NextWord(STRPTR text
, UWORD x
, struct Locale
*locale
)
195 while(IsAlNum(locale
, (UBYTE
)text
[x
]))
198 while(text
[x
] != '\0' && !IsAlNum(locale
, (UBYTE
)text
[x
]))
204 static UWORD
PrevWord(STRPTR text
, UWORD x
, struct Locale
*locale
)
209 while(x
&& !IsAlNum(locale
, (UBYTE
)text
[x
]))
212 while(x
> 0 && IsAlNum(locale
, (UBYTE
)text
[x
-1]))
218 void strcpyback(STRPTR dest
, STRPTR src
)
222 length
= strlen(src
)+1;
223 dest
= dest
+ length
;
233 void DeleteBlock(struct InstData
*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
)
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
);
264 Blk_Width
= strlen(data
->Contents
);
267 StringToClipboard(&data
->Contents
[Blk_Start
], Blk_Width
);
273 static void CutBlock(struct InstData
*data
)
279 if(BlockEnabled(data
) == TRUE
)
283 clearFlag(data
->Flags
, FLG_BlockEnabled
);
287 *data
->Contents
= '\0';
294 static void Paste(struct InstData
*data
)
301 // clear the selection
304 ClipboardToString(&str
, &length
);
305 if(str
!= NULL
&& length
> 0)
307 if(data
->MaxLength
!= 0 && strlen(data
->Contents
) + length
> (ULONG
)data
->MaxLength
- 1)
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
;
324 static void UndoRedo(struct InstData
*data
)
326 STRPTR oldcontents
= data
->Contents
;
327 UWORD oldpos
= data
->BufferPos
;
331 data
->Contents
= data
->Undo
;
332 data
->Undo
= oldcontents
;
334 if(isFlagSet(data
->Flags
, FLG_RedoAvailable
))
335 clearFlag(data
->Flags
, FLG_RedoAvailable
);
337 setFlag(data
->Flags
, FLG_RedoAvailable
);
339 clearFlag(data
->Flags
, FLG_BlockEnabled
);
340 data
->BufferPos
= data
->UndoPos
;
341 data
->UndoPos
= oldpos
;
346 static void RevertToOriginal(struct InstData
*data
)
348 STRPTR oldcontents
= data
->Contents
;
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
);
361 static BOOL
ToggleCaseChar(struct InstData
*data
)
363 UBYTE key
= *(data
->Contents
+data
->BufferPos
);
368 if(data
->BufferPos
< strlen(data
->Contents
))
370 *(data
->Contents
+data
->BufferPos
) = IsLower(data
->locale
, key
) ? ConvToUpper(data
->locale
, key
) : ConvToLower(data
->locale
, key
);
379 static BOOL
ToggleCaseWord(struct InstData
*data
)
381 UWORD Stop
= NextWord(data
->Contents
, data
->BufferPos
, data
->locale
);
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
);
399 static BOOL
IncreaseNearNumber(struct InstData
*data
)
406 if((pos
= FindDigit(data
)) >= 0)
411 if((cut
= StrToLong(data
->Contents
+pos
, (LONG
*)&res
)))
417 MySPrintf(format
, "%%0%ldlu", cut
);
418 MySPrintf(string
, format
, res
);
419 Overwrite(string
, pos
, cut
, data
);
428 static BOOL
DecreaseNearNumber(struct InstData
*data
)
435 if((pos
= FindDigit(data
)) >= 0)
440 if((cut
= StrToLong(data
->Contents
+pos
, (LONG
*)&res
)))
448 format
= &format2
[0];
449 MySPrintf(format
, "%%0%ldlu", cut
);
451 MySPrintf(string
, format
, res
);
452 Overwrite(string
, pos
, cut
, data
);
462 static BOOL
HexToDec(struct InstData
*data
)
465 UWORD pos
= data
->BufferPos
;
471 while(pos
&& IsHex(*(data
->Contents
+pos
-1)))
474 while(IsHex(*(data
->Contents
+pos
+cut
)))
476 res
= (result
<< 4) + DecimalValue(*(data
->Contents
+pos
+cut
));
484 MySPrintf(string
, "%lu", res
);
485 Overwrite(string
, pos
, cut
, data
);
493 static BOOL
DecToHex(struct InstData
*data
)
500 if((pos
= FindDigit(data
)) >= 0)
505 if((cut
= StrToLong(data
->Contents
+pos
, (LONG
*)&res
)))
507 const char *format
= "%lx";
510 MySPrintf(string
, format
, res
);
511 Overwrite(string
, pos
, cut
, data
);
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
);
536 IPTR
mDoAction(struct IClass
*cl
, Object
*obj
, struct MUIP_BetterString_DoAction
*msg
)
538 struct InstData
*data
= (struct InstData
*)INST_DATA(cl
, obj
);
544 D(DBF_INPUT
, "DoAction(%ld)", msg
->action
);
548 case MUIV_BetterString_DoAction_Cut
:
556 case MUIV_BetterString_DoAction_Copy
:
559 clearFlag(data
->Flags
, FLG_BlockEnabled
);
564 case MUIV_BetterString_DoAction_Paste
:
567 clearFlag(data
->Flags
, FLG_BlockEnabled
);
573 case MUIV_BetterString_DoAction_Delete
:
576 clearFlag(data
->Flags
, FLG_BlockEnabled
);
582 case MUIV_BetterString_DoAction_SelectAll
:
584 data
->BlockStart
= 0;
585 data
->BlockStop
= strlen(data
->Contents
);
586 setFlag(data
->Flags
, FLG_BlockEnabled
);
591 case MUIV_BetterString_DoAction_SelectNone
:
593 clearFlag(data
->Flags
, FLG_BlockEnabled
);
598 case MUIV_BetterString_DoAction_Undo
:
599 case MUIV_BetterString_DoAction_Redo
:
602 (((msg
->action
== MUIV_BetterString_DoAction_Redo
) && isFlagSet(data
->Flags
, FLG_RedoAvailable
)) ||
603 ((msg
->action
== MUIV_BetterString_DoAction_Undo
) && isFlagClear(data
->Flags
, FLG_RedoAvailable
))))
606 clearFlag(data
->Flags
, FLG_BlockEnabled
);
613 case MUIV_BetterString_DoAction_Revert
:
615 RevertToOriginal(data
);
616 clearFlag(data
->Flags
, FLG_BlockEnabled
);
622 case MUIV_BetterString_DoAction_ToggleCase
:
624 edited
= result
= ToggleCaseChar(data
);
625 clearFlag(data
->Flags
, FLG_BlockEnabled
);
629 case MUIV_BetterString_DoAction_ToggleCaseWord
:
631 edited
= result
= ToggleCaseWord(data
);
632 clearFlag(data
->Flags
, FLG_BlockEnabled
);
636 case MUIV_BetterString_DoAction_IncreaseNum
:
638 edited
= result
= IncreaseNearNumber(data
);
639 clearFlag(data
->Flags
, FLG_BlockEnabled
);
643 case MUIV_BetterString_DoAction_DecreaseNum
:
645 edited
= result
= DecreaseNearNumber(data
);
646 clearFlag(data
->Flags
, FLG_BlockEnabled
);
650 case MUIV_BetterString_DoAction_HexToDec
:
652 edited
= result
= HexToDec(data
);
653 clearFlag(data
->Flags
, FLG_BlockEnabled
);
657 case MUIV_BetterString_DoAction_DecToHex
:
659 edited
= result
= DecToHex(data
);
660 clearFlag(data
->Flags
, FLG_BlockEnabled
);
664 case MUIV_BetterString_DoAction_NextFileComp
:
666 edited
= result
= FileNameComplete(obj
, FALSE
, data
);
667 clearFlag(data
->Flags
, FLG_BlockEnabled
);
671 case MUIV_BetterString_DoAction_PrevFileComp
:
673 edited
= result
= FileNameComplete(obj
, TRUE
, data
);
674 clearFlag(data
->Flags
, FLG_BlockEnabled
);
681 struct TagItem tags
[] =
683 { MUIA_String_Contents
, (IPTR
)data
->Contents
},
687 DoSuperMethod(cl
, obj
, OM_SET
, tags
, NULL
);
690 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
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
;
702 BOOL movement
= FALSE
;
705 Object
*focus
= NULL
;
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
;
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
))
731 if(isFlagClear(data
->Flags
, FLG_BlockEnabled
))
732 data
->BlockStart
= data
->BufferPos
;
734 if(isFlagSet(data
->Flags
, FLG_NoInput
))
736 switch(msg
->imsg
->Code
)
739 case RAWKEY_BACKSPACE
:
748 switch(msg
->imsg
->Code
)
753 if(isFlagSet(data
->Flags
, FLG_NoShortcuts
) || isFlagClear(msg
->imsg
->Qualifier
, IEQUALIFIER_RCOMMAND
))
759 if(!(edited
= FileNameComplete(obj
, isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
|IEQUALIFIER_LSHIFT
), data
)))
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
);
793 case RAWKEY_CRSRLEFT
:
797 if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
|IEQUALIFIER_LSHIFT
))
801 else if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RALT
|IEQUALIFIER_LALT
))
803 data
->BufferPos
= PrevWord(data
->Contents
, data
->BufferPos
, data
->locale
);
807 if(BlockEnabled(data
) && isFlagClear(msg
->imsg
->Qualifier
, IEQUALIFIER_CONTROL
))
808 data
->BufferPos
= MIN(data
->BlockStart
, data
->BlockStop
);
819 case RAWKEY_BACKSPACE
:
821 if(BlockEnabled(data
))
827 if(data
->BufferPos
!= 0)
829 if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
|IEQUALIFIER_LSHIFT
|IEQUALIFIER_CONTROL
))
832 strcpy(data
->Contents
, data
->Contents
+data
->BufferPos
);
835 else if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RALT
|IEQUALIFIER_LALT
))
837 UWORD NewPos
= PrevWord(data
->Contents
, data
->BufferPos
, data
->locale
);
840 strcpy(data
->Contents
+NewPos
, data
->Contents
+data
->BufferPos
);
841 data
->BufferPos
= NewPos
;
845 strcpy(data
->Contents
+data
->BufferPos
-1, data
->Contents
+data
->BufferPos
);
857 if(BlockEnabled(data
))
863 if(data
->BufferPos
< StringLength
)
865 if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
|IEQUALIFIER_LSHIFT
) || isFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_CONTROL
))
868 *(data
->Contents
+data
->BufferPos
) = '\0';
870 else if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RALT
|IEQUALIFIER_LALT
))
873 strcpy(data
->Contents
+data
->BufferPos
, data
->Contents
+NextWord(data
->Contents
, data
->BufferPos
, data
->locale
));
877 strcpy(data
->Contents
+data
->BufferPos
, data
->Contents
+data
->BufferPos
+1);
898 if(data
->BufferPos
< StringLength
)
899 data
->BufferPos
= StringLength
;
907 if(data
->Popup
&& msg
->muikey
== MUIKEY_POPUP
)
909 DoMethod(data
->Popup
, MUIM_Popstring_Open
);
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
))
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
;
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
))
951 RETURN(MUI_EventHandlerRC_Eat
);
952 return MUI_EventHandlerRC_Eat
;
957 // check if the user pressed return and if he has activated AdvanceOnCr or not
960 if(isFlagClear(data
->Flags
, FLG_StayActive
))
964 if(isFlagSet(data
->Flags
, FLG_AdvanceOnCr
))
966 if(isAnyFlagSet(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
|IEQUALIFIER_LSHIFT
))
967 active
= MUIV_Window_ActiveObject_Prev
;
969 active
= MUIV_Window_ActiveObject_Next
;
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.
992 edited
= ToggleCaseChar(data
);
998 edited
= ToggleCaseWord(data
);
1018 if((edited
= IncreaseNearNumber(data
)) == FALSE
)
1025 if((edited
= DecreaseNearNumber(data
)) == FALSE
)
1032 if((edited
= HexToDec(data
)) == FALSE
)
1039 if((edited
= DecToHex(data
)) == FALSE
)
1046 RevertToOriginal(data
);
1054 if(data
->Undo
&& (((code
== 'Z') && isFlagSet(data
->Flags
, FLG_RedoAvailable
)) ||
1055 ((code
== 'z') && isFlagClear(data
->Flags
, FLG_RedoAvailable
))))
1066 clearFlag(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
);
1073 clearFlag(msg
->imsg
->Qualifier
, IEQUALIFIER_RSHIFT
);
1084 if(data
->FNCBuffer
&& !FNC
)
1086 struct FNCData
*fncbuffer
= data
->FNCBuffer
, *fncframe
;
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
);
1100 clearFlag(data
->Flags
, FLG_BlockEnabled
);
1102 if(isFlagSet(data
->Flags
, FLG_BlockEnabled
))
1103 data
->BlockStop
= data
->BufferPos
;
1107 struct TagItem tags
[] =
1109 { MUIA_String_Contents
, (IPTR
)data
->Contents
},
1113 DoSuperMethod(cl
, obj
, OM_SET
, tags
, NULL
);
1116 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1117 result
= MUI_EventHandlerRC_Eat
;
1121 if(data
->CtrlChar
&& ConvertKey(msg
->imsg
) == data
->CtrlChar
)
1123 set(_win(obj
), MUIA_Window_ActiveObject
, obj
);
1124 result
= MUI_EventHandlerRC_Eat
;
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__)
1154 isOverObject
= TRUE
;
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
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
);
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
))
1207 get(_win(obj
), MUIA_Window_ActiveObject
, &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
);
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)
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
)
1270 if(isFlagClear(data
->Flags
, FLG_BlockEnabled
) || isFlagClear(msg
->imsg
->Qualifier
, IEQUALIFIER_CONTROL
))
1271 data
->BlockStart
= data
->BufferPos
;
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)))
1286 while(alpha
== (ULONG
)IsAlNum(data
->locale
, (UBYTE
)*(data
->Contents
+stop
)) && *(data
->Contents
+stop
) != '\0')
1289 data
->BlockStart
= start
;
1290 data
->BufferPos
= stop
;
1297 data
->BlockStart
= 0;
1298 data
->BufferPos
= strlen(data
->Contents
);
1304 data
->BlockStart
= data
->BufferPos
;
1305 data
->ClickCount
= 0;
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
);
1320 set(_win(obj
), MUIA_Window_ActiveObject
, obj
);
1322 result
= MUI_EventHandlerRC_Eat
;
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
);
1337 set(_win(obj
), MUIA_Window_ActiveObject
, MUIV_Window_ActiveObject_None
);
1345 #ifdef ALLOW_OUTSIDE_MARKING
1346 if(msg
->imsg
->Class
== IDCMP_MOUSEMOVE
)
1348 clearFlag(data
->Flags
, FLG_DragOutside
);
1349 D(DBF_STARTUP
, "Detected drag");
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
)
1369 if(data
->DisplayPos
)
1371 data
->BufferPos
= data
->DisplayPos
;
1375 if(mousex
>= x
+width
)
1377 if(data
->DisplayPos
< StringLength
)
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
);
1384 data
->BufferPos
= StringLength
;
1389 WORD offset
= mousex
- x
;
1392 data->BufferPos = 0;
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
);
1404 WORD offset
= mousex
- x
;
1407 if(mousex
< x
&& data
->DisplayPos
)
1410 newpos
= data
->DisplayPos
;
1414 // offset -= AlignOffset(obj, data);
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
)))
1426 while(newpos
> 0 && IsAlNum(data
->locale
, (UBYTE
)*(data
->Contents
+newpos
-1)))
1430 if(data
->BufferPos
!= newpos
)
1432 data
->BlockStop
= data
->BufferPos
= newpos
;
1433 MUI_Redraw(obj
, MADF_DRAWUPDATE
);