muimaster.library: remove empty Dispose from Listview
[AROS.git] / workbench / libs / muimaster / classes / string.c
blob5d575b3c9f25bc0c62371b91aa7133261d704249
1 /*
2 Copyright © 2003-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /* This is based on muimaster/class/text.c (first string version)
7 * and on rom/intuition/str*.c
8 */
10 #define MUIMASTER_YES_INLINE_STDARG
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <ctype.h>
17 #include <exec/types.h>
18 #include <clib/alib_protos.h>
20 #include <proto/exec.h>
21 #include <proto/dos.h>
22 #include <proto/graphics.h>
23 #include <proto/intuition.h>
24 #include <proto/utility.h>
25 #include <proto/muimaster.h>
26 #include <proto/locale.h>
28 #ifdef __AROS__
29 #include <devices/rawkeycodes.h>
30 #endif
32 #include "mui.h"
33 #include "muimaster_intern.h"
34 #include "support.h"
35 #include "prefs.h"
36 #include "penspec.h"
37 #include "imspec.h"
38 #include "clipboard.h"
39 #include "string.h"
41 //#define MYDEBUG 1
42 #include "debug.h"
44 extern struct Library *MUIMasterBase;
46 struct MUI_StringData
48 ULONG msd_Flags;
49 CONST_STRPTR msd_Accept; /* MUIA_String_Accept */
50 CONST_STRPTR msd_Reject; /* MUIA_String_Reject */
51 LONG msd_Align;
52 struct Hook *msd_EditHook;
53 Object *msd_AttachedList;
54 LONG msd_RedrawReason;
56 ULONG msd_useSecret;
57 /* Fields mostly ripped from rom/intuition/strgadgets.c */
58 STRPTR Buffer; /* char container */
59 STRPTR SecBuffer; /* Buffer for secret string */
60 STRPTR VisualBuffer; /* Pointer to either Buffer or SecBuffer */
61 ULONG BufferSize; /* memory allocated */
62 ULONG NumChars; /* string length */
63 ULONG BufferPos; /* cursor (insert/delete) position */
64 ULONG MarkPos; /* cursor text marking start pos */
65 LONG DispPos; /* leftmost visible char */
66 ULONG DispCount; /* number of visible chars */
68 ULONG OldClick_Sec;
69 ULONG OldClick_Micro;
70 ULONG NewClick_Sec;
71 ULONG NewClick_Micro;
72 WORD MultiClick;
74 WORD Columns;
76 struct MUI_EventHandlerNode ehn;
77 struct MUI_PenSpec_intern inactive_text;
78 struct MUI_PenSpec_intern active_text;
79 struct MUI_PenSpec_intern marked_text;
80 struct MUI_PenSpec_intern marked_bg;
81 struct MUI_PenSpec_intern cursor;
83 BOOL is_active;
86 #define MSDF_ADVANCEONCR (1<<0)
87 #define MSDF_LONELYEDITHOOK (1<<1)
88 #define MSDF_MARKING (1<<2)
89 #define MSDF_KEYMARKING (1<<3)
90 #define MSDF_NOINPUT (1<<4)
91 #define MSDF_STAYACTIVE (1<<5)
93 enum
95 NO_REASON = 0,
96 WENT_ACTIVE = 1,
97 WENT_INACTIVE,
98 DO_CURSOR_LEFT = 3,
99 DO_CURSOR_RIGHT,
100 DO_DELETE = 5,
101 DO_BACKSPACE,
102 DO_ADDCHAR = 7,
103 NEW_CONTENTS,
104 MOVE_CURSOR,
105 DO_UNKNOWN,
108 #define SECRET_CHAR '*'
111 /****** String.mui/MUIA_String_Accept ****************************************
113 * NAME
114 * MUIA_String_Accept -- (V4) [ISG], STRPTR
116 * FUNCTION
117 * A string containing the characters to be accepted by the string
118 * gadget. If NULL is specified, all characters are accepted. The
119 * character list is case sensitive.
121 * NOTES
122 * MUIA_String_Reject takes precedence over MUIA_String_Accept.
124 * The specified string is not cached within the object.
126 * SEE ALSO
127 * MUIA_String_Reject
129 ******************************************************************************
133 /****** String.mui/MUIA_String_Reject ****************************************
135 * NAME
136 * MUIA_String_Reject -- (V4) [ISG], STRPTR
138 * FUNCTION
139 * A string containing the characters to be rejected by the string
140 * gadget. If NULL is specified, no characters are rejected. The
141 * character list is case sensitive.
143 * NOTES
144 * MUIA_String_Reject takes precedence over MUIA_String_Accept.
146 * The specified string is not cached within the object.
148 * SEE ALSO
149 * MUIA_String_Accept
151 ******************************************************************************
155 /****** String.mui/MUIA_String_BufferPos *************************************
157 * NAME
158 * MUIA_String_BufferPos -- (V4) [ISG], STRPTR
160 * FUNCTION
161 * The cursor's position relative to the start of the string.
163 * NOTES
164 * The MUI AutoDocs claim this attribute is not initialisable.
166 ******************************************************************************
170 /**************************************************************************
171 Buffer_Alloc
172 Allocate memory for buffer
173 **************************************************************************/
174 static BOOL Buffer_Alloc(struct MUI_StringData *data)
176 UWORD i;
178 data->Buffer =
179 (STRPTR) AllocVec(data->BufferSize * sizeof(char), MEMF_ANY);
180 if (NULL == data->Buffer)
182 bug("MUIC_String: Can't allocate %ld bytes for buffer1\n",
183 data->BufferSize * sizeof(char));
184 return FALSE;
186 if (data->msd_useSecret)
188 data->SecBuffer =
189 (STRPTR) AllocVec(data->BufferSize * sizeof(char), MEMF_ANY);
190 if (NULL == data->SecBuffer)
192 bug("MUIC_String: Can't allocate %ld bytes for buffer2\n",
193 data->BufferSize * sizeof(char));
194 FreeVec(data->Buffer);
195 data->Buffer = NULL;
196 return FALSE;
199 /* Initialise maximum number of asterisks we'll need */
200 for (i = 0; i < data->BufferSize - 1; i++)
201 data->SecBuffer[i] = SECRET_CHAR;
203 data->VisualBuffer = data->SecBuffer;
205 else
206 data->VisualBuffer = data->Buffer;
208 return TRUE;
211 static inline VOID PrepareVisualBuffer(struct MUI_StringData *data)
213 if (data->msd_useSecret)
214 data->VisualBuffer[data->NumChars] = '\0';
217 static inline VOID CleanVisualBuffer(struct MUI_StringData *data)
219 if (data->msd_useSecret)
220 data->VisualBuffer[data->NumChars] = SECRET_CHAR;
223 /**************************************************************************
224 Buffer_SetNewContents
225 Initialize buffer with a string, replace former content if any
226 **************************************************************************/
227 static BOOL Buffer_SetNewContents(struct MUI_StringData *data,
228 CONST_STRPTR str)
230 if (NULL == data->Buffer)
231 return FALSE;
233 if (NULL == str)
235 data->Buffer[0] = 0;
236 data->NumChars = 0;
238 else
240 data->NumChars = strlen(str);
241 if (data->NumChars >= data->BufferSize)
242 data->NumChars = data->BufferSize - 1;
244 strncpy(data->Buffer, str, data->BufferSize);
245 data->Buffer[data->BufferSize - 1] = 0;
248 // avoid to BufferPos jumps to end of string if characters are inserted
249 // in string
250 if (data->BufferPos > data->NumChars)
251 data->BufferPos = data->NumChars;
252 data->DispPos = 0;
253 return TRUE;
256 /**************************************************************************
257 Buffer_AddChar
258 Add a char on cursor position
259 **************************************************************************/
260 static BOOL Buffer_AddChar(struct MUI_StringData *data, unsigned char code)
262 STRPTR dst;
264 if (data->Buffer == NULL)
265 return FALSE;
267 if (data->NumChars + 1 >= data->BufferSize)
268 return FALSE;
270 dst = &data->Buffer[data->BufferPos + 1];
272 memmove(dst, &data->Buffer[data->BufferPos],
273 data->NumChars - data->BufferPos);
275 dst[data->NumChars - data->BufferPos] = 0;
276 dst[-1] = code;
278 data->BufferPos++;
279 data->NumChars++;
280 return TRUE;
283 static WORD Buffer_GetWordStartIndex(struct MUI_StringData *data,
284 WORD startindex)
286 WORD index = startindex;
288 while (index > 0)
290 if (data->Buffer[index - 1] == ' ')
292 break;
294 index--;
297 return index;
300 static WORD Buffer_GetWordEndIndex(struct MUI_StringData *data,
301 WORD startindex)
303 WORD index = startindex;
305 while (index < data->NumChars)
307 if (data->Buffer[index] == ' ')
309 break;
311 index++;
314 return index;
317 static WORD Buffer_GetPrevWordIndex(struct MUI_StringData *data,
318 WORD startindex)
320 WORD index = startindex;
322 while (index > 0)
324 index--;
326 if ((index == 0) ||
327 ((data->Buffer[index - 1] == ' ') &&
328 (data->Buffer[index] != ' ')))
330 break;
335 return index;
338 static WORD Buffer_GetSuccWordIndex(struct MUI_StringData *data,
339 WORD startindex)
341 WORD index = startindex;
343 while (index < data->NumChars)
345 index++;
347 if ((index == data->NumChars) ||
348 ((data->Buffer[index - 1] == ' ') &&
349 (data->Buffer[index] != ' ')))
351 break;
355 return index;
358 static BOOL Buffer_GetMarkedRange(struct MUI_StringData *data, WORD *start,
359 WORD *stop)
361 WORD markstart = data->MarkPos;
362 WORD markstop = data->BufferPos;
364 markstart = MIN(markstart, data->NumChars);
365 markstart = MAX(markstart, 0);
367 markstop = MIN(markstop, data->NumChars);
368 markstop = MAX(markstop, 0);
370 if (markstart > markstop)
372 markstart ^= markstop;
373 markstop ^= markstart;
374 markstart ^= markstop;
377 switch (data->MultiClick)
379 case 0:
380 /* char select */
381 break;
383 case 1:
384 /* word select */
385 markstart = Buffer_GetWordStartIndex(data, markstart);
386 markstop = Buffer_GetWordEndIndex(data, markstop);
387 break;
389 default:
390 /* select all */
391 markstart = 0;
392 markstop = data->NumChars;
393 break;
397 if (markstart == markstop)
398 return FALSE;
400 if (start)
401 *start = markstart;
402 if (stop)
403 *stop = markstop;
405 //kprintf("Buffer_GetMarkedRange: returning %d .. %d\n",
406 // markstart, markstop);
408 return TRUE;
411 static BOOL Buffer_AnythingMarked(struct MUI_StringData *data)
413 if (!(data->msd_Flags & MSDF_MARKING))
414 return FALSE;
416 return Buffer_GetMarkedRange(data, NULL, NULL);
419 static BOOL Buffer_KillMarked(struct MUI_StringData *data)
421 WORD markstart = data->MarkPos;
422 WORD markstop = data->BufferPos;
423 WORD marklen;
425 //kprintf("\nBuffer_KillMarked 1 markpos %d bufferpos %d numchars %d\n",
426 // markstart, markstop, data->NumChars);
428 if (!(data->msd_Flags & MSDF_MARKING))
429 return FALSE;
431 data->msd_Flags &= ~MSDF_MARKING;
433 if (!Buffer_GetMarkedRange(data, &markstart, &markstop))
434 return FALSE;
436 //kprintf("Buffer_KillMarked 2 markstart %d markstop %d\n",
437 // markstart, markstop);
439 if (markstart > markstop)
441 markstart ^= markstop;
442 markstop ^= markstart;
443 markstart ^= markstop;
446 marklen = markstop - markstart;
448 //kprintf("Buffer_KillMarked: markstart %d markstop %d\n",
449 // markstart, markstop);
451 memmove(&data->Buffer[markstart],
452 &data->Buffer[markstart + marklen],
453 data->NumChars - markstart - marklen + 1);
455 data->NumChars -= marklen;
456 data->BufferPos = markstart;
458 return TRUE;
461 /**************************************************************************
462 OM_NEW
463 **************************************************************************/
464 IPTR String__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
466 struct MUI_StringData *data;
467 struct TagItem *tags, *tag;
468 CONST_STRPTR str = NULL;
469 char integerbuf[20];
471 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
472 /* MUIA_FillArea, TRUE, */
473 TAG_MORE, (IPTR) msg->ops_AttrList);
474 if (!obj)
475 return FALSE;
477 data = INST_DATA(cl, obj);
478 data->msd_useSecret = FALSE;
479 data->msd_Align = MUIV_String_Format_Left;
480 data->BufferSize = 80;
481 data->Columns = -1;
483 Buffer_SetNewContents(data, ""); /* <-- isn't this pointless? */
485 /* parse initial taglist */
486 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
488 switch (tag->ti_Tag)
490 case MUIA_String_Accept:
491 data->msd_Accept = (CONST_STRPTR) tag->ti_Data;
492 break;
494 case MUIA_String_Reject:
495 data->msd_Reject = (CONST_STRPTR) tag->ti_Data;
496 break;
498 case MUIA_String_AdvanceOnCR:
499 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
500 MSDF_ADVANCEONCR);
501 break;
503 case MUIA_String_BufferPos:
504 data->BufferPos = (ULONG) tag->ti_Data;
505 break;
507 case MUIA_String_AttachedList:
508 data->msd_AttachedList = (Object *) tag->ti_Data;
509 break;
511 case MUIA_String_Secret:
512 data->msd_useSecret = (BOOL) tag->ti_Data;
513 break;
515 case MUIA_String_Contents:
516 str = (CONST_STRPTR) tag->ti_Data;
517 break;
519 case MUIA_String_EditHook:
520 data->msd_EditHook = (struct Hook *)tag->ti_Data;
521 break;
523 case MUIA_String_Format:
524 data->msd_Align = (LONG) tag->ti_Data;
525 break;
527 case MUIA_String_Integer:
528 snprintf(integerbuf, 19, "%ld", tag->ti_Data);
529 str = integerbuf;
530 break;
532 case MUIA_String_LonelyEditHook:
533 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
534 MSDF_LONELYEDITHOOK);
535 break;
537 case MUIA_String_MaxLen:
538 data->BufferSize = tag->ti_Data;
539 if (data->BufferSize < 1)
540 data->BufferSize = 1;
541 break;
543 case MUIA_String_Columns: /* BetterString */
544 data->Columns = (WORD) tag->ti_Data;
545 break;
547 case MUIA_String_NoInput: /* BetterString */
548 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_NOINPUT);
549 break;
551 case MUIA_String_StayActive: /* BetterString */
552 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
553 MSDF_STAYACTIVE);
554 break;
559 if (Buffer_Alloc(data))
561 Buffer_SetNewContents(data, str);
564 if (NULL == data->Buffer)
566 CoerceMethod(cl, obj, OM_DISPOSE);
567 return 0;
570 D(bug("String_New(%p)\n", obj));
572 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
573 data->ehn.ehn_Priority = 0;
574 data->ehn.ehn_Flags = 0;
575 data->ehn.ehn_Object = obj;
576 data->ehn.ehn_Class = cl;
578 CurrentTime(&data->OldClick_Sec, &data->OldClick_Micro);
580 return (IPTR) obj;
583 /**************************************************************************
584 OM_DISPOSE
585 **************************************************************************/
586 IPTR String__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
588 struct MUI_StringData *data = INST_DATA(cl, obj);
590 FreeVec(data->Buffer);
591 FreeVec(data->SecBuffer);
593 D(bug("String_Dispose %p\n", obj));
595 return DoSuperMethodA(cl, obj, msg);
598 /**************************************************************************
599 OM_SET
600 **************************************************************************/
601 IPTR String__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
603 struct MUI_StringData *data = INST_DATA(cl, obj);
604 struct TagItem *tags = msg->ops_AttrList;
605 struct TagItem *tag;
607 while ((tag = NextTagItem(&tags)) != NULL)
609 switch (tag->ti_Tag)
611 case MUIA_String_Contents:
612 Buffer_SetNewContents(data, (STRPTR) tag->ti_Data);
613 data->msd_RedrawReason = NEW_CONTENTS;
614 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
615 MUI_Redraw(obj, MADF_DRAWOBJECT);
616 break;
618 case MUIA_String_Accept:
619 data->msd_Accept = (CONST_STRPTR) tag->ti_Data;
620 break;
622 case MUIA_String_Reject:
623 data->msd_Reject = (CONST_STRPTR) tag->ti_Data;
624 break;
626 case MUIA_String_AttachedList:
627 data->msd_AttachedList = (Object *) tag->ti_Data;
628 break;
630 case MUIA_String_Integer:
632 char buf[20];
634 snprintf(buf, 19, "%ld", tag->ti_Data);
635 set(obj, MUIA_String_Contents, buf);
637 break;
639 case MUIA_String_AdvanceOnCR:
640 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
641 MSDF_ADVANCEONCR);
642 break;
644 case MUIA_String_BufferPos:
645 data->BufferPos = (ULONG) tag->ti_Data;
646 data->msd_Flags &= ~MSDF_MARKING;
647 data->msd_RedrawReason = MOVE_CURSOR;
648 MUI_Redraw(obj, MADF_DRAWUPDATE);
649 break;
651 case MUIA_String_DisplayPos:
652 data->BufferPos = (ULONG) tag->ti_Data;
653 data->DispPos = data->BufferPos; // move both pos
654 data->msd_Flags &= ~MSDF_MARKING;
655 data->msd_RedrawReason = MOVE_CURSOR;
656 MUI_Redraw(obj, MADF_DRAWUPDATE);
657 break;
659 case MUIA_String_NoInput: /* BetterString */
660 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_NOINPUT);
661 break;
663 case MUIA_String_StayActive: /* BetterString */
664 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
665 MSDF_STAYACTIVE);
666 break;
668 case MUIA_String_SelectSize: /* BetterString */
669 // TODO: Implement OM_SET(MUIA_String_SelectSize)!
670 break;
675 return DoSuperMethodA(cl, obj, (Msg) msg);
679 /**************************************************************************
680 OM_GET
681 **************************************************************************/
682 IPTR String__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
684 struct MUI_StringData *data = INST_DATA(cl, obj);
686 #define STORE *(msg->opg_Storage)
687 switch (msg->opg_AttrID)
689 case MUIA_String_Contents:
690 STORE = (IPTR) data->Buffer;
691 return TRUE;
693 case MUIA_String_Secret:
694 STORE = (IPTR) data->msd_useSecret;
695 return TRUE;
697 case MUIA_String_Accept:
698 STORE = (IPTR) data->msd_Accept;
699 return TRUE;
701 case MUIA_String_Reject:
702 STORE = (IPTR) data->msd_Reject;
703 return TRUE;
705 case MUIA_String_AttachedList:
706 STORE = (IPTR) data->msd_AttachedList;
707 return TRUE;
709 case MUIA_String_Format:
710 STORE = (IPTR) data->msd_Align;
711 return TRUE;
713 case MUIA_String_Integer:
715 STRPTR buf = NULL;
716 STORE = 0;
717 get(obj, MUIA_String_Contents, &buf);
718 if (NULL != buf)
720 LONG val = 0;
721 StrToLong(buf, &val);
722 STORE = val;
724 return TRUE;
727 case MUIA_String_MaxLen:
728 STORE = (IPTR) data->BufferSize;
729 return TRUE;
731 case MUIA_String_AdvanceOnCR:
732 STORE = (data->msd_Flags & MSDF_ADVANCEONCR) ? TRUE : FALSE;
733 return TRUE;
735 case MUIA_String_BufferPos:
736 STORE = data->BufferPos;
737 return TRUE;
739 case MUIA_String_DisplayPos:
740 STORE = data->DispPos;
741 return TRUE;
743 case MUIA_String_NoInput: /* BetterString */
744 STORE = (data->msd_Flags & MSDF_NOINPUT) ? TRUE : FALSE;
745 return TRUE;
747 case MUIA_String_StayActive: /* BetterString */
748 STORE = (data->msd_Flags & MSDF_STAYACTIVE) ? TRUE : FALSE;
749 return TRUE;
751 case MUIA_String_SelectSize: /* BetterString */
752 if (data->msd_Flags & MSDF_MARKING)
754 WORD markstart, markstop;
756 if (Buffer_GetMarkedRange(data, &markstart, &markstop))
758 LONG size = markstop - markstart;
760 if (data->MarkPos < data->BufferPos)
761 size = -size;
763 STORE = (IPTR) size;
765 return 1;
770 STORE = 0;
771 return TRUE;
775 return DoSuperMethodA(cl, obj, (Msg) msg);
776 #undef STORE
779 /**************************************************************************
780 MUIM_Setup
781 **************************************************************************/
782 IPTR String__MUIM_Setup(struct IClass *cl, Object *obj,
783 struct MUIP_Setup *msg)
785 struct MUI_StringData *data = INST_DATA(cl, obj);
787 if (0 == DoSuperMethodA(cl, obj, (Msg) msg))
788 return FALSE;
790 data->is_active = FALSE;
791 set(obj, MUIA_Background,
792 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
794 zune_pen_spec_to_intern(
795 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
796 string_text_inactive, &data->inactive_text);
797 zune_penspec_setup(&data->inactive_text, muiRenderInfo(obj));
799 zune_pen_spec_to_intern(
800 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
801 string_text_active, &data->active_text);
802 zune_penspec_setup(&data->active_text, muiRenderInfo(obj));
804 zune_pen_spec_to_intern(
805 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
806 string_text_marked, &data->marked_text);
807 zune_penspec_setup(&data->marked_text, muiRenderInfo(obj));
809 zune_pen_spec_to_intern(
810 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
811 string_bg_marked, &data->marked_bg);
812 zune_penspec_setup(&data->marked_bg, muiRenderInfo(obj));
814 zune_pen_spec_to_intern(
815 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
816 string_cursor, &data->cursor);
817 zune_penspec_setup(&data->cursor, muiRenderInfo(obj));
819 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
820 return TRUE;
823 /**************************************************************************
824 MUIM_Cleanup
825 **************************************************************************/
826 IPTR String__MUIM_Cleanup(struct IClass *cl, Object *obj,
827 struct MUIP_Cleanup *msg)
829 struct MUI_StringData *data = INST_DATA(cl, obj);
831 D(bug("String_Cleanup %p\n", obj));
832 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
834 zune_penspec_cleanup(&data->inactive_text);
835 zune_penspec_cleanup(&data->active_text);
836 zune_penspec_cleanup(&data->marked_text);
837 zune_penspec_cleanup(&data->marked_bg);
838 zune_penspec_cleanup(&data->cursor);
840 return (DoSuperMethodA(cl, obj, (Msg) msg));
843 /**************************************************************************
844 MUIM_AskMinMax
845 **************************************************************************/
846 IPTR String__MUIM_AskMinMax(struct IClass *cl, Object *obj,
847 struct MUIP_AskMinMax *msg)
849 struct MUI_StringData *data = INST_DATA(cl, obj);
851 DoSuperMethodA(cl, obj, (Msg) msg);
853 if (data->Columns >= 0)
855 msg->MinMaxInfo->MinWidth += _font(obj)->tf_XSize * data->Columns;
856 msg->MinMaxInfo->DefWidth += _font(obj)->tf_XSize * data->Columns;
857 msg->MinMaxInfo->MaxWidth += _font(obj)->tf_XSize * data->Columns;
859 else
861 msg->MinMaxInfo->MinWidth += _font(obj)->tf_XSize * 4;
862 msg->MinMaxInfo->DefWidth += _font(obj)->tf_XSize * 12;
863 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
866 msg->MinMaxInfo->MinHeight += _font(obj)->tf_YSize;
867 msg->MinMaxInfo->DefHeight += _font(obj)->tf_YSize;
868 msg->MinMaxInfo->MaxHeight += _font(obj)->tf_YSize;
870 /* D(bug("String_AskMinMax(%p): Min=%ldx%ld Max=%ldx%ld Def=%ldx%ld\n", */
871 /* obj, msg->MinMaxInfo->MinWidth, msg->MinMaxInfo->MinHeight, */
872 /* msg->MinMaxInfo->MaxWidth, msg->MinMaxInfo->MaxHeight, */
873 /* msg->MinMaxInfo->DefWidth, msg->MinMaxInfo->DefHeight)); */
875 return TRUE;
879 static WORD MaxDispPos(struct IClass *cl, Object *obj)
881 struct MUI_StringData *data = INST_DATA(cl, obj);
882 WORD numfit, max_disppos, numchars;
883 struct TextExtent te;
884 BOOL cursor_at_end;
886 cursor_at_end = (data->BufferPos == data->NumChars);
888 /* D(bug("MaxDispPos(current length: %d, bufferpos=%d)\n", */
889 /* data->NumChars, data->BufferPos)); */
891 /* D(bug("cursor_at_end: %d\n", cursor_at_end)); */
893 if (cursor_at_end) /* Cursor at end of string ? */
895 /* D(bug("Making cursor last char\n")); */
896 numchars = data->NumChars + 1; /* Take cursor into account */
898 /* This has already been done by UpdateDisp() which called us
899 strinfo->Buffer[strinfo->NumChars] = 0x20;
903 else
905 numchars = data->NumChars;
908 /* Find the amount of characters that fit into the bbox, counting
909 ** from the last character in the buffer and forward,
911 numfit = TextFit(_rp(obj),
912 &(data->Buffer[numchars - 1]),
913 numchars, &te, NULL, -1, _mwidth(obj), _mheight(obj));
915 max_disppos = numchars - numfit;
917 /* if ((max_disppos > 0) && (!cursor_at_end))
918 max_disppos --;
921 /* D(bug("Numchars w/cursor: %d, Numfit: %d, maxdisppos=%d " */
922 /* "bbox->Width = %d te->te_Width = %d\n", */
923 /* numchars, numfit, max_disppos, _mwidth(obj), te.te_Width)); */
925 return max_disppos;
929 static void UpdateDisp(struct IClass *cl, Object *obj)
931 struct MUI_StringData *data = INST_DATA(cl, obj);
932 struct TextExtent te;
933 STRPTR dispstr;
935 /* If the cursor is at the trailing \0, insert a SPACE instead */
936 if (data->BufferPos == data->NumChars)
937 data->VisualBuffer[data->NumChars] = ' ';
939 /* In this function we check if the cursor has gone outside
940 ** of the visible area (because of application setting
941 ** strinfo->BufferPos or strinfo->DispPos to a different value, or
942 ** because of user input).
943 ** This is made a bit difficult by the rule (R), that there
944 ** should NOT be available space on the right, and characters
945 ** scrolled out at the left, at the same time.
946 ** We have 3 possible scenarios:
947 ** 1) Cursor to the left of DispPos:
948 ** Set DispPos to the lowest of BufferPos and the
949 ** maximum allowed disppos (according to (R) ).
950 ** 2) Cursor to the right of visible area:
951 ** Set dispose sou that the cursor is the last visible character.
952 ** This afheres to (R).
953 ** 3) Cursor inside visible area. Do a check on rule (R),
954 ** and if DispPos > max allowed, then adjust it down,
955 ** so that the last character in the buffer becomes last character
956 ** displayed. (The cursor will still be visible after adjustion)
959 /* 1) Cursor to the left of visible area */
960 if (data->BufferPos < data->DispPos)
962 WORD max_disppos;
964 max_disppos = MaxDispPos(cl, obj);
965 data->DispPos = MIN(data->BufferPos, max_disppos);
967 else /* Cursor equal to the right of disppos [ 2) or 3) ] */
969 UWORD strsize;
971 /* How many pixels are there from current 1st displayed to cursor? */
972 strsize = TextLength(_rp(obj),
973 data->VisualBuffer + data->DispPos,
974 data->BufferPos - data->DispPos + 1);
976 /* 2) More than fits into the gadget ? */
977 if (strsize > _mwidth(obj))
979 /* Compute new DispPos such that the cursor is at the right */
980 data->DispPos = data->BufferPos
981 - TextFit(_rp(obj),
982 &(data->VisualBuffer[data->BufferPos]),
983 data->NumChars, &te, NULL, -1,
984 _mwidth(obj), _mheight(obj)) + 1;
986 /* D(bug("cursor right of visible area, new disppos: %d\n", */
987 /* data->DispPos)); */
989 else /* 3). Cursor inside gadget */
991 WORD max_disppos;
993 max_disppos = MaxDispPos(cl, obj);
994 if (data->DispPos > max_disppos)
995 data->DispPos = max_disppos;
997 } /* if (cursor inside or to the right of visible area ) */
1001 /* Update the DispCount */
1002 /* It might be necessary with special handling for centre aligned gads */
1003 dispstr = &(data->VisualBuffer[data->DispPos]);
1004 /* D(bug("DispCount before = %d\n", data->DispCount)); */
1005 data->DispCount = TextFit(_rp(obj), dispstr,
1006 data->NumChars - data->DispPos,
1007 &te, NULL, 1, _mwidth(obj), _mheight(obj));
1008 /* D(bug("DispCount after = %d\n", data->DispCount)); */
1010 /* 0-terminate string (in case we put a SPACE at the end) */
1011 data->VisualBuffer[data->NumChars] = '\0';
1015 /* Gets left position of text in the string gadget */
1016 static UWORD GetTextLeft(struct IClass *cl, Object *obj)
1018 struct MUI_StringData *data = INST_DATA(cl, obj);
1019 UWORD text_left = 0;
1020 STRPTR dispstr = &(data->VisualBuffer[data->DispPos]);
1021 UWORD dispstrlen;
1022 BOOL cursor_at_end;
1024 cursor_at_end = (data->BufferPos == data->NumChars);
1025 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
1027 switch (data->msd_Align)
1029 case MUIV_String_Format_Left:
1030 text_left = _mleft(obj);
1031 break;
1033 case MUIV_String_Format_Center:
1035 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
1036 if (cursor_at_end)
1037 textwidth += TextLength(_rp(obj), " ", 1);
1038 text_left = _mleft(obj) + ((_mwidth(obj) - textwidth) / 2);
1039 /* D(bug("GetTextLeft: dispstr=%s, dispstrlen=%d, textw=%d, " */
1040 /* "textl=%d\n", */
1041 /* dispstr, dispstrlen, textwidth, text_left)); */
1043 break;
1045 case MUIV_String_Format_Right:
1047 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
1049 if (cursor_at_end)
1050 textwidth += TextLength(_rp(obj), " ", 1);
1051 text_left = _mleft(obj) + (_mwidth(obj) - 1 - textwidth);
1053 break;
1055 return (text_left);
1058 /* Gets right offset of text in the string gadget */
1059 static UWORD GetTextRight(struct IClass *cl, Object *obj)
1061 struct MUI_StringData *data = INST_DATA(cl, obj);
1062 UWORD text_right = 0;
1063 STRPTR dispstr = &(data->VisualBuffer[data->DispPos]);
1064 UWORD dispstrlen;
1065 BOOL cursor_at_end;
1067 cursor_at_end = (data->BufferPos == data->NumChars);
1068 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
1070 switch (data->msd_Align)
1072 case MUIV_String_Format_Left:
1073 text_right =
1074 _mleft(obj) + TextLength(_rp(obj), dispstr, dispstrlen);
1075 break;
1077 case MUIV_String_Format_Center:
1079 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
1081 if (cursor_at_end)
1082 textwidth += TextLength(_rp(obj), " ", 1);
1083 text_right = _mright(obj) - ((_mwidth(obj) - textwidth) / 2);
1085 break;
1087 case MUIV_String_Format_Right:
1088 text_right = _mright(obj);
1089 break;
1091 return (text_right);
1095 /* Updates the stringdata in case user has set some fields */
1096 static VOID UpdateStringData(struct IClass *cl, Object *obj)
1098 struct MUI_StringData *data = INST_DATA(cl, obj);
1100 data->NumChars = strlen(data->Buffer);
1102 if (data->BufferPos > data->NumChars)
1104 data->BufferPos = data->NumChars;
1108 static VOID TextM(Object *obj, struct MUI_StringData *data,
1109 STRPTR text, WORD textlen, WORD markstart, WORD markend)
1111 struct RastPort *rp = _rp(obj);
1112 ULONG textpen;
1113 WORD len;
1115 if (data->is_active)
1116 textpen = data->active_text.p_pen;
1117 else
1118 textpen = data->inactive_text.p_pen;
1120 //kprintf("TextM: textlen %d markstart %d markend %d ... \n",
1121 // textlen, markstart, markend);
1123 /* <unmarked><marked><unmarked> */
1125 /* <unmarked> */
1127 len = MIN(markstart, textlen);
1128 len = MAX(len, 0);
1130 if (len)
1132 //kprintf("A: %d ", len);
1134 SetABPenDrMd(rp, textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1135 Text(rp, text, len);
1137 text += len;
1138 textlen -= len;
1142 len = MIN(markend - len, textlen);
1143 len = MAX(len, 0);
1145 if (len)
1147 //kprintf("B: %d ", len);
1148 SetABPenDrMd(_rp(obj), data->marked_text.p_pen,
1149 data->marked_bg.p_pen, JAM2);
1150 Text(rp, text, len);
1152 text += len;
1153 textlen -= len;
1156 if (textlen)
1158 //kprintf("C: %d ", textlen);
1160 SetABPenDrMd(rp, textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1161 Text(rp, text, textlen);
1163 //kprintf("\n");
1166 /**************************************************************************
1167 MUIM_Draw
1168 **************************************************************************/
1169 IPTR String__MUIM_Draw(struct IClass *cl, Object *obj,
1170 struct MUIP_Draw *msg)
1172 struct MUI_StringData *data = INST_DATA(cl, obj);
1173 UWORD text_left;
1174 UWORD text_top;
1175 STRPTR dispstr;
1176 UWORD dispstrlen;
1177 ULONG textpen;
1178 UWORD textleft_save;
1179 WORD markstart = 0, markstop = 0;
1181 /* D(bug("\nString_Draw(%p) %ldx%ldx%ldx%ld reason=%ld msgflgs=%ld " */
1182 /* "curs=%d " */
1183 /* "displ=%ld len=%ld buf='%s'\n",obj,_mleft(obj),_mtop(obj), */
1184 /* _mwidth(obj),_mheight(obj), data->msd_RedrawReason, msg->flags, */
1185 /* data->BufferPos, data->DispPos, data->NumChars, data->Buffer)); */
1187 DoSuperMethodA(cl, obj, (Msg) msg);
1189 if (!(msg->flags & MADF_DRAWUPDATE) && !(msg->flags & MADF_DRAWOBJECT))
1190 return 0;
1192 PrepareVisualBuffer(data);
1193 SetFont(_rp(obj), _font(obj));
1194 if (data->is_active)
1195 textpen = data->active_text.p_pen;
1196 else
1197 textpen = data->inactive_text.p_pen;
1199 /* Update the stringdata in case of user change */
1200 UpdateStringData(cl, obj);
1202 /* Update the DispPos and DispCount fields so that the gadget renders
1203 * properly */
1204 UpdateDisp(cl, obj);
1206 text_top = _mtop(obj)
1207 + ((_mheight(obj) - _rp(obj)->Font->tf_YSize) >> 1)
1208 + _rp(obj)->Font->tf_Baseline;
1210 dispstr = data->VisualBuffer + data->DispPos;
1211 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
1212 textleft_save = text_left = GetTextLeft(cl, obj);
1214 // little flicker improvement, don't redraw first part of string
1215 // when adding a char
1216 if (msg->flags & MADF_DRAWUPDATE &&
1217 data->msd_RedrawReason == DO_ADDCHAR &&
1218 data->msd_Align == MUIV_String_Format_Left && data->DispPos == 0)
1220 text_left += TextLength(_rp(obj), dispstr, data->BufferPos - 1);
1221 dispstr += data->BufferPos - 1;
1222 dispstrlen -= data->BufferPos - 1;
1223 DoMethod(obj, MUIM_DrawBackground, text_left, _mtop(obj),
1224 _mwidth(obj) - text_left + _mleft(obj), _mheight(obj),
1225 text_left, _mtop(obj), 0);
1227 else if (msg->flags & MADF_DRAWUPDATE)
1229 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1230 _mwidth(obj), _mheight(obj), _mleft(obj), _mtop(obj), 0);
1233 SetABPenDrMd(_rp(obj), textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1234 Move(_rp(obj), text_left, text_top);
1236 if ((data->msd_Flags & MSDF_MARKING)
1237 && Buffer_GetMarkedRange(data, &markstart, &markstop))
1239 TextM(obj, data, dispstr, dispstrlen, markstart - data->DispPos,
1240 markstop - data->DispPos);
1243 else
1245 Text(_rp(obj), dispstr, dispstrlen);
1247 if (data->is_active) // active, draw cursor
1249 UWORD cursoroffset = data->BufferPos - data->DispPos;
1251 dispstr = data->VisualBuffer + data->DispPos;
1252 text_left = textleft_save;
1254 SetABPenDrMd(_rp(obj), data->active_text.p_pen,
1255 data->cursor.p_pen, JAM2);
1256 text_left += TextLength(_rp(obj), dispstr, cursoroffset);
1259 Move(_rp(obj), text_left, text_top);
1260 Text(_rp(obj),
1261 ((data->BufferPos < data->NumChars)
1262 ? dispstr + cursoroffset : (STRPTR) " "), 1);
1266 data->msd_RedrawReason = NO_REASON;
1267 CleanVisualBuffer(data);
1269 return TRUE;
1272 /**************************************************************************
1273 Returns whether object needs redrawing
1274 **************************************************************************/
1275 static int String_HandleVanillakey(struct IClass *cl, Object *obj,
1276 unsigned char code, UWORD qual, IPTR *retval)
1278 struct MUI_StringData *data =
1279 (struct MUI_StringData *)INST_DATA(cl, obj);
1280 BOOL doinput;
1282 D(bug("String_HandleVanillakey: code=%d qual=%d\n", code, qual));
1284 if (0 == code)
1285 return 0;
1287 doinput = (data->msd_Flags & MSDF_NOINPUT) ? FALSE : TRUE;
1289 if (doinput && (code == '\b')) /* backspace */
1291 if (Buffer_KillMarked(data))
1293 return 1;
1296 if (data->BufferPos > 0)
1298 LONG shift;
1300 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
1302 shift = data->BufferPos;
1303 data->msd_RedrawReason = NEW_CONTENTS;
1305 else
1307 shift = 1;
1308 data->msd_RedrawReason = DO_BACKSPACE;
1311 strcpy(&data->Buffer[data->BufferPos - shift],
1312 &data->Buffer[data->BufferPos]);
1313 data->BufferPos -= shift;
1314 data->NumChars -= shift;
1315 return 1;
1317 return 0;
1320 if (doinput && (code == 21)) // ctrl-u == NAK (like shift-bs)
1322 if (Buffer_KillMarked(data))
1324 return 1;
1327 if (data->BufferPos > 0)
1329 strcpy(&data->Buffer[0], &data->Buffer[data->BufferPos]);
1330 data->NumChars -= data->BufferPos;
1331 data->BufferPos = 0;
1332 data->msd_RedrawReason = NEW_CONTENTS;
1333 return 1;
1335 return 0;
1338 if (doinput && (code == 127)) /* del */
1340 if (!Buffer_KillMarked(data))
1342 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
1344 data->Buffer[data->BufferPos] = 0;
1345 data->NumChars = data->BufferPos;
1346 data->msd_RedrawReason = NEW_CONTENTS;
1348 else
1350 if (data->BufferPos < data->NumChars)
1352 strcpy(&data->Buffer[data->BufferPos],
1353 &data->Buffer[data->BufferPos + 1]);
1354 data->NumChars--;
1357 data->msd_RedrawReason = DO_DELETE;
1360 return 1;
1363 if (doinput && (code == 11)) // ctrl-k == VT == \v (like shift-del)
1365 if (!Buffer_KillMarked(data))
1367 data->Buffer[data->BufferPos] = 0;
1368 data->NumChars = data->BufferPos;
1369 data->msd_RedrawReason = NEW_CONTENTS;
1371 return 1;
1374 if (doinput && (code == 24)) /* ctrl x == ascii cancel */
1376 if (!Buffer_KillMarked(data))
1378 data->Buffer[0] = 0;
1379 data->BufferPos = 0;
1380 data->NumChars = 0;
1381 data->msd_RedrawReason = NEW_CONTENTS;
1383 return 1;
1386 if (code == 1) // ctrl-a, linestart
1388 data->BufferPos = 0;
1389 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
1390 return 1;
1393 if (code == 26) // ctrl-z, lineend
1395 data->BufferPos = data->NumChars;
1396 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
1397 return 1;
1400 if (code == '\t') // tab
1402 return 0;
1405 if (((ToLower(code) == 'c') || (ToLower(code) == 'x')) &&
1406 (qual & IEQUALIFIER_RCOMMAND))
1408 WORD markstart, markstop;
1410 if ((data->msd_Flags & MSDF_MARKING)
1411 && Buffer_GetMarkedRange(data, &markstart, &markstop))
1413 clipboard_write_text(&data->Buffer[markstart],
1414 markstop - markstart);
1416 if (doinput && (ToLower(code) == 'x'))
1418 Buffer_KillMarked(data);
1420 else
1422 data->BufferPos = markstop;
1423 data->msd_Flags &= ~MSDF_MARKING;
1425 return 1;
1427 return 0;
1430 if (doinput && (ToLower(code) == 'v') && (qual & IEQUALIFIER_RCOMMAND))
1432 STRPTR text;
1433 int retval;
1434 struct Locale *locale = OpenLocale(NULL);
1436 retval = Buffer_KillMarked(data);
1437 if ((text = clipboard_read_text()))
1439 STRPTR text2 = text;
1440 UBYTE c;
1442 while ((c = *text2++))
1444 if (!IsPrint(locale, c))
1445 break;
1446 if (!(Buffer_AddChar(data, c)))
1447 break;
1448 if (!retval)
1449 retval = 1;
1452 clipboard_free_text(text);
1455 CloseLocale(locale);
1457 return retval;
1460 if (data->msd_Accept != NULL)
1462 /* Check if character is accepted */
1463 if (NULL == strchr(data->msd_Accept, code))
1465 DisplayBeep(NULL);
1466 *retval = MUI_EventHandlerRC_Eat;
1467 return 0;
1471 if (data->msd_Reject != NULL)
1473 /* Check if character is rejected */
1474 if (NULL != strchr(data->msd_Reject, code))
1476 DisplayBeep(NULL);
1477 *retval = MUI_EventHandlerRC_Eat;
1478 return 0;
1482 if (doinput)
1484 struct Locale *locale = OpenLocale(NULL);
1486 if (!(code >= 0x09 && code <= 0x0D) && IsPrint(locale, code))
1488 Buffer_KillMarked(data);
1489 if (Buffer_AddChar(data, code))
1491 data->msd_RedrawReason = DO_ADDCHAR;
1492 return 2;
1496 CloseLocale(locale);
1499 data->msd_RedrawReason = DO_UNKNOWN;
1500 return 0;
1504 /**************************************************************************
1505 MUIM_HandleEvent
1506 **************************************************************************/
1507 IPTR String__MUIM_HandleEvent(struct IClass *cl, Object *obj,
1508 struct MUIP_HandleEvent *msg)
1510 struct MUI_StringData *data =
1511 (struct MUI_StringData *)INST_DATA(cl, obj);
1512 IPTR retval = 0;
1513 int update = 0;
1514 BOOL edited = FALSE;
1515 LONG muikey = msg->muikey;
1516 BOOL cursor_kills_marking = FALSE;
1518 if ((data->msd_Flags & MSDF_MARKING)
1519 && !(data->msd_Flags & MSDF_KEYMARKING))
1521 cursor_kills_marking = TRUE;
1524 /* Convert raw keys to MUI keys for marking */
1525 if (muikey == MUIKEY_NONE && msg->imsg != NULL)
1527 if (msg->imsg->Class == IDCMP_RAWKEY)
1529 static LONG muikeytable[3][2] = {
1530 {MUIKEY_LEFT, MUIKEY_RIGHT},
1531 {MUIKEY_WORDLEFT, MUIKEY_WORDRIGHT},
1532 {MUIKEY_LINESTART, MUIKEY_LINEEND}
1534 WORD dirindex = -1, amountindex = 0;
1536 switch (msg->imsg->Code)
1538 case 0x4F:
1539 dirindex = 0;
1540 break;
1542 case 0x4E:
1543 dirindex = 1;
1544 break;
1546 #ifdef __AROS__
1547 case RAWKEY_HOME:
1548 muikey = MUIKEY_LINESTART;
1549 break;
1551 case RAWKEY_END:
1552 muikey = MUIKEY_LINEEND;
1553 break;
1554 #endif
1558 if (dirindex != -1)
1560 if (msg->imsg->
1561 Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
1563 amountindex = 2;
1565 else if (msg->imsg->Qualifier & IEQUALIFIER_CONTROL)
1567 amountindex = 1;
1570 muikey = muikeytable[amountindex][dirindex];
1576 D(bug("String_HandleEvent: muikey %d, imsg %p is_active=%d\n", muikey,
1577 msg->imsg, data->is_active));
1578 if (muikey != MUIKEY_NONE && data->is_active)
1580 retval = MUI_EventHandlerRC_Eat;
1582 switch (muikey)
1584 case MUIKEY_LEFT:
1585 if (cursor_kills_marking)
1587 update = 1;
1588 data->BufferPos = MIN(data->BufferPos, data->MarkPos);
1589 if (data->BufferPos > 0)
1590 data->BufferPos--;
1592 data->msd_Flags &= ~MSDF_MARKING;
1594 else if (data->BufferPos > 0)
1596 update = 1;
1598 data->BufferPos--;
1599 data->msd_RedrawReason = DO_CURSOR_LEFT;
1601 break;
1602 case MUIKEY_RIGHT:
1603 if (cursor_kills_marking)
1605 update = 1;
1606 data->BufferPos = MAX(data->BufferPos, data->MarkPos);
1607 data->msd_Flags &= ~MSDF_MARKING;
1609 else if (data->BufferPos < data->NumChars)
1611 update = 1;
1612 data->BufferPos++;
1613 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1615 break;
1616 case MUIKEY_WORDLEFT:
1617 if (data->BufferPos > 0)
1619 data->BufferPos =
1620 Buffer_GetPrevWordIndex(data, data->BufferPos);
1621 update = 1;
1622 data->msd_RedrawReason = DO_CURSOR_LEFT;
1624 if (cursor_kills_marking)
1626 data->msd_Flags &= ~MSDF_MARKING;
1627 update = 1;
1629 break;
1630 case MUIKEY_WORDRIGHT:
1631 if (data->BufferPos < data->NumChars)
1633 data->BufferPos =
1634 Buffer_GetSuccWordIndex(data, data->BufferPos);
1635 update = 1;
1636 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1638 if (cursor_kills_marking)
1640 data->msd_Flags &= ~MSDF_MARKING;
1641 update = 1;
1643 break;
1644 case MUIKEY_LINESTART:
1645 data->BufferPos = 0;
1646 update = 1;
1647 if (cursor_kills_marking)
1649 data->msd_Flags &= ~MSDF_MARKING;
1651 break;
1653 case MUIKEY_LINEEND:
1654 data->BufferPos = data->NumChars;
1655 update = 1;
1656 if (cursor_kills_marking)
1658 data->msd_Flags &= ~MSDF_MARKING;
1660 break;
1662 case MUIKEY_UP:
1663 if (data->msd_AttachedList)
1664 set(data->msd_AttachedList,
1665 MUIA_List_Active, MUIV_List_Active_Up);
1666 break;
1667 case MUIKEY_DOWN:
1668 if (data->msd_AttachedList)
1669 set(data->msd_AttachedList,
1670 MUIA_List_Active, MUIV_List_Active_Down);
1671 break;
1672 case MUIKEY_PAGEUP:
1673 if (data->msd_AttachedList)
1674 set(data->msd_AttachedList,
1675 MUIA_List_Active, MUIV_List_Active_PageUp);
1676 break;
1677 case MUIKEY_PAGEDOWN:
1678 if (data->msd_AttachedList)
1679 set(data->msd_AttachedList,
1680 MUIA_List_Active, MUIV_List_Active_PageDown);
1681 break;
1682 case MUIKEY_TOP:
1683 if (data->msd_AttachedList)
1684 set(data->msd_AttachedList,
1685 MUIA_List_Active, MUIV_List_Active_Top);
1686 break;
1687 case MUIKEY_BOTTOM:
1688 if (data->msd_AttachedList)
1689 set(data->msd_AttachedList,
1690 MUIA_List_Active, MUIV_List_Active_Bottom);
1691 break;
1692 case MUIKEY_PRESS:
1694 UBYTE *buf = NULL;
1695 LONG val = 0;
1697 get(obj, MUIA_String_Contents, &buf);
1699 if (data->msd_Flags & MSDF_STAYACTIVE)
1701 /* Do not change active object */
1703 else if (data->msd_Flags & MSDF_ADVANCEONCR)
1705 set(_win(obj), MUIA_Window_ActiveObject,
1706 MUIV_Window_ActiveObject_Next);
1708 else if (!(data->msd_Flags & MSDF_STAYACTIVE))
1710 set(_win(obj), MUIA_Window_ActiveObject,
1711 MUIV_Window_ActiveObject_None);
1714 /* Notify listeners of new string value */
1715 set(obj, MUIA_String_Acknowledge, buf);
1717 /* Notify listeners of new integer value (if any) */
1718 if (StrToLong(buf, &val) >= 0)
1719 superset(cl, obj, MUIA_String_Integer, val);
1721 break;
1723 case MUIKEY_WINDOW_CLOSE:
1724 data->is_active = FALSE;
1725 set(obj, MUIA_Background,
1726 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
1727 DoMethod(obj, MUIM_GoInactive);
1728 retval = 0;
1729 break;
1731 default:
1732 retval = 0;
1733 } // switch(muikey)
1734 } // if (muikey != MUIKEY_NONE)
1736 if (msg->imsg)
1738 UWORD code = msg->imsg->Code;
1739 //UWORD qual = msg->imsg->Qualifier;
1740 WORD x = msg->imsg->MouseX;
1741 WORD y = msg->imsg->MouseY;
1743 //bug("String_HandleEvent: parsing imsg %p, class=%ld\n",
1744 // msg->imsg, msg->imsg->Class);
1746 switch (msg->imsg->Class)
1748 case IDCMP_MOUSEBUTTONS: /* set cursor and activate it */
1749 if (code == SELECTDOWN)
1751 //bug("String_HandleEvent: code == SELECTDOWN, x=%d y=%d\n",
1752 // x, y);
1754 if (_isinobject(obj, x, y))
1756 UWORD text_left, text_right;
1758 retval = MUI_EventHandlerRC_Eat;
1760 CurrentTime(&data->NewClick_Sec, &data->NewClick_Micro);
1761 if (DoubleClick(data->OldClick_Sec,
1762 data->OldClick_Micro, data->NewClick_Sec,
1763 data->NewClick_Micro))
1765 data->MultiClick++;
1767 else
1769 data->MultiClick = 0;
1771 data->OldClick_Sec = data->NewClick_Sec;
1772 data->OldClick_Micro = data->NewClick_Micro;
1774 //kprintf("multiclick %d\n", data->MultiClick);
1776 if (!data->is_active)
1778 //bug("String got button, lets activate\n");
1779 data->is_active = TRUE;
1780 data->msd_RedrawReason = WENT_ACTIVE;
1781 // redraw
1782 set(obj, MUIA_Background,
1783 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->
1784 string_bg_active);
1786 //DoMethod(obj, MUIM_GoActive);
1787 set(_win(obj), MUIA_Window_ActiveObject, obj);
1788 // let other objects a chance to get desactivated
1789 //retval = 0;
1792 if (!(data->ehn.ehn_Events & IDCMP_MOUSEMOVE))
1794 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1795 (IPTR) & data->ehn);
1796 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
1797 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1798 (IPTR) & data->ehn);
1801 PrepareVisualBuffer(data);
1802 text_left = GetTextLeft(cl, obj);
1803 text_right = GetTextRight(cl, obj);
1804 CleanVisualBuffer(data);
1806 /* Check if mouseclick is inside displayed text */
1807 if ((x >= text_left) && (x <= text_right))
1809 /* Find new cursor pos. */
1810 struct TextExtent te;
1811 ULONG newpos;
1812 STRPTR dispstr = data->Buffer + data->DispPos;
1814 newpos = data->DispPos
1815 + TextFit(_rp(obj), dispstr,
1816 data->NumChars - data->DispPos, &te, NULL, 1,
1817 x - text_left, _rp(obj)->Font->tf_YSize);
1819 if (data->BufferPos != newpos)
1821 data->BufferPos = newpos;
1822 update = 1;
1825 else if (x < text_left)
1827 /* Click on empty space at left. Set cursor to first
1828 * visible */
1829 if (data->BufferPos != data->DispPos)
1831 data->BufferPos = data->DispPos;
1832 update = 1;
1835 else
1837 /* Click on empty space at right. Set cursor to last
1838 * visible */
1839 if (data->BufferPos !=
1840 data->DispPos + data->DispCount)
1842 data->BufferPos =
1843 data->DispPos + data->DispCount;
1844 update = 1;
1846 } /* if (click is on text or not) */
1848 data->MarkPos = data->BufferPos;
1850 if (data->MultiClick == 0)
1852 if (data->msd_Flags & MSDF_MARKING)
1854 data->msd_Flags &= ~MSDF_MARKING;
1855 update = 1;
1858 else if (data->MultiClick
1859 && Buffer_GetMarkedRange(data, NULL, NULL))
1861 data->msd_Flags |= MSDF_MARKING;
1862 update = 1;
1866 } /* is in object */
1867 else if (data->is_active
1868 && !(data->msd_Flags & MSDF_STAYACTIVE))
1869 /* and click not on object */
1871 data->is_active = FALSE;
1872 set(obj, MUIA_Background,
1873 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->
1874 string_bg_inactive);
1875 //DoMethod(obj, MUIM_GoInactive);
1876 // let other objects a chance to get activated
1877 //retval = 0;
1879 } /* if (code == SELECTDOWN) */
1880 else if (code == SELECTUP)
1882 if (data->ehn.ehn_Events & IDCMP_MOUSEMOVE)
1884 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1885 (IPTR) & data->ehn);
1886 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
1887 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1888 (IPTR) & data->ehn);
1891 break;
1893 case IDCMP_MOUSEMOVE:
1894 if (data->is_active)
1896 UWORD text_left, text_right;
1898 if (!(data->msd_Flags & MSDF_MARKING))
1900 data->msd_Flags |= MSDF_MARKING;
1903 PrepareVisualBuffer(data);
1904 text_left = GetTextLeft(cl, obj);
1905 text_right = GetTextRight(cl, obj);
1906 CleanVisualBuffer(data);
1908 /* Check if mouseclick is inside displayed text */
1909 if ((x >= text_left) && (x <= text_right))
1911 /* Find new cursor pos. */
1912 struct TextExtent te;
1913 ULONG newpos;
1914 STRPTR dispstr = data->Buffer + data->DispPos;
1916 newpos = data->DispPos
1917 + TextFit(_rp(obj), dispstr,
1918 data->NumChars - data->DispPos, &te, NULL, 1,
1919 x - text_left, _rp(obj)->Font->tf_YSize);
1921 if (data->BufferPos != newpos)
1923 WORD old_markstart = 0, old_markstop = 0;
1924 WORD markstart = 0, markstop = 0;
1925 BOOL was_marked, is_marked;
1927 was_marked = Buffer_AnythingMarked(data) &&
1928 Buffer_GetMarkedRange(data, &old_markstart,
1929 &old_markstop);
1931 data->BufferPos = newpos;
1933 is_marked = Buffer_AnythingMarked(data) &&
1934 Buffer_GetMarkedRange(data, &markstart,
1935 &markstop);
1937 if ((was_marked != is_marked) ||
1938 (old_markstart != markstart) ||
1939 (old_markstop != markstop))
1941 update = 1;
1945 else if ((x < text_left) && (data->BufferPos > 0))
1947 data->BufferPos--;
1948 update = 1;
1949 data->msd_RedrawReason = DO_CURSOR_LEFT;
1951 else if ((x > text_right)
1952 && (data->BufferPos < data->NumChars))
1954 data->BufferPos++;
1955 update = 1;
1956 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1958 //kprintf(" ---- bp: %d\n", data->BufferPos);
1960 break;
1962 case IDCMP_RAWKEY:
1964 unsigned char code;
1966 //bug("String_HandleEvent: idcmp_rawkey\n");
1968 if (!data->is_active)
1969 break;
1971 code = ConvertKey(msg->imsg);
1972 if (!code)
1974 switch (msg->imsg->Code)
1976 case 0x64: /* LALT */
1977 case 0x65: /* RALT */
1978 case 0x64 | IECODE_UP_PREFIX:
1979 case 0x65 | IECODE_UP_PREFIX:
1980 if (msg->imsg->
1981 Qualifier & (IEQUALIFIER_LALT |
1982 IEQUALIFIER_RALT))
1984 data->MarkPos = data->BufferPos;
1985 data->msd_Flags |=
1986 (MSDF_MARKING | MSDF_KEYMARKING);
1988 else
1990 data->msd_Flags &= ~MSDF_KEYMARKING;
1992 break;
1997 if (code)
1999 update =
2000 String_HandleVanillakey(cl, obj, code,
2001 msg->imsg->Qualifier, &retval);
2002 if (update)
2004 retval = MUI_EventHandlerRC_Eat;
2005 edited = TRUE;
2009 break;
2013 /* Trigger notification */
2014 if (edited)
2015 superset(cl, obj, MUIA_String_Contents, data->Buffer);
2017 if (update)
2019 MUI_Redraw(obj, MADF_DRAWUPDATE);
2021 //D(bug("String eh return %ld\n", retval));
2023 return retval;
2027 /**************************************************************************
2028 MUIM_Export : to export an object's "contents" to a dataspace object.
2029 **************************************************************************/
2030 IPTR String__MUIM_Export(struct IClass *cl, Object *obj,
2031 struct MUIP_Export *msg)
2033 struct MUI_StringData *data = INST_DATA(cl, obj);
2034 ULONG id;
2036 if ((id = muiNotifyData(obj)->mnd_ObjectID))
2038 if (data->Buffer != NULL)
2039 DoMethod(msg->dataspace, MUIM_Dataspace_Add,
2040 (IPTR) data->Buffer, data->NumChars + 1, (IPTR) id);
2041 else
2042 DoMethod(msg->dataspace, MUIM_Dataspace_Remove, (IPTR) id);
2045 return 0;
2049 /**************************************************************************
2050 MUIM_Import : to import an object's "contents" from a dataspace object.
2051 **************************************************************************/
2052 IPTR String__MUIM_Import(struct IClass *cl, Object *obj,
2053 struct MUIP_Import *msg)
2055 ULONG id;
2056 STRPTR s;
2058 if ((id = muiNotifyData(obj)->mnd_ObjectID))
2060 if ((s = (STRPTR) DoMethod(msg->dataspace, MUIM_Dataspace_Find,
2061 (IPTR) id)))
2063 set(obj, MUIA_String_Contents, s);
2067 return 0;
2070 /**************************************************************************
2071 MUIM_GoActive
2072 **************************************************************************/
2073 IPTR String__MUIM_GoActive(struct IClass *cl, Object *obj, Msg msg)
2075 struct MUI_StringData *data =
2076 (struct MUI_StringData *)INST_DATA(cl, obj);
2078 //D(bug("String_GoActive %p\n", obj));
2079 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
2080 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
2081 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
2082 data->is_active = TRUE;
2083 data->msd_Flags &= ~MSDF_KEYMARKING;
2084 data->msd_RedrawReason = WENT_ACTIVE;
2085 // redraw
2086 set(obj, MUIA_Background,
2087 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_active);
2089 return 0;
2092 /**************************************************************************
2093 MUIM_GoInactive
2094 **************************************************************************/
2095 IPTR String__MUIM_GoInactive(struct IClass *cl, Object *obj, Msg msg)
2097 struct MUI_StringData *data =
2098 (struct MUI_StringData *)INST_DATA(cl, obj);
2100 //D(bug("String_GoInactive %p\n", obj));
2102 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
2103 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
2104 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
2105 data->is_active = FALSE;
2106 data->msd_RedrawReason = WENT_INACTIVE;
2107 data->MultiClick = 0;
2109 // redraw
2110 set(obj, MUIA_Background,
2111 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
2113 return 0;
2116 /**************************************************************************
2117 MUIM_String_ClearSelected (BetterString)
2118 **************************************************************************/
2119 IPTR String__MUIM_ClearSelected(struct IClass *cl, Object *obj,
2120 struct MUIP_String_ClearSelected *msg)
2122 struct MUI_StringData *data =
2123 (struct MUI_StringData *)INST_DATA(cl, obj);
2125 //D(bug("String_ClearSelected %p\n", obj));
2127 if (Buffer_KillMarked(data))
2129 MUI_Redraw(obj, MADF_DRAWUPDATE);
2132 return 0;
2135 /**************************************************************************
2136 MUIM_String_Insert (BetterString)
2137 **************************************************************************/
2138 IPTR String__MUIM_Insert(struct IClass *cl, Object *obj,
2139 struct MUIP_String_Insert *msg)
2141 struct MUI_StringData *data =
2142 (struct MUI_StringData *)INST_DATA(cl, obj);
2143 LONG pos;
2144 ULONG old_bufferpos;
2145 ULONG num_inserted = 0;
2147 //D(bug("String_Insert %p\n", obj));
2149 switch ((ULONG) msg->pos)
2151 case MUIV_String_Insert_StartOfString:
2152 pos = 0;
2153 break;
2155 case MUIV_String_Insert_EndOfString:
2156 pos = data->NumChars;
2157 break;
2159 case MUIV_String_Insert_BufferPos:
2160 pos = data->BufferPos;
2161 break;
2163 default:
2164 pos = msg->pos;
2165 break;
2168 if ((pos < 0) || (pos > data->NumChars))
2169 return 0;
2171 old_bufferpos = data->BufferPos;
2172 data->BufferPos = pos;
2174 while (msg->text[num_inserted]
2175 && Buffer_AddChar(data, msg->text[num_inserted]))
2177 num_inserted++;
2180 if (num_inserted)
2182 if (old_bufferpos >= pos)
2184 data->BufferPos = old_bufferpos + num_inserted;
2186 else
2188 data->BufferPos = old_bufferpos;
2191 MUI_Redraw(obj, MADF_DRAWUPDATE);
2194 return 0;
2197 /**************************************************************************
2198 MUIM_String_FileNameStart (BetterString)
2199 **************************************************************************/
2200 IPTR String__MUIM_FileNameStart(struct IClass *cl, Object *obj,
2201 struct MUIP_String_FileNameStart *msg)
2203 struct MUI_StringData *data =
2204 (struct MUI_StringData *)INST_DATA(cl, obj);
2205 STRPTR buf;
2207 //D(bug("String_FileNameStart %p\n", obj));
2209 buf = data->Buffer;
2211 // TODO: Implement String_FileNameStart correctly!
2213 return (IPTR) buf;
2216 BOOPSI_DISPATCHER(IPTR, String_Dispatcher, cl, obj, msg)
2218 switch (msg->MethodID)
2220 case OM_NEW:
2221 return String__OM_NEW(cl, obj, (struct opSet *)msg);
2222 case OM_DISPOSE:
2223 return String__OM_DISPOSE(cl, obj, msg);
2224 case OM_SET:
2225 return String__OM_SET(cl, obj, (struct opSet *)msg);
2226 case OM_GET:
2227 return String__OM_GET(cl, obj, (struct opGet *)msg);
2229 case MUIM_Setup:
2230 return String__MUIM_Setup(cl, obj, (APTR) msg);
2231 case MUIM_Cleanup:
2232 return String__MUIM_Cleanup(cl, obj, (APTR) msg);
2233 case MUIM_AskMinMax:
2234 return String__MUIM_AskMinMax(cl, obj, (APTR) msg);
2235 case MUIM_Draw:
2236 return String__MUIM_Draw(cl, obj, (APTR) msg);
2237 case MUIM_Export:
2238 return String__MUIM_Export(cl, obj, (APTR) msg);
2239 case MUIM_Import:
2240 return String__MUIM_Import(cl, obj, (APTR) msg);
2241 case MUIM_GoActive:
2242 return String__MUIM_GoActive(cl, obj, (APTR) msg);
2243 case MUIM_GoInactive:
2244 return String__MUIM_GoInactive(cl, obj, (APTR) msg);
2245 case MUIM_HandleEvent:
2246 return String__MUIM_HandleEvent(cl, obj, (APTR) msg);
2248 /* BetterString */
2249 case MUIM_String_ClearSelected:
2250 return String__MUIM_ClearSelected(cl, obj, (APTR) msg);
2251 case MUIM_String_Insert:
2252 return String__MUIM_Insert(cl, obj, (APTR) msg);
2253 case MUIM_String_FileNameStart:
2254 return String__MUIM_FileNameStart(cl, obj, (APTR) msg);
2257 return DoSuperMethodA(cl, obj, msg);
2259 BOOPSI_DISPATCHER_END
2262 * Class descriptor.
2264 const struct __MUIBuiltinClass _MUI_String_desc =
2266 MUIC_String,
2267 MUIC_Area,
2268 sizeof(struct MUI_StringData),
2269 (void *)String_Dispatcher