Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / classes / zune / betterstring / mcc / HandleInput.c
blob29d2eec5b7c00f7e567462c9ab1f6bea0d0e79f1
1 /***************************************************************************
3 BetterString.mcc - A better String gadget MUI Custom Class
4 Copyright (C) 1997-2000 Allan Odgaard
5 Copyright (C) 2005 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>
25 #include <stdio.h>
26 #include <ctype.h>
28 #include <clib/alib_protos.h>
29 #include <clib/macros.h>
30 #include <devices/clipboard.h>
31 #include <devices/inputevent.h>
32 #include <libraries/mui.h>
33 #include <proto/dos.h>
34 #include <proto/exec.h>
35 #include <proto/keymap.h>
36 #include <proto/intuition.h>
37 #include <proto/iffparse.h>
38 #include <proto/locale.h>
39 #include <proto/muimaster.h>
40 #include <proto/utility.h>
42 #include "private.h"
44 #ifndef __AROS__
45 #include "SDI_stdarg.h"
46 #endif
48 #ifdef __AROS__
49 #include <aros/macros.h>
50 #define LONG2BE(x) AROS_LONG2BE(x)
51 #define BE2LONG(x) AROS_BE2LONG(x)
52 #else
53 #define LONG2BE(x) x
54 #define BE2LONG(x) x
55 #endif
57 static BOOL BlockEnabled(struct InstData *data)
59 return((data->Flags & FLG_BlockEnabled) && data->BlockStart != data->BlockStop);
62 #if defined(__amigaos4__) || defined(__MORPHOS__)
63 static int VARARGS68K MySPrintf(char *buf, char *fmt, ...)
65 VA_LIST args;
67 VA_START(args, fmt);
68 RawDoFmt(fmt, VA_ARG(args, void *), NULL, buf);
69 VA_END(args);
71 return(strlen(buf));
73 #elif defined(__AROS__)
74 #define MySPrintf __sprintf /* from amiga lib */
75 #else
76 static int STDARGS MySPrintf(char *buf, char *fmt,...)
78 static const UWORD PutCharProc[2] = {0x16C0,0x4E75};
79 /* dirty hack to avoid assembler part :-)
80 16C0: move.b d0,(a3)+
81 4E75: rts */
82 RawDoFmt(fmt, (APTR)(((ULONG)&fmt)+4), (APTR)PutCharProc, buf);
84 return(strlen(buf));
86 #endif
88 VOID AddToUndo (struct InstData *data)
90 if(data->Undo)
91 MyFreePooled(data->Pool, data->Undo);
93 if((data->Undo = (STRPTR)MyAllocPooled(data->Pool, strlen(data->Contents)+1)))
95 strcpy(data->Undo, data->Contents);
96 data->UndoPos = data->BufferPos;
97 data->Flags &= ~FLG_RedoAvailable;
101 WORD AlignOffset (Object *obj, struct InstData *data)
103 struct MUI_AreaData *ad = muiAreaData(obj);
104 struct TextFont *font = data->Font ? data->Font : ad->mad_Font;
105 WORD width = ad->mad_Box.Width - ad->mad_subwidth;
106 WORD offset = 0;
108 if(data->Alignment != MUIV_String_Format_Left)
110 STRPTR text = data->Contents+data->DisplayPos;
111 UWORD StrLength = strlen(text);
112 UWORD length, textlength, crsr_width;
114 length = MyTextFit(font, text, StrLength, width, 1);
115 textlength = MyTextLength(font, text, length);
117 crsr_width = (data->Flags & FLG_Active) ? MyTextLength(font, (*(data->Contents+data->BufferPos) == '\0') ? "n" : data->Contents+data->BufferPos, 1) : 0;
118 if(crsr_width && !BlockEnabled(data) && data->BufferPos == data->DisplayPos+StrLength)
120 textlength += crsr_width;
123 switch(data->Alignment)
125 case MUIV_String_Format_Center:
126 offset = (width - textlength)/2;
127 break;
128 case MUIV_String_Format_Right:
129 offset = (width - textlength);
130 break;
133 return(offset);
136 BOOL Reject (UBYTE code, STRPTR reject)
138 if(reject)
140 while(*reject)
142 if(code == *reject++)
143 return(FALSE);
146 return(TRUE);
149 BOOL Accept (UBYTE code, STRPTR accept)
151 return(accept ? !Reject(code, accept) : TRUE);
154 UWORD DecimalValue (UBYTE code)
156 if(code >= '0' && code <= '9')
157 return(code - '0');
158 if(code >= 'a' && code <= 'f')
159 return(code - 'a' + 10);
160 if(code >= 'A' && code <= 'F')
161 return(code - 'A' + 10);
163 return(0);
166 BOOL IsHex (UBYTE code)
168 return(
169 (code >= '0' && code <= '9') ||
170 (code >= 'a' && code <= 'f') ||
171 (code >= 'A' && code <= 'F') ? TRUE : FALSE);
174 LONG FindDigit (struct InstData *data)
176 WORD pos = data->BufferPos;
178 if(IsDigit(data->locale, *(data->Contents+pos)))
180 while(pos > 0 && IsDigit(data->locale, *(data->Contents+pos-1)))
181 pos--;
183 else
185 while(*(data->Contents+pos) != '\0' && !IsDigit(data->locale, *(data->Contents+pos)))
186 pos++;
189 if(*(data->Contents+pos) == '\0')
191 pos = data->BufferPos;
192 while(pos && !IsDigit(data->locale, *(data->Contents+pos)))
193 pos--;
195 while(pos > 0 && IsDigit(data->locale, *(data->Contents+pos-1)))
196 pos--;
198 if(!pos && !IsDigit(data->locale, *data->Contents))
200 pos = -1;
203 return(pos);
206 UWORD NextWord (STRPTR text, UWORD x, struct Locale *locale)
208 while(IsAlNum(locale, (UBYTE)text[x]))
209 x++;
211 while(text[x] != '\0' && !IsAlNum(locale, (UBYTE)text[x]))
212 x++;
214 return(x);
217 UWORD PrevWord (STRPTR text, UWORD x, struct Locale *locale)
219 if(x)
220 x--;
222 while(x && !IsAlNum(locale, (UBYTE)text[x]))
223 x--;
225 while(x > 0 && IsAlNum(locale, (UBYTE)text[x-1]))
226 x--;
228 return(x);
231 VOID strcpyback (STRPTR dest, STRPTR src)
233 UWORD length;
235 length = strlen(src)+1;
236 dest = dest + length;
237 src = src + length;
239 length++;
240 while(--length)
242 *--dest = *--src;
246 VOID DeleteBlock (struct InstData *data)
248 AddToUndo(data);
249 if(BlockEnabled(data))
251 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 strcpy(data->Contents+Blk_Start, data->Contents+Blk_Start+Blk_Width);
255 data->BufferPos = Blk_Start;
259 VOID CopyBlock (struct InstData *data)
261 struct MsgPort *port;
262 struct IOClipReq *iorequest;
263 UWORD Blk_Start, Blk_Width;
265 if(data->Flags & FLG_Secret)
266 return;
268 if(BlockEnabled(data))
270 Blk_Start = (data->BlockStart < data->BlockStop) ? data->BlockStart : data->BlockStop;
271 Blk_Width = abs(data->BlockStop-data->BlockStart);
273 else
275 Blk_Start = 0;
276 Blk_Width = strlen(data->Contents);
279 if((port = CreateMsgPort()))
281 if((iorequest = (struct IOClipReq *)CreateIORequest(port, sizeof(struct IOClipReq))))
283 if(!OpenDevice("clipboard.device", 0, (struct IORequest *)iorequest, 0))
285 ULONG IFF_Head[] = { LONG2BE(MAKE_ID('F','O','R','M')),
286 LONG2BE(12 + ((Blk_Width + 1) & ~1)),
287 LONG2BE(MAKE_ID('F','T','X','T')),
288 LONG2BE(MAKE_ID('C','H','R','S')),
289 LONG2BE(Blk_Width)
292 iorequest->io_ClipID = 0;
293 iorequest->io_Offset = 0;
294 iorequest->io_Data = (STRPTR)IFF_Head;
295 iorequest->io_Length = sizeof(IFF_Head);
296 iorequest->io_Command = CMD_WRITE;
297 DoIO((struct IORequest *)iorequest);
299 iorequest->io_Data = data->Contents+Blk_Start;
300 iorequest->io_Length = Blk_Width;
301 DoIO((struct IORequest *)iorequest);
303 iorequest->io_Command = CMD_UPDATE;
304 DoIO((struct IORequest *)iorequest);
306 CloseDevice((struct IORequest *)iorequest);
308 DeleteIORequest((struct IORequest *)iorequest);
310 DeleteMsgPort(port);
314 VOID Paste (struct InstData *data)
316 struct MsgPort *port;
317 struct IOClipReq *iorequest;
319 if((port = CreateMsgPort()))
321 if((iorequest = (struct IOClipReq *)CreateIORequest(port, sizeof(struct IOClipReq))))
323 if(!OpenDevice("clipboard.device", 0, (struct IORequest *)iorequest, 0))
325 ULONG IFF_Head[3];
326 LONG length;
328 iorequest->io_ClipID = 0;
329 iorequest->io_Offset = 0;
330 iorequest->io_Data = (STRPTR)IFF_Head;
331 iorequest->io_Length = sizeof(IFF_Head);
332 iorequest->io_Command = CMD_READ;
333 DoIO((struct IORequest *)iorequest);
334 length = IFF_Head[1]-4;
336 if(iorequest->io_Actual == sizeof(IFF_Head) &&
337 *IFF_Head == BE2LONG(MAKE_ID('F','O','R','M')) &&
338 IFF_Head[2] == BE2LONG(MAKE_ID('F','T','X','T')) && length > 8)
340 iorequest->io_Length = 8;
341 DoIO((struct IORequest *)iorequest);
342 length -= 8;
344 while(length > 0 && *IFF_Head != BE2LONG(MAKE_ID('C','H','R','S')))
346 iorequest->io_Offset += BE2LONG(IFF_Head[1]);
347 length -= BE2LONG(IFF_Head[1])+8;
348 DoIO((struct IORequest *)iorequest);
351 if(*IFF_Head == BE2LONG(MAKE_ID('C','H','R','S')))
353 ULONG pastelength = BE2LONG(IFF_Head[1]);
355 if(data->MaxLength && strlen(data->Contents)+pastelength > data->MaxLength-1)
357 DisplayBeep(NULL);
358 pastelength = (data->MaxLength-1)-strlen(data->Contents);
361 data->Contents = (STRPTR)ExpandPool(data->Pool, data->Contents, pastelength);
362 strcpyback(data->Contents+data->BufferPos+pastelength, data->Contents+data->BufferPos);
363 iorequest->io_Length = pastelength;
364 iorequest->io_Data = data->Contents+data->BufferPos;
365 DoIO((struct IORequest *)iorequest);
367 while(pastelength--)
369 if(data->Contents[data->BufferPos] == '\0')
370 data->Contents[data->BufferPos] = '?';
371 data->BufferPos++;
374 else
376 DisplayBeep(NULL);
379 else
381 DisplayBeep(NULL);
384 iorequest->io_Offset = 0xfffffff;
385 iorequest->io_Data = NULL;
386 DoIO((struct IORequest *)iorequest);
388 CloseDevice((struct IORequest *)iorequest);
390 DeleteIORequest((struct IORequest *)iorequest);
392 DeleteMsgPort(port);
396 ULONG ConvertKey (struct IntuiMessage *imsg)
398 struct InputEvent event;
399 UBYTE code = 0;
401 event.ie_NextEvent = NULL;
402 event.ie_Class = IECLASS_RAWKEY;
403 event.ie_SubClass = 0;
404 event.ie_Code = imsg->Code;
405 event.ie_Qualifier = imsg->Qualifier;
406 event.ie_EventAddress = (APTR *) *((ULONG *)imsg->IAddress);
408 MapRawKey(&event, &code, 1, NULL);
409 return(code);
412 ULONG HandleInput(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
414 struct InstData *data = (struct InstData *)INST_DATA(cl, obj);
415 struct MUI_AreaData *ad = muiAreaData(obj);
416 struct TextFont *Font = data->Font ? data->Font : ad->mad_Font;
417 ULONG result = 0;
418 BOOL movement = FALSE;
419 BOOL deletion = FALSE;
420 BOOL edited = FALSE;
421 BOOL FNC = FALSE;
423 Object *focus = NULL;
424 if(msg->muikey == MUIKEY_UP)
425 focus = data->KeyUpFocus;
426 else if(msg->muikey == MUIKEY_DOWN)
427 focus = data->KeyDownFocus;
429 if(focus && _win(obj))
431 set(_win(obj), MUIA_Window_ActiveObject, focus);
432 result = MUI_EventHandlerRC_Eat;
434 else if(msg->imsg)
436 WORD StringLength = strlen(data->Contents);
438 if(msg->imsg->Class == IDCMP_RAWKEY && msg->imsg->Code >= IECODE_KEY_CODE_FIRST && msg->imsg->Code <= IECODE_KEY_CODE_LAST)
440 if(data->Flags & FLG_Active)
442 if(!(data->Flags & FLG_BlockEnabled))
443 data->BlockStart = data->BufferPos;
445 BOOL input = TRUE;
446 if(data->Flags & FLG_NoInput)
448 switch(msg->imsg->Code)
450 case 66: /* Tab */
451 case 65: /* Backspace */
452 case 70: /* Delete */
453 input = FALSE;
454 break;
458 if(input) switch(msg->imsg->Code)
460 case 66: /* Tab */
461 if(!(msg->imsg->Qualifier & IEQUALIFIER_RCOMMAND))
462 return(0);
464 if(!(edited = FileNameComplete(obj, (msg->imsg->Qualifier & (IEQUALIFIER_RSHIFT | IEQUALIFIER_LSHIFT)) ? TRUE : FALSE, data)))
465 DisplayBeep(NULL);
466 FNC = TRUE;
467 break;
469 case 78: /* Right */
470 if(data->BufferPos < StringLength)
472 if(msg->imsg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
474 data->BufferPos = StringLength;
476 else
478 if(msg->imsg->Qualifier & (IEQUALIFIER_RALT | IEQUALIFIER_LALT))
480 data->BufferPos = NextWord(data->Contents, data->BufferPos, data->locale);
482 else
484 if(BlockEnabled(data) && !(msg->imsg->Qualifier & IEQUALIFIER_CONTROL))
485 data->BufferPos = MAX(data->BlockStart, data->BlockStop);
486 else
487 data->BufferPos++;
491 movement = TRUE;
492 break;
494 case 79: /* Left */
495 if(data->BufferPos)
497 if(msg->imsg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
499 data->BufferPos = 0;
501 else
503 if(msg->imsg->Qualifier & (IEQUALIFIER_RALT | IEQUALIFIER_LALT))
505 data->BufferPos = PrevWord(data->Contents, data->BufferPos, data->locale);
507 else
509 if(BlockEnabled(data) && !(msg->imsg->Qualifier & IEQUALIFIER_CONTROL))
510 data->BufferPos = MIN(data->BlockStart, data->BlockStop);
512 if(data->BufferPos)
513 data->BufferPos--;
517 movement = TRUE;
518 break;
520 case 65: /* Backspace */
521 if(BlockEnabled(data))
523 DeleteBlock(data);
525 else
527 if(data->BufferPos)
529 if(msg->imsg->Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
531 AddToUndo(data);
532 strcpy(data->Contents, data->Contents+data->BufferPos);
533 data->BufferPos = 0;
535 else
537 if(msg->imsg->Qualifier & (IEQUALIFIER_RALT | IEQUALIFIER_LALT))
539 UWORD NewPos = PrevWord(data->Contents, data->BufferPos, data->locale);
541 AddToUndo(data);
542 strcpy(data->Contents+NewPos, data->Contents+data->BufferPos);
543 data->BufferPos = NewPos;
545 else
547 strcpy(data->Contents+data->BufferPos-1, data->Contents+data->BufferPos);
548 data->BufferPos--;
553 deletion = TRUE;
554 break;
556 case 70: /* Delete */
557 if(BlockEnabled(data))
559 DeleteBlock(data);
561 else
563 if(data->BufferPos < StringLength)
565 if(msg->imsg->Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
567 AddToUndo(data);
568 *(data->Contents+data->BufferPos) = '\0';
570 else
572 if(msg->imsg->Qualifier & (IEQUALIFIER_RALT | IEQUALIFIER_LALT))
574 AddToUndo(data);
575 strcpy(data->Contents+data->BufferPos, data->Contents+NextWord(data->Contents, data->BufferPos, data->locale));
577 else
579 strcpy(data->Contents+data->BufferPos, data->Contents+data->BufferPos+1);
584 deletion = TRUE;
585 break;
587 default:
589 if(data->Popup && msg->muikey == MUIKEY_POPUP)
591 DoMethod(data->Popup, MUIM_Popstring_Open);
593 else
595 UBYTE code = ConvertKey(msg->imsg);
596 if((((code >= 32 && code <= 126) || code >= 160) && !(msg->imsg->Qualifier & IEQUALIFIER_RCOMMAND)) || (code && msg->imsg->Qualifier & IEQUALIFIER_CONTROL))
598 if(!(data->Flags & FLG_NoInput))
600 DeleteBlock(data);
601 if((data->MaxLength == 0 || data->MaxLength-1 > strlen(data->Contents)) && Accept(code, data->Accept) && Reject(code, data->Reject))
603 data->Contents = (STRPTR)ExpandPool(data->Pool, data->Contents, 1);
604 strcpyback(data->Contents+data->BufferPos+1, data->Contents+data->BufferPos);
605 *(data->Contents+data->BufferPos) = code;
606 data->BufferPos++;
607 edited = TRUE;
609 else
611 DisplayBeep(NULL);
615 else
617 if(data->Flags & FLG_NoInput)
619 switch(code)
621 case '\r':
622 case 'c':
623 break;
625 default:
626 return(MUI_EventHandlerRC_Eat);
627 break;
631 switch(code)
633 case '\r':
634 if(!(data->Flags & FLG_StayActive))
635 set(_win(obj), MUIA_Window_ActiveObject, (data->Flags & FLG_AdvanceOnCr) ? (msg->imsg->Qualifier & (IEQUALIFIER_RSHIFT | IEQUALIFIER_LSHIFT) ? MUIV_Window_ActiveObject_Prev : MUIV_Window_ActiveObject_Next) : MUIV_Window_ActiveObject_None);
636 set(obj, MUIA_String_Acknowledge, data->Contents);
637 return(MUI_EventHandlerRC_Eat);
638 /* Skip the "un-block" code */
640 case 'g':
642 UBYTE key = *(data->Contents+data->BufferPos);
644 if(data->BufferPos < StringLength)
646 *(data->Contents+data->BufferPos) = IsLower(data->locale, key) ? ConvToUpper(data->locale, key) : ConvToLower(data->locale, key);
647 data->BufferPos++;
648 edited = TRUE;
651 break;
653 case 'G':
655 UWORD Stop = NextWord(data->Contents, data->BufferPos, data->locale);
657 while(data->BufferPos < Stop)
659 UBYTE key = *(data->Contents+data->BufferPos);
661 *(data->Contents+data->BufferPos) = IsLower(data->locale, key) ? ConvToUpper(data->locale, key) : ConvToLower(data->locale, key);
662 data->BufferPos++;
663 edited = TRUE;
666 break;
668 case 'c':
669 CopyBlock(data);
670 break;
672 case 'x':
673 AddToUndo(data);
674 if(BlockEnabled(data))
676 CopyBlock(data);
677 DeleteBlock(data);
679 else
681 *data->Contents = '\0';
682 data->BufferPos = 0;
684 deletion = TRUE;
685 break;
687 case 'v':
688 DeleteBlock(data);
689 Paste(data);
690 edited = TRUE;
691 break;
693 case 'i':
695 LONG pos, cut;
696 ULONG result;
698 if((pos = FindDigit(data)) >= 0)
700 if((cut = StrToLong(data->Contents+pos, (LONG *)&result)))
702 UBYTE string[12], format[12];
704 result++;
705 MySPrintf(format, "%%0%ldlu", cut);
706 MySPrintf(string, format, result);
707 Overwrite(string, pos, cut, data);
708 edited = TRUE;
711 if(!edited)
712 DisplayBeep(NULL);
713 break;
716 case 'd':
717 case '$':
719 LONG pos, cut;
720 ULONG result;
722 if((pos = FindDigit(data)) >= 0)
724 if((cut = StrToLong(data->Contents+pos, (LONG *)&result)))
726 if(result || code == '$')
728 UBYTE string[12], format2[12];
729 STRPTR format = "%lx";
730 if(code == 'd')
732 result--;
733 format = format2;
734 MySPrintf(format, "%%0%ldlu", cut);
736 MySPrintf(string, format, result);
737 Overwrite(string, pos, cut, data);
738 edited = TRUE;
742 if(!edited)
743 DisplayBeep(NULL);
744 break;
747 case '#':
749 LONG cut = 0;
750 UWORD pos = data->BufferPos;
751 ULONG result = 0;
753 while(pos && IsHex(*(data->Contents+pos-1)))
754 pos--;
756 while(IsHex(*(data->Contents+pos+cut)))
758 result = (result << 4) + DecimalValue(*(data->Contents+pos+cut));
759 cut++;
762 if(cut)
764 UBYTE string[12];
766 MySPrintf(string, "%lu", result);
767 Overwrite(string, pos, cut, data);
768 edited = TRUE;
770 if(!edited)
771 DisplayBeep(NULL);
772 break;
775 case 'q':
777 STRPTR oldcontents = data->Contents;
778 data->Contents = data->Original;
779 data->Original = oldcontents;
780 data->Flags |= FLG_Original;
781 data->Flags &= ~FLG_BlockEnabled;
782 data->BufferPos = strlen(data->Contents);
783 edited = TRUE;
784 break;
787 case 'z':
788 case 'Z':
790 if(data->Undo && (((code == 'Z') && (data->Flags & FLG_RedoAvailable)) || ((code == 'z') && !(data->Flags & FLG_RedoAvailable))))
792 STRPTR oldcontents = data->Contents;
793 UWORD oldpos = data->BufferPos;
795 data->Contents = data->Undo;
796 data->Undo = oldcontents;
797 data->Flags ^= FLG_RedoAvailable;
798 data->Flags &= ~FLG_BlockEnabled;
799 data->BufferPos = data->UndoPos;
800 data->UndoPos = oldpos;
801 edited = TRUE;
803 else
805 DisplayBeep(NULL);
807 break;
810 default:
811 msg->imsg->Qualifier &= ~IEQUALIFIER_RSHIFT;
812 return(0);
817 break;
820 if(data->FNCBuffer && !FNC)
822 struct FNCData *fncbuffer = data->FNCBuffer, *fncframe;
824 while(fncbuffer)
826 fncframe = fncbuffer;
827 fncbuffer = fncbuffer->next;
828 MyFreePooled(data->Pool, fncframe);
830 data->FNCBuffer = NULL;
833 if(movement && msg->imsg->Qualifier & IEQUALIFIER_CONTROL)
834 data->Flags |= FLG_BlockEnabled;
835 else data->Flags &= ~FLG_BlockEnabled;
837 if(data->Flags & FLG_BlockEnabled)
839 data->BlockStop = data->BufferPos;
842 if(deletion || edited)
844 struct TagItem tags[] =
846 { MUIA_String_Contents, (ULONG)data->Contents },
847 { TAG_DONE, NULL }
849 DoSuperMethod(cl, obj, OM_SET, tags, NULL);
850 // set(obj, MUIA_String_Contents, data->Contents);
853 MUI_Redraw(obj, MADF_DRAWUPDATE);
854 result = MUI_EventHandlerRC_Eat;
856 else
858 if(data->CtrlChar && ConvertKey(msg->imsg) == data->CtrlChar)
860 set(_win(obj), MUIA_Window_ActiveObject, obj);
861 result = MUI_EventHandlerRC_Eat;
865 else
867 if(msg->imsg->Class == IDCMP_MOUSEBUTTONS)
869 if(msg->imsg->Code == (IECODE_LBUTTON | IECODE_UP_PREFIX))
871 if(data->ehnode.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
873 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
874 data->ehnode.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
875 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
878 #ifdef ALLOW_OUTSIDE_MARKING
879 if((data->Flags & (FLG_Active|FLG_DragOutside)) == (FLG_Active|FLG_DragOutside))
881 Object *active;
882 get(_win(obj), MUIA_Window_ActiveObject, &active);
883 if(obj != active)
884 kprintf("MUI error: %lx, %lx\n", active, obj);
886 WORD x = ad->mad_Box.Left + ad->mad_addleft;
887 WORD y = ad->mad_Box.Top + ad->mad_addtop;
888 WORD width = ad->mad_Box.Width - ad->mad_subwidth;
889 WORD height = Font->tf_YSize;
891 if(!(msg->imsg->MouseX >= x && msg->imsg->MouseX < x+width && msg->imsg->MouseY >= y && msg->imsg->MouseY < y+height))
893 kprintf("Detected LMB+up outside (drag: %ld)\n", data->Flags & FLG_DragOutside ? 1:0);
894 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
897 #endif
899 else if(msg->imsg->Code == IECODE_LBUTTON)
901 WORD x = ad->mad_Box.Left + ad->mad_addleft;
902 WORD y = ad->mad_Box.Top + ad->mad_addtop;
903 WORD width = ad->mad_Box.Width - ad->mad_subwidth;
904 WORD height = Font->tf_YSize;
906 if(msg->imsg->MouseX >= x && msg->imsg->MouseX < x+width && msg->imsg->MouseY >= y && msg->imsg->MouseY < y+height)
908 WORD offset = msg->imsg->MouseX - x;
910 offset -= AlignOffset(obj, data);
911 data->BufferPos = data->DisplayPos + MyTextFit(Font, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, offset+1, 1);
913 if(DoubleClick(data->StartSecs, data->StartMicros, msg->imsg->Seconds, msg->imsg->Micros))
914 data->ClickCount++;
915 else data->ClickCount = 0;
916 data->StartSecs = msg->imsg->Seconds;
917 data->StartMicros = msg->imsg->Micros;
919 switch(data->ClickCount)
921 case 0:
922 if(!(data->Flags & FLG_BlockEnabled && msg->imsg->Qualifier & IEQUALIFIER_CONTROL))
923 data->BlockStart = data->BufferPos;
924 break;
926 case 1:
927 if(*(data->Contents+data->BufferPos) != '\0')
929 UWORD start = data->BufferPos,
930 stop = data->BufferPos;
931 BOOL alpha = IsAlNum(data->locale, (UBYTE)*(data->Contents+data->BufferPos));
933 while(start > 0 && alpha == IsAlNum(data->locale, (UBYTE)*(data->Contents+start-1)))
934 start--;
936 while(alpha == IsAlNum(data->locale, (UBYTE)*(data->Contents+stop)) && *(data->Contents+stop) != '\0')
937 stop++;
939 data->BlockStart = start;
940 data->BufferPos = stop;
942 break;
944 case 2:
945 data->BlockStart = 0;
946 data->BufferPos = strlen(data->Contents);
947 break;
949 case 3:
950 data->BlockStart = data->BufferPos;
951 data->ClickCount = 0;
952 break;
954 data->BlockStop = data->BufferPos;
955 data->Flags |= FLG_BlockEnabled;
957 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
958 data->ehnode.ehn_Events |= (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
959 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
961 if(data->Flags & FLG_Active)
962 MUI_Redraw(obj, MADF_DRAWUPDATE);
963 else set(_win(obj), MUIA_Window_ActiveObject, obj);
964 result = MUI_EventHandlerRC_Eat;
966 else
968 data->ClickCount = 0;
969 if(data->Flags & FLG_Active && !(data->Flags & FLG_StayActive))
971 #ifdef ALLOW_OUTSIDE_MARKING
972 kprintf("Clicked outside gadget\n");
973 data->Flags |= FLG_DragOutside;
975 DoMethod(_win(obj), MUIM_Window_RemEventHandler, &data->ehnode);
976 data->ehnode.ehn_Events |= IDCMP_MOUSEMOVE;
977 DoMethod(_win(obj), MUIM_Window_AddEventHandler, &data->ehnode);
978 #else
979 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
980 #endif
985 else
987 #ifdef ALLOW_OUTSIDE_MARKING
988 if(msg->imsg->Class == IDCMP_MOUSEMOVE)
990 data->Flags &= ~FLG_DragOutside;
991 kprintf("Detected drag\n");
993 #endif
994 if((msg->imsg->Class == IDCMP_MOUSEMOVE || msg->imsg->Class == IDCMP_INTUITICKS) && data->Flags & FLG_Active)
996 WORD x, width, mousex;
998 x = ad->mad_Box.Left + ad->mad_addleft;
999 mousex = msg->imsg->MouseX - AlignOffset(obj, data);
1000 width = ad->mad_Box.Width - ad->mad_subwidth;
1002 switch(data->ClickCount)
1004 case 0:
1006 if(mousex < x)
1008 if(data->DisplayPos)
1009 data->DisplayPos--;
1010 data->BufferPos = data->DisplayPos;
1012 else
1014 if(mousex >= x+width)
1016 if(data->DisplayPos < StringLength)
1018 data->DisplayPos++;
1019 data->BufferPos = data->DisplayPos + MyTextFit(Font, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, ad->mad_Box.Width - ad->mad_subwidth, 1);
1021 else
1023 data->BufferPos = StringLength;
1026 else
1028 WORD offset = mousex - x;
1030 /* if(offset < 0)
1031 data->BufferPos = 0;
1032 else
1033 */ data->BufferPos = data->DisplayPos + MyTextFit(Font, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, offset+1, 1);
1036 data->BlockStop = data->BufferPos;
1037 MUI_Redraw(obj, MADF_DRAWUPDATE);
1039 break;
1041 case 1:
1043 WORD offset = mousex - x,
1044 newpos = 0;
1046 if(mousex < x && data->DisplayPos)
1048 data->DisplayPos--;
1049 newpos = data->DisplayPos;
1051 else
1053 // offset -= AlignOffset(obj, data);
1054 if(offset > 0)
1055 newpos = data->DisplayPos + MyTextFit(Font, data->Contents+data->DisplayPos, StringLength-data->DisplayPos, offset+1, 1);
1058 if(newpos >= data->BlockStart)
1060 while(IsAlNum(data->locale, (UBYTE)*(data->Contents+newpos)))
1061 newpos++;
1063 else
1065 while(newpos > 0 && IsAlNum(data->locale, (UBYTE)*(data->Contents+newpos-1)))
1066 newpos--;
1069 if(data->BufferPos != newpos)
1071 data->BlockStop = data->BufferPos = newpos;
1072 MUI_Redraw(obj, MADF_DRAWUPDATE);
1075 break;
1081 return(result);