Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / muimaster / classes / string.c
blob161584e4589b0611ce910b18bb00097a0fa73642
1 /*
2 Copyright © 2003-2006, 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 ULONG BufferSize; /* memory allocated */
60 STRPTR SecBuffer; /* Buffer for secret string */
61 ULONG NumChars; /* string length */
62 ULONG BufferPos; /* cursor (insert/delete) position */
63 ULONG MarkPos; /* cursor text marking start pos */
64 LONG DispPos; /* leftmost visible char */
65 ULONG DispCount; /* number of visible chars */
67 ULONG OldClick_Sec;
68 ULONG OldClick_Micro;
69 ULONG NewClick_Sec;
70 ULONG NewClick_Micro;
71 WORD MultiClick;
73 WORD Columns;
75 struct MUI_EventHandlerNode ehn;
76 struct MUI_PenSpec_intern inactive_text;
77 struct MUI_PenSpec_intern active_text;
78 struct MUI_PenSpec_intern marked_text;
79 struct MUI_PenSpec_intern marked_bg;
80 struct MUI_PenSpec_intern cursor;
82 BOOL is_active;
85 #define MSDF_ADVANCEONCR (1<<0)
86 #define MSDF_LONELYEDITHOOK (1<<1)
87 #define MSDF_MARKING (1<<2)
88 #define MSDF_KEYMARKING (1<<3)
89 #define MSDF_NOINPUT (1<<4)
90 #define MSDF_STAYACTIVE (1<<5)
92 enum
94 NO_REASON = 0,
95 WENT_ACTIVE = 1,
96 WENT_INACTIVE,
97 DO_CURSOR_LEFT = 3,
98 DO_CURSOR_RIGHT,
99 DO_DELETE = 5,
100 DO_BACKSPACE,
101 DO_ADDCHAR = 7,
102 NEW_CONTENTS,
103 MOVE_CURSOR,
104 DO_UNKNOWN,
108 /**************************************************************************
109 Buffer_SetNewContents
110 Allocate memory for buffer
111 **************************************************************************/
112 static BOOL Buffer_Alloc(struct MUI_StringData *data)
114 data->Buffer =
115 (STRPTR) AllocVec(data->BufferSize * sizeof(char), MEMF_ANY);
116 if (NULL == data->Buffer)
118 bug("MUIC_String: Can't allocate %ld bytes for buffer1\n",
119 data->BufferSize * sizeof(char));
120 return FALSE;
122 if (data->msd_useSecret)
124 data->SecBuffer =
125 (STRPTR) AllocVec(data->BufferSize * sizeof(char), MEMF_ANY);
126 if (NULL == data->SecBuffer)
128 bug("MUIC_String: Can't allocate %ld bytes for buffer2\n",
129 data->BufferSize * sizeof(char));
130 FreeVec(data->Buffer);
131 data->Buffer = NULL;
132 return FALSE;
135 return TRUE;
138 /**************************************************************************
139 Buffer_SetNewContents
140 Initialize buffer with a string, replace former content if any
141 **************************************************************************/
142 static BOOL Buffer_SetNewContents(struct MUI_StringData *data,
143 CONST_STRPTR str)
145 if (NULL == data->Buffer)
146 return FALSE;
148 if (NULL == str)
150 data->Buffer[0] = 0;
151 if (data->msd_useSecret)
152 data->SecBuffer[0] = 0;
153 data->NumChars = 0;
155 else
157 data->NumChars = strlen(str);
158 if (data->NumChars >= data->BufferSize)
159 data->NumChars = data->BufferSize - 1;
161 if (data->msd_useSecret)
163 strncpy(data->SecBuffer, str, data->BufferSize);
164 data->SecBuffer[data->BufferSize - 1] = 0;
165 int i;
166 for (i = 0; i < data->NumChars; i++)
167 data->Buffer[i] = 0x78;
168 data->Buffer[data->NumChars] = 0;
170 else
172 strncpy(data->Buffer, str, data->BufferSize);
173 data->Buffer[data->BufferSize - 1] = 0;
178 // avoid to BufferPos jumps to end of string if characters are inserted
179 // in string
180 if (data->BufferPos > data->NumChars)
181 data->BufferPos = data->NumChars;
182 data->DispPos = 0;
183 return TRUE;
186 /**************************************************************************
187 Buffer_AddChar
188 Add a char on cursor position
189 **************************************************************************/
190 static BOOL Buffer_AddChar(struct MUI_StringData *data, unsigned char code)
192 STRPTR dst;
194 if (data->Buffer == NULL)
195 return FALSE;
197 if (data->NumChars + 1 >= data->BufferSize)
198 return FALSE;
200 if (data->msd_useSecret)
202 dst = &data->SecBuffer[data->BufferPos + 1];
204 memmove(dst, &data->SecBuffer[data->BufferPos],
205 data->NumChars - data->BufferPos);
207 data->Buffer[data->NumChars] = 0x78;
208 data->Buffer[data->NumChars + 1] = 0;
210 else
212 dst = &data->Buffer[data->BufferPos + 1];
214 memmove(dst, &data->Buffer[data->BufferPos],
215 data->NumChars - data->BufferPos);
219 dst[data->NumChars - data->BufferPos] = 0;
220 dst[-1] = code;
222 data->BufferPos++;
223 data->NumChars++;
224 return TRUE;
227 static WORD Buffer_GetWordStartIndex(struct MUI_StringData *data,
228 WORD startindex)
230 WORD index = startindex;
232 while (index > 0)
234 if (data->Buffer[index - 1] == ' ')
236 break;
238 index--;
241 return index;
244 static WORD Buffer_GetWordEndIndex(struct MUI_StringData *data,
245 WORD startindex)
247 WORD index = startindex;
249 while (index < data->NumChars)
251 if (data->Buffer[index] == ' ')
253 break;
255 index++;
258 return index;
261 static WORD Buffer_GetPrevWordIndex(struct MUI_StringData *data,
262 WORD startindex)
264 WORD index = startindex;
266 while (index > 0)
268 index--;
270 if ((index == 0) ||
271 ((data->Buffer[index - 1] == ' ') &&
272 (data->Buffer[index] != ' ')))
274 break;
279 return index;
282 static WORD Buffer_GetSuccWordIndex(struct MUI_StringData *data,
283 WORD startindex)
285 WORD index = startindex;
287 while (index < data->NumChars)
289 index++;
291 if ((index == data->NumChars) ||
292 ((data->Buffer[index - 1] == ' ') &&
293 (data->Buffer[index] != ' ')))
295 break;
299 return index;
302 static BOOL Buffer_GetMarkedRange(struct MUI_StringData *data, WORD *start,
303 WORD *stop)
305 WORD markstart = data->MarkPos;
306 WORD markstop = data->BufferPos;
308 markstart = MIN(markstart, data->NumChars);
309 markstart = MAX(markstart, 0);
311 markstop = MIN(markstop, data->NumChars);
312 markstop = MAX(markstop, 0);
314 if (markstart > markstop)
316 markstart ^= markstop;
317 markstop ^= markstart;
318 markstart ^= markstop;
321 switch (data->MultiClick)
323 case 0:
324 /* char select */
325 break;
327 case 1:
328 /* word select */
329 markstart = Buffer_GetWordStartIndex(data, markstart);
330 markstop = Buffer_GetWordEndIndex(data, markstop);
331 break;
333 default:
334 /* select all */
335 markstart = 0;
336 markstop = data->NumChars;
337 break;
341 if (markstart == markstop)
342 return FALSE;
344 if (start)
345 *start = markstart;
346 if (stop)
347 *stop = markstop;
349 //kprintf("Buffer_GetMarkedRange: returning %d .. %d\n",
350 // markstart, markstop);
352 return TRUE;
355 static BOOL Buffer_AnythingMarked(struct MUI_StringData *data)
357 if (!(data->msd_Flags & MSDF_MARKING))
358 return FALSE;
360 return Buffer_GetMarkedRange(data, NULL, NULL);
363 static BOOL Buffer_KillMarked(struct MUI_StringData *data)
365 WORD markstart = data->MarkPos;
366 WORD markstop = data->BufferPos;
367 WORD marklen;
369 //kprintf("\nBuffer_KillMarked 1 markpos %d bufferpos %d numchars %d\n",
370 // markstart, markstop, data->NumChars);
372 if (!(data->msd_Flags & MSDF_MARKING))
373 return FALSE;
375 data->msd_Flags &= ~MSDF_MARKING;
377 if (!Buffer_GetMarkedRange(data, &markstart, &markstop))
378 return FALSE;
380 //kprintf("Buffer_KillMarked 2 markstart %d markstop %d\n",
381 // markstart, markstop);
383 if (markstart > markstop)
385 markstart ^= markstop;
386 markstop ^= markstart;
387 markstart ^= markstop;
390 marklen = markstop - markstart;
392 //kprintf("Buffer_KillMarked: markstart %d markstop %d\n",
393 // markstart, markstop);
395 memmove(&data->Buffer[markstart],
396 &data->Buffer[markstart + marklen],
397 data->NumChars - markstart - marklen + 1);
399 data->NumChars -= marklen;
400 data->BufferPos = markstart;
402 return TRUE;
405 /**************************************************************************
406 OM_NEW
407 **************************************************************************/
408 IPTR String__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
410 struct MUI_StringData *data;
411 struct TagItem *tags, *tag;
412 CONST_STRPTR str = NULL;
413 char integerbuf[20];
415 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
416 /* MUIA_FillArea, TRUE, */
417 TAG_MORE, (IPTR) msg->ops_AttrList);
418 if (!obj)
419 return FALSE;
421 data = INST_DATA(cl, obj);
422 data->msd_useSecret = FALSE;
423 data->msd_Align = MUIV_String_Format_Left;
424 data->BufferSize = 80;
425 data->Columns = -1;
427 Buffer_SetNewContents(data, ""); /* <-- isnt this pointless? */
429 /* parse initial taglist */
430 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
432 switch (tag->ti_Tag)
434 case MUIA_String_Accept:
435 data->msd_Accept = (CONST_STRPTR) tag->ti_Data;
436 break;
438 case MUIA_String_Reject:
439 data->msd_Reject = (CONST_STRPTR) tag->ti_Data;
440 break;
442 case MUIA_String_AdvanceOnCR:
443 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
444 MSDF_ADVANCEONCR);
445 break;
447 case MUIA_String_AttachedList:
448 data->msd_AttachedList = (Object *) tag->ti_Data;
449 break;
451 case MUIA_String_Secret:
452 data->msd_useSecret = (BOOL) tag->ti_Data;
453 break;
455 case MUIA_String_Contents:
456 str = (CONST_STRPTR) tag->ti_Data;
457 break;
459 case MUIA_String_EditHook:
460 data->msd_EditHook = (struct Hook *)tag->ti_Data;
461 break;
463 case MUIA_String_Format:
464 data->msd_Align = (LONG) tag->ti_Data;
465 break;
467 case MUIA_String_Integer:
468 snprintf(integerbuf, 19, "%ld", tag->ti_Data);
469 str = integerbuf;
470 break;
472 case MUIA_String_LonelyEditHook:
473 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
474 MSDF_LONELYEDITHOOK);
475 break;
477 case MUIA_String_MaxLen:
478 data->BufferSize = tag->ti_Data;
479 if (data->BufferSize < 1)
480 data->BufferSize = 1;
481 break;
483 case MUIA_String_Columns: /* BetterString */
484 data->Columns = (WORD) tag->ti_Data;
485 break;
487 case MUIA_String_NoInput: /* BetterString */
488 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_NOINPUT);
489 break;
491 case MUIA_String_StayActive: /* BetterString */
492 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
493 MSDF_STAYACTIVE);
494 break;
499 if (Buffer_Alloc(data))
501 Buffer_SetNewContents(data, str);
504 if (NULL == data->Buffer)
506 CoerceMethod(cl, obj, OM_DISPOSE);
507 return 0;
510 D(bug("String_New(%p)\n", obj));
512 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
513 data->ehn.ehn_Priority = 0;
514 data->ehn.ehn_Flags = 0;
515 data->ehn.ehn_Object = obj;
516 data->ehn.ehn_Class = cl;
518 CurrentTime(&data->OldClick_Sec, &data->OldClick_Micro);
520 return (IPTR) obj;
523 /**************************************************************************
524 OM_DISPOSE
525 **************************************************************************/
526 IPTR String__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
528 struct MUI_StringData *data = INST_DATA(cl, obj);
530 FreeVec(data->Buffer);
531 FreeVec(data->SecBuffer);
533 D(bug("String_Dispose %p\n", obj));
535 return DoSuperMethodA(cl, obj, msg);
538 /**************************************************************************
539 OM_SET
540 **************************************************************************/
541 IPTR String__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
543 struct MUI_StringData *data = INST_DATA(cl, obj);
544 struct TagItem *tags = msg->ops_AttrList;
545 struct TagItem *tag;
547 while ((tag = NextTagItem(&tags)) != NULL)
549 switch (tag->ti_Tag)
551 case MUIA_String_Contents:
552 Buffer_SetNewContents(data, (STRPTR) tag->ti_Data);
553 data->msd_RedrawReason = NEW_CONTENTS;
554 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
555 MUI_Redraw(obj, MADF_DRAWOBJECT);
556 break;
558 case MUIA_String_Accept:
559 data->msd_Accept = (CONST_STRPTR) tag->ti_Data;
560 break;
562 case MUIA_String_Reject:
563 data->msd_Reject = (CONST_STRPTR) tag->ti_Data;
564 break;
566 case MUIA_String_AttachedList:
567 data->msd_AttachedList = (Object *) tag->ti_Data;
568 break;
570 case MUIA_String_Integer:
572 char buf[20];
574 snprintf(buf, 19, "%ld", tag->ti_Data);
575 set(obj, MUIA_String_Contents, buf);
577 break;
579 case MUIA_String_AdvanceOnCR:
580 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
581 MSDF_ADVANCEONCR);
582 break;
584 case MUIA_String_BufferPos:
585 data->BufferPos = (ULONG) tag->ti_Data;
586 data->msd_Flags &= ~MSDF_MARKING;
587 data->msd_RedrawReason = MOVE_CURSOR;
588 MUI_Redraw(obj, MADF_DRAWUPDATE);
589 break;
591 case MUIA_String_DisplayPos:
592 data->BufferPos = (ULONG) tag->ti_Data;
593 data->DispPos = data->BufferPos; // move both pos
594 data->msd_Flags &= ~MSDF_MARKING;
595 data->msd_RedrawReason = MOVE_CURSOR;
596 MUI_Redraw(obj, MADF_DRAWUPDATE);
597 break;
599 case MUIA_String_NoInput: /* BetterString */
600 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_NOINPUT);
601 break;
603 case MUIA_String_StayActive: /* BetterString */
604 _handle_bool_tag(data->msd_Flags, tag->ti_Data,
605 MSDF_STAYACTIVE);
606 break;
608 case MUIA_String_SelectSize: /* BetterString */
609 // TODO: Implement OM_SET(MUIA_String_SelectSize)!
610 break;
615 return DoSuperMethodA(cl, obj, (Msg) msg);
619 /**************************************************************************
620 OM_GET
621 **************************************************************************/
622 IPTR String__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
624 struct MUI_StringData *data = INST_DATA(cl, obj);
626 #define STORE *(msg->opg_Storage)
627 switch (msg->opg_AttrID)
629 case MUIA_String_Contents:
630 if (data->msd_useSecret)
631 STORE = (IPTR) data->SecBuffer;
632 else
633 STORE = (IPTR) data->Buffer;
634 return TRUE;
636 case MUIA_String_Secret:
637 STORE = (IPTR) data->msd_useSecret;
638 return TRUE;
640 case MUIA_String_Accept:
641 STORE = (IPTR) data->msd_Accept;
642 return TRUE;
644 case MUIA_String_Reject:
645 STORE = (IPTR) data->msd_Reject;
646 return TRUE;
648 case MUIA_String_AttachedList:
649 STORE = (IPTR) data->msd_AttachedList;
650 return TRUE;
652 case MUIA_String_Integer:
654 STRPTR buf = NULL;
655 STORE = 0;
656 get(obj, MUIA_String_Contents, &buf);
657 if (NULL != buf)
659 LONG val = 0;
660 StrToLong(buf, &val);
661 STORE = val;
663 return TRUE;
666 case MUIA_String_MaxLen:
667 STORE = (IPTR) data->BufferSize;
668 return TRUE;
670 case MUIA_String_AdvanceOnCR:
671 STORE = (data->msd_Flags & MSDF_ADVANCEONCR) ? TRUE : FALSE;
672 return TRUE;
674 case MUIA_String_BufferPos:
675 STORE = data->BufferPos;
676 return TRUE;
678 case MUIA_String_DisplayPos:
679 STORE = data->DispPos;
680 return TRUE;
682 case MUIA_String_NoInput: /* BetterString */
683 STORE = (data->msd_Flags & MSDF_NOINPUT) ? TRUE : FALSE;
684 return TRUE;
686 case MUIA_String_StayActive: /* BetterString */
687 STORE = (data->msd_Flags & MSDF_STAYACTIVE) ? TRUE : FALSE;
688 return TRUE;
690 case MUIA_String_SelectSize: /* BetterString */
691 if (data->msd_Flags & MSDF_MARKING)
693 WORD markstart, markstop;
695 if (Buffer_GetMarkedRange(data, &markstart, &markstop))
697 LONG size = markstop - markstart;
699 if (data->MarkPos < data->BufferPos)
700 size = -size;
702 STORE = (IPTR) size;
704 return 1;
709 STORE = 0;
710 return TRUE;
714 return DoSuperMethodA(cl, obj, (Msg) msg);
715 #undef STORE
718 /**************************************************************************
719 MUIM_Setup
720 **************************************************************************/
721 IPTR String__MUIM_Setup(struct IClass *cl, Object *obj,
722 struct MUIP_Setup *msg)
724 struct MUI_StringData *data = INST_DATA(cl, obj);
726 if (0 == DoSuperMethodA(cl, obj, (Msg) msg))
727 return FALSE;
729 data->is_active = FALSE;
730 set(obj, MUIA_Background,
731 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
733 zune_pen_spec_to_intern(
734 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
735 string_text_inactive, &data->inactive_text);
736 zune_penspec_setup(&data->inactive_text, muiRenderInfo(obj));
738 zune_pen_spec_to_intern(
739 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
740 string_text_active, &data->active_text);
741 zune_penspec_setup(&data->active_text, muiRenderInfo(obj));
743 zune_pen_spec_to_intern(
744 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
745 string_text_marked, &data->marked_text);
746 zune_penspec_setup(&data->marked_text, muiRenderInfo(obj));
748 zune_pen_spec_to_intern(
749 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
750 string_bg_marked, &data->marked_bg);
751 zune_penspec_setup(&data->marked_bg, muiRenderInfo(obj));
753 zune_pen_spec_to_intern(
754 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->
755 string_cursor, &data->cursor);
756 zune_penspec_setup(&data->cursor, muiRenderInfo(obj));
758 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
759 return TRUE;
762 /**************************************************************************
763 MUIM_Cleanup
764 **************************************************************************/
765 IPTR String__MUIM_Cleanup(struct IClass *cl, Object *obj,
766 struct MUIP_Cleanup *msg)
768 struct MUI_StringData *data = INST_DATA(cl, obj);
770 D(bug("String_Cleanup %p\n", obj));
771 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
773 zune_penspec_cleanup(&data->inactive_text);
774 zune_penspec_cleanup(&data->active_text);
775 zune_penspec_cleanup(&data->marked_text);
776 zune_penspec_cleanup(&data->marked_bg);
777 zune_penspec_cleanup(&data->cursor);
779 return (DoSuperMethodA(cl, obj, (Msg) msg));
782 /**************************************************************************
783 MUIM_AskMinMax
784 **************************************************************************/
785 IPTR String__MUIM_AskMinMax(struct IClass *cl, Object *obj,
786 struct MUIP_AskMinMax *msg)
788 struct MUI_StringData *data = INST_DATA(cl, obj);
790 DoSuperMethodA(cl, obj, (Msg) msg);
792 if (data->Columns >= 0)
794 msg->MinMaxInfo->MinWidth += _font(obj)->tf_XSize * data->Columns;
795 msg->MinMaxInfo->DefWidth += _font(obj)->tf_XSize * data->Columns;
796 msg->MinMaxInfo->MaxWidth += _font(obj)->tf_XSize * data->Columns;
798 else
800 msg->MinMaxInfo->MinWidth += _font(obj)->tf_XSize * 4;
801 msg->MinMaxInfo->DefWidth += _font(obj)->tf_XSize * 12;
802 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
805 msg->MinMaxInfo->MinHeight += _font(obj)->tf_YSize;
806 msg->MinMaxInfo->DefHeight += _font(obj)->tf_YSize;
807 msg->MinMaxInfo->MaxHeight += _font(obj)->tf_YSize;
809 /* D(bug("String_AskMinMax(%p): Min=%ldx%ld Max=%ldx%ld Def=%ldx%ld\n", */
810 /* obj, msg->MinMaxInfo->MinWidth, msg->MinMaxInfo->MinHeight, */
811 /* msg->MinMaxInfo->MaxWidth, msg->MinMaxInfo->MaxHeight, */
812 /* msg->MinMaxInfo->DefWidth, msg->MinMaxInfo->DefHeight)); */
814 return TRUE;
818 static WORD MaxDispPos(struct IClass *cl, Object *obj)
820 struct MUI_StringData *data = INST_DATA(cl, obj);
821 WORD numfit, max_disppos, numchars;
822 struct TextExtent te;
823 BOOL cursor_at_end;
825 cursor_at_end = (data->BufferPos == data->NumChars);
827 /* D(bug("MaxDispPos(current length: %d, bufferpos=%d)\n", */
828 /* data->NumChars, data->BufferPos)); */
830 /* D(bug("cursor_at_end: %d\n", cursor_at_end)); */
832 if (cursor_at_end) /* Cursor at end of string ? */
834 /* D(bug("Making cursor last char\n")); */
835 numchars = data->NumChars + 1; /* Take cursor into account */
837 /* This has already been done by UpdateDisp() which called us
838 strinfo->Buffer[strinfo->NumChars] = 0x20;
842 else
844 numchars = data->NumChars;
847 /* Find the amount of characters that fit into the bbox, counting
848 ** from the last character in the buffer and forward,
850 numfit = TextFit(_rp(obj),
851 &(data->Buffer[numchars - 1]),
852 numchars, &te, NULL, -1, _mwidth(obj), _mheight(obj));
854 max_disppos = numchars - numfit;
856 /* if ((max_disppos > 0) && (!cursor_at_end))
857 max_disppos --;
860 /* D(bug("Numchars w/cursor: %d, Numfit: %d, maxdisppos=%d " */
861 /* "bbox->Width = %d te->te_Width = %d\n", */
862 /* numchars, numfit, max_disppos, _mwidth(obj), te.te_Width)); */
864 return max_disppos;
868 static void UpdateDisp(struct IClass *cl, Object *obj)
870 struct MUI_StringData *data = INST_DATA(cl, obj);
871 struct TextExtent te;
872 STRPTR dispstr;
874 /* If the cursor is at the trailing \0, insert a SPACE instead */
875 if (data->BufferPos == data->NumChars)
876 data->Buffer[data->NumChars] = 0x20;
878 /* In this function we check if the cursor has gone outside
879 ** of the visible area (because of application setting
880 ** strinfo->BufferPos or strinfo->DispPos to a different value, or
881 ** because of user input).
882 ** This is made a bit difficult by the rule (R), that there
883 ** should NOT be available space on the right, and characters
884 ** scrolled out at the left, at the same time.
885 ** We have 3 possible scenarios:
886 ** 1) Cursor to the left of DispPos:
887 ** Set DispPos to the lowest of BufferPos and the
888 ** maximum allowed disppos (according to (R) ).
889 ** 2) Cursor to the right of visible area:
890 ** Set dispose sou that the cursor is the last visible character.
891 ** This afheres to (R).
892 ** 3) Cursor inside visible area. Do a check on rule (R),
893 ** and if DispPos > max allowed, then adjust it down,
894 ** so that the last character in the buffer becomes last character
895 ** displayed. (The cursor will still be visible after adjustion)
898 /* 1) Cursor to the left of visible area */
899 if (data->BufferPos < data->DispPos)
901 WORD max_disppos;
903 max_disppos = MaxDispPos(cl, obj);
904 data->DispPos = MIN(data->BufferPos, max_disppos);
906 else /* Cursor equal to the right of disppos [ 2) or 3) ] */
908 UWORD strsize;
910 /* How many pixels are there from current 1st displayed to cursor? */
911 strsize = TextLength(_rp(obj),
912 data->Buffer + data->DispPos,
913 data->BufferPos - data->DispPos + 1);
915 /* 2) More than fits into the gadget ? */
916 if (strsize > _mwidth(obj))
918 /* Compute new DispPos such that the cursor is at the right */
919 data->DispPos = data->BufferPos
920 - TextFit(_rp(obj),
921 &(data->Buffer[data->BufferPos]),
922 data->NumChars, &te, NULL, -1,
923 _mwidth(obj), _mheight(obj)) + 1;
925 /* D(bug("cursor right of visible area, new disppos: %d\n", */
926 /* data->DispPos)); */
928 else /* 3). Cursor inside gadget */
930 WORD max_disppos;
932 max_disppos = MaxDispPos(cl, obj);
933 if (data->DispPos > max_disppos)
934 data->DispPos = max_disppos;
936 } /* if (cursor inside or to the right of visible area ) */
940 /* Update the DispCount */
941 /* It might be necessary with special handling for centre aligned gads */
942 dispstr = &(data->Buffer[data->DispPos]);
943 /* D(bug("DispCount before = %d\n", data->DispCount)); */
944 data->DispCount = TextFit(_rp(obj), dispstr,
945 data->NumChars - data->DispPos,
946 &te, NULL, 1, _mwidth(obj), _mheight(obj));
947 /* D(bug("DispCount after = %d\n", data->DispCount)); */
949 /* 0-terminate string */
950 data->Buffer[data->NumChars] = 0x00;
954 /* Gets left position of text in the string gadget */
955 static UWORD GetTextLeft(struct IClass *cl, Object *obj)
957 struct MUI_StringData *data = INST_DATA(cl, obj);
958 UWORD text_left = 0;
959 STRPTR dispstr = &(data->Buffer[data->DispPos]);
960 UWORD dispstrlen;
961 BOOL cursor_at_end;
963 cursor_at_end = (data->BufferPos == data->NumChars);
964 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
966 switch (data->msd_Align)
968 case MUIV_String_Format_Left:
969 text_left = _mleft(obj);
970 break;
972 case MUIV_String_Format_Center:
974 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
975 if (cursor_at_end)
976 textwidth += TextLength(_rp(obj), " ", 1);
977 text_left = _mleft(obj) + ((_mwidth(obj) - textwidth) / 2);
978 /* D(bug("GetTextLeft: dispstr=%s, dispstrlen=%d, textw=%d, " */
979 /* "textl=%d\n", */
980 /* dispstr, dispstrlen, textwidth, text_left)); */
982 break;
984 case MUIV_String_Format_Right:
986 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
988 if (cursor_at_end)
989 textwidth += TextLength(_rp(obj), " ", 1);
990 text_left = _mleft(obj) + (_mwidth(obj) - 1 - textwidth);
992 break;
994 return (text_left);
997 /* Gets right offset of text in the string gadget */
998 static UWORD GetTextRight(struct IClass *cl, Object *obj)
1000 struct MUI_StringData *data = INST_DATA(cl, obj);
1001 UWORD text_right = 0;
1002 STRPTR dispstr = &(data->Buffer[data->DispPos]);
1003 UWORD dispstrlen;
1004 BOOL cursor_at_end;
1006 cursor_at_end = (data->BufferPos == data->NumChars);
1007 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
1009 switch (data->msd_Align)
1011 case MUIV_String_Format_Left:
1012 text_right =
1013 _mleft(obj) + TextLength(_rp(obj), dispstr, dispstrlen);
1014 break;
1016 case MUIV_String_Format_Center:
1018 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
1020 if (cursor_at_end)
1021 textwidth += TextLength(_rp(obj), " ", 1);
1022 text_right = _mright(obj) - ((_mwidth(obj) - textwidth) / 2);
1024 break;
1026 case MUIV_String_Format_Right:
1027 text_right = _mright(obj);
1028 break;
1030 return (text_right);
1034 /* Updates the stringdata in case user has set some fields */
1035 static VOID UpdateStringData(struct IClass *cl, Object *obj)
1037 struct MUI_StringData *data = INST_DATA(cl, obj);
1039 data->NumChars = strlen(data->Buffer);
1041 if (data->BufferPos > data->NumChars)
1043 data->BufferPos = data->NumChars;
1047 static VOID TextM(Object *obj, struct MUI_StringData *data,
1048 STRPTR text, WORD textlen, WORD markstart, WORD markend)
1050 struct RastPort *rp = _rp(obj);
1051 ULONG textpen;
1052 WORD len;
1054 if (data->is_active)
1055 textpen = data->active_text.p_pen;
1056 else
1057 textpen = data->inactive_text.p_pen;
1059 //kprintf("TextM: textlen %d markstart %d markend %d ... \n",
1060 // textlen, markstart, markend);
1062 /* <unmarked><marked><unmarked> */
1064 /* <unmarked> */
1066 len = MIN(markstart, textlen);
1067 len = MAX(len, 0);
1069 if (len)
1071 //kprintf("A: %d ", len);
1073 SetABPenDrMd(rp, textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1074 Text(rp, text, len);
1076 text += len;
1077 textlen -= len;
1081 len = MIN(markend - len, textlen);
1082 len = MAX(len, 0);
1084 if (len)
1086 //kprintf("B: %d ", len);
1087 SetABPenDrMd(_rp(obj), data->marked_text.p_pen,
1088 data->marked_bg.p_pen, JAM2);
1089 Text(rp, text, len);
1091 text += len;
1092 textlen -= len;
1095 if (textlen)
1097 //kprintf("C: %d ", textlen);
1099 SetABPenDrMd(rp, textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1100 Text(rp, text, textlen);
1102 //kprintf("\n");
1105 /**************************************************************************
1106 MUIM_Draw
1107 **************************************************************************/
1108 IPTR String__MUIM_Draw(struct IClass *cl, Object *obj,
1109 struct MUIP_Draw *msg)
1111 struct MUI_StringData *data = INST_DATA(cl, obj);
1112 UWORD text_left;
1113 UWORD text_top;
1114 STRPTR dispstr;
1115 UWORD dispstrlen;
1116 ULONG textpen;
1117 UWORD textleft_save;
1118 WORD markstart = 0, markstop = 0;
1120 /* D(bug("\nString_Draw(%p) %ldx%ldx%ldx%ld reason=%ld msgflgs=%ld " */
1121 /* "curs=%d " */
1122 /* "displ=%ld len=%ld buf='%s'\n",obj,_mleft(obj),_mtop(obj), */
1123 /* _mwidth(obj),_mheight(obj), data->msd_RedrawReason, msg->flags, */
1124 /* data->BufferPos, data->DispPos, data->NumChars, data->Buffer)); */
1126 DoSuperMethodA(cl, obj, (Msg) msg);
1128 if (!(msg->flags & MADF_DRAWUPDATE) && !(msg->flags & MADF_DRAWOBJECT))
1129 return 0;
1131 SetFont(_rp(obj), _font(obj));
1132 if (data->is_active)
1133 textpen = data->active_text.p_pen;
1134 else
1135 textpen = data->inactive_text.p_pen;
1137 /* Update the stringdata in case of user change */
1138 UpdateStringData(cl, obj);
1140 /* Update the DispPos and DispCount fields so that the gadget renders
1141 * properly */
1142 UpdateDisp(cl, obj);
1144 text_top = _mtop(obj)
1145 + ((_mheight(obj) - _rp(obj)->Font->tf_YSize) >> 1)
1146 + _rp(obj)->Font->tf_Baseline;
1148 dispstr = data->Buffer + data->DispPos;
1149 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
1150 textleft_save = text_left = GetTextLeft(cl, obj);
1152 // little flicker improvement, don't redraw first part of string
1153 // when adding a char
1154 if (msg->flags & MADF_DRAWUPDATE &&
1155 data->msd_RedrawReason == DO_ADDCHAR &&
1156 data->msd_Align == MUIV_String_Format_Left && data->DispPos == 0)
1158 text_left += TextLength(_rp(obj), dispstr, data->BufferPos - 1);
1159 dispstr += data->BufferPos - 1;
1160 dispstrlen -= data->BufferPos - 1;
1161 DoMethod(obj, MUIM_DrawBackground, text_left, _mtop(obj),
1162 _mwidth(obj) - text_left + _mleft(obj), _mheight(obj),
1163 text_left, _mtop(obj), 0);
1165 else if (msg->flags & MADF_DRAWUPDATE)
1167 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1168 _mwidth(obj), _mheight(obj), _mleft(obj), _mtop(obj), 0);
1171 SetABPenDrMd(_rp(obj), textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1172 Move(_rp(obj), text_left, text_top);
1174 if ((data->msd_Flags & MSDF_MARKING)
1175 && Buffer_GetMarkedRange(data, &markstart, &markstop))
1177 TextM(obj, data, dispstr, dispstrlen, markstart - data->DispPos,
1178 markstop - data->DispPos);
1181 else
1183 Text(_rp(obj), dispstr, dispstrlen);
1185 if (data->is_active) // active, draw cursor
1187 UWORD cursoroffset = data->BufferPos - data->DispPos;
1189 dispstr = data->Buffer + data->DispPos;
1190 text_left = textleft_save;
1192 SetABPenDrMd(_rp(obj), data->active_text.p_pen,
1193 data->cursor.p_pen, JAM2);
1194 text_left += TextLength(_rp(obj), dispstr, cursoroffset);
1197 Move(_rp(obj), text_left, text_top);
1198 Text(_rp(obj),
1199 ((data->BufferPos < data->NumChars)
1200 ? dispstr + cursoroffset : (STRPTR) " "), 1);
1204 data->msd_RedrawReason = NO_REASON;
1205 return TRUE;
1208 /**************************************************************************
1209 Returns whether object needs redrawing
1210 **************************************************************************/
1211 static int String_HandleVanillakey(struct IClass *cl, Object *obj,
1212 unsigned char code, UWORD qual)
1214 struct MUI_StringData *data =
1215 (struct MUI_StringData *)INST_DATA(cl, obj);
1216 BOOL doinput;
1218 D(bug("String_HandleVanillakey: code=%d qual=%d\n", code, qual));
1220 if (0 == code)
1221 return 0;
1223 doinput = (data->msd_Flags & MSDF_NOINPUT) ? FALSE : TRUE;
1225 if (doinput && (code == '\b')) /* backspace */
1227 if (Buffer_KillMarked(data))
1229 return 1;
1232 if (data->BufferPos > 0)
1234 LONG shift;
1236 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
1238 shift = data->BufferPos;
1239 data->msd_RedrawReason = NEW_CONTENTS;
1241 else
1243 shift = 1;
1244 data->msd_RedrawReason = DO_BACKSPACE;
1247 strcpy(&data->Buffer[data->BufferPos - shift],
1248 &data->Buffer[data->BufferPos]);
1249 data->BufferPos -= shift;
1250 data->NumChars -= shift;
1251 return 1;
1253 return 0;
1256 if (doinput && (code == 21)) // ctrl-u == NAK (like shift-bs)
1258 if (Buffer_KillMarked(data))
1260 return 1;
1263 if (data->BufferPos > 0)
1265 strcpy(&data->Buffer[0], &data->Buffer[data->BufferPos]);
1266 data->NumChars -= data->BufferPos;
1267 data->BufferPos = 0;
1268 data->msd_RedrawReason = NEW_CONTENTS;
1269 return 1;
1271 return 0;
1274 if (doinput && (code == 127)) /* del */
1276 if (!Buffer_KillMarked(data))
1278 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
1280 data->Buffer[data->BufferPos] = 0;
1281 data->NumChars = data->BufferPos;
1282 data->msd_RedrawReason = NEW_CONTENTS;
1284 else
1286 if (data->BufferPos < data->NumChars)
1288 strcpy(&data->Buffer[data->BufferPos],
1289 &data->Buffer[data->BufferPos + 1]);
1290 data->NumChars--;
1293 data->msd_RedrawReason = DO_DELETE;
1296 return 1;
1299 if (doinput && (code == 11)) // ctrl-k == VT == \v (like shift-del)
1301 if (!Buffer_KillMarked(data))
1303 data->Buffer[data->BufferPos] = 0;
1304 data->NumChars = data->BufferPos;
1305 data->msd_RedrawReason = NEW_CONTENTS;
1307 return 1;
1310 if (doinput && (code == 24)) /* ctrl x == ascii cancel */
1312 if (!Buffer_KillMarked(data))
1314 data->Buffer[0] = 0;
1315 data->BufferPos = 0;
1316 data->NumChars = 0;
1317 data->msd_RedrawReason = NEW_CONTENTS;
1319 return 1;
1322 if (code == 1) // ctrl-a, linestart
1324 data->BufferPos = 0;
1325 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
1326 return 1;
1329 if (code == 26) // ctrl-z, lineend
1331 data->BufferPos = data->NumChars;
1332 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
1333 return 1;
1336 if (((ToLower(code) == 'c') || (ToLower(code) == 'x')) &&
1337 (qual & IEQUALIFIER_RCOMMAND))
1339 WORD markstart, markstop;
1341 if ((data->msd_Flags & MSDF_MARKING)
1342 && Buffer_GetMarkedRange(data, &markstart, &markstop))
1344 clipboard_write_text(&data->Buffer[markstart],
1345 markstop - markstart);
1347 if (doinput && (ToLower(code) == 'x'))
1349 Buffer_KillMarked(data);
1351 else
1353 data->BufferPos = markstop;
1354 data->msd_Flags &= ~MSDF_MARKING;
1356 return 1;
1358 return 0;
1361 if (doinput && (ToLower(code) == 'v') && (qual & IEQUALIFIER_RCOMMAND))
1363 STRPTR text;
1364 int retval;
1365 struct Locale *locale = OpenLocale(NULL);
1367 retval = Buffer_KillMarked(data);
1368 if ((text = clipboard_read_text()))
1370 STRPTR text2 = text;
1371 UBYTE c;
1373 while ((c = *text2++))
1375 if (!IsPrint(locale, c))
1376 break;
1377 if (!(Buffer_AddChar(data, c)))
1378 break;
1379 if (!retval)
1380 retval = 1;
1383 clipboard_free_text(text);
1386 CloseLocale(locale);
1388 return retval;
1391 if (data->msd_Accept != NULL)
1393 /* Check if character is accepted */
1394 if (NULL == strchr(data->msd_Accept, code))
1395 return 0;
1398 if (data->msd_Reject != NULL)
1400 /* Check if character is rejected */
1401 if (NULL != strchr(data->msd_Reject, code))
1403 DisplayBeep(NULL);
1404 return 0;
1408 if (doinput)
1410 struct Locale *locale = OpenLocale(NULL);
1412 if (!(code >= 0x09 && code <= 0x0D) && IsPrint(locale, code))
1414 Buffer_KillMarked(data);
1415 if (Buffer_AddChar(data, code))
1417 data->msd_RedrawReason = DO_ADDCHAR;
1418 return 2;
1422 CloseLocale(locale);
1425 data->msd_RedrawReason = DO_UNKNOWN;
1426 return 0;
1430 /**************************************************************************
1431 MUIM_HandleEvent
1432 **************************************************************************/
1433 IPTR String__MUIM_HandleEvent(struct IClass *cl, Object *obj,
1434 struct MUIP_HandleEvent *msg)
1436 struct MUI_StringData *data =
1437 (struct MUI_StringData *)INST_DATA(cl, obj);
1438 ULONG retval = 0;
1439 int update = 0;
1440 BOOL edited = FALSE;
1441 LONG muikey = msg->muikey;
1442 BOOL cursor_kills_marking = FALSE;
1444 if ((data->msd_Flags & MSDF_MARKING)
1445 && !(data->msd_Flags & MSDF_KEYMARKING))
1447 cursor_kills_marking = TRUE;
1450 if (muikey == MUIKEY_NONE)
1452 if (msg->imsg->Class == IDCMP_RAWKEY)
1454 static LONG muikeytable[3][2] = {
1455 {MUIKEY_LEFT, MUIKEY_RIGHT},
1456 {MUIKEY_WORDLEFT, MUIKEY_WORDRIGHT},
1457 {MUIKEY_LINESTART, MUIKEY_LINEEND}
1459 WORD dirindex = -1, amountindex = 0;
1461 switch (msg->imsg->Code)
1463 case 0x4F:
1464 dirindex = 0;
1465 break;
1467 case 0x4E:
1468 dirindex = 1;
1469 break;
1471 #ifdef __AROS__
1472 case RAWKEY_HOME:
1473 muikey = MUIKEY_LINESTART;
1474 break;
1476 case RAWKEY_END:
1477 muikey = MUIKEY_LINEEND;
1478 break;
1479 #endif
1483 if ((dirindex != -1) && (muikey == MUIKEY_NONE))
1485 if (msg->imsg->
1486 Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
1488 amountindex = 2;
1490 else if (msg->imsg->Qualifier & IEQUALIFIER_CONTROL)
1492 amountindex = 1;
1495 muikey = muikeytable[amountindex][dirindex];
1501 D(bug("String_HandleEvent: muikey %d, imsg %p is_active=%d\n", muikey,
1502 msg->imsg, data->is_active));
1503 if (muikey != MUIKEY_NONE && data->is_active)
1505 retval = MUI_EventHandlerRC_Eat;
1507 switch (muikey)
1509 case MUIKEY_LEFT:
1510 if (cursor_kills_marking)
1512 update = 1;
1513 data->BufferPos = MIN(data->BufferPos, data->MarkPos);
1514 if (data->BufferPos > 0)
1515 data->BufferPos--;
1517 data->msd_Flags &= ~MSDF_MARKING;
1519 else if (data->BufferPos > 0)
1521 update = 1;
1523 data->BufferPos--;
1524 data->msd_RedrawReason = DO_CURSOR_LEFT;
1526 break;
1527 case MUIKEY_RIGHT:
1528 if (cursor_kills_marking)
1530 update = 1;
1531 data->BufferPos = MAX(data->BufferPos, data->MarkPos);
1532 data->msd_Flags &= ~MSDF_MARKING;
1534 else if (data->BufferPos < data->NumChars)
1536 update = 1;
1537 data->BufferPos++;
1538 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1540 break;
1541 case MUIKEY_WORDLEFT:
1542 if (data->BufferPos > 0)
1544 data->BufferPos =
1545 Buffer_GetPrevWordIndex(data, data->BufferPos);
1546 update = 1;
1547 data->msd_RedrawReason = DO_CURSOR_LEFT;
1549 if (cursor_kills_marking)
1551 data->msd_Flags &= ~MSDF_MARKING;
1552 update = 1;
1554 break;
1555 case MUIKEY_WORDRIGHT:
1556 if (data->BufferPos < data->NumChars)
1558 data->BufferPos =
1559 Buffer_GetSuccWordIndex(data, data->BufferPos);
1560 update = 1;
1561 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1563 if (cursor_kills_marking)
1565 data->msd_Flags &= ~MSDF_MARKING;
1566 update = 1;
1568 break;
1569 case MUIKEY_LINESTART:
1570 data->BufferPos = 0;
1571 update = 1;
1572 if (cursor_kills_marking)
1574 data->msd_Flags &= ~MSDF_MARKING;
1576 break;
1578 case MUIKEY_LINEEND:
1579 data->BufferPos = data->NumChars;
1580 update = 1;
1581 if (cursor_kills_marking)
1583 data->msd_Flags &= ~MSDF_MARKING;
1585 break;
1587 case MUIKEY_UP:
1588 if (data->msd_AttachedList)
1589 set(data->msd_AttachedList,
1590 MUIA_List_Active, MUIV_List_Active_Up);
1591 break;
1592 case MUIKEY_DOWN:
1593 if (data->msd_AttachedList)
1594 set(data->msd_AttachedList,
1595 MUIA_List_Active, MUIV_List_Active_Down);
1596 break;
1597 case MUIKEY_PAGEUP:
1598 if (data->msd_AttachedList)
1599 set(data->msd_AttachedList,
1600 MUIA_List_Active, MUIV_List_Active_PageUp);
1601 break;
1602 case MUIKEY_PAGEDOWN:
1603 if (data->msd_AttachedList)
1604 set(data->msd_AttachedList,
1605 MUIA_List_Active, MUIV_List_Active_PageDown);
1606 break;
1607 case MUIKEY_TOP:
1608 if (data->msd_AttachedList)
1609 set(data->msd_AttachedList,
1610 MUIA_List_Active, MUIV_List_Active_Top);
1611 break;
1612 case MUIKEY_BOTTOM:
1613 if (data->msd_AttachedList)
1614 set(data->msd_AttachedList,
1615 MUIA_List_Active, MUIV_List_Active_Bottom);
1616 break;
1617 case MUIKEY_PRESS:
1619 UBYTE *buf = NULL;
1621 get(obj, MUIA_String_Contents, &buf);
1623 if (data->msd_Flags & MSDF_STAYACTIVE)
1625 /* Do not change active object */
1627 else if (data->msd_Flags & MSDF_ADVANCEONCR)
1629 set(_win(obj), MUIA_Window_ActiveObject,
1630 MUIV_Window_ActiveObject_Next);
1632 else if (!(data->msd_Flags & MSDF_STAYACTIVE))
1634 set(_win(obj), MUIA_Window_ActiveObject,
1635 MUIV_Window_ActiveObject_None);
1638 set(obj, MUIA_String_Acknowledge, buf);
1640 break;
1642 case MUIKEY_WINDOW_CLOSE:
1643 data->is_active = FALSE;
1644 set(obj, MUIA_Background,
1645 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
1646 DoMethod(obj, MUIM_GoInactive);
1647 retval = 0;
1648 break;
1650 default:
1651 retval = 0;
1652 } // switch(muikey)
1653 } // if (muikey != MUIKEY_NONE)
1655 if (msg->imsg)
1657 UWORD code = msg->imsg->Code;
1658 //UWORD qual = msg->imsg->Qualifier;
1659 WORD x = msg->imsg->MouseX;
1660 WORD y = msg->imsg->MouseY;
1662 //bug("String_HandleEvent: parsing imsg %p, class=%ld\n",
1663 // msg->imsg, msg->imsg->Class);
1665 switch (msg->imsg->Class)
1667 case IDCMP_MOUSEBUTTONS: /* set cursor and activate it */
1668 if (code == SELECTDOWN)
1670 //bug("String_HandleEvent: code == SELECTDOWN, x=%d y=%d\n",
1671 // x, y);
1673 if (_isinobject(x, y))
1675 UWORD text_left, text_right;
1677 retval = MUI_EventHandlerRC_Eat;
1679 CurrentTime(&data->NewClick_Sec, &data->NewClick_Micro);
1680 if (DoubleClick(data->OldClick_Sec,
1681 data->OldClick_Micro, data->NewClick_Sec,
1682 data->NewClick_Micro))
1684 data->MultiClick++;
1686 else
1688 data->MultiClick = 0;
1690 data->OldClick_Sec = data->NewClick_Sec;
1691 data->OldClick_Micro = data->NewClick_Micro;
1693 //kprintf("multiclick %d\n", data->MultiClick);
1695 if (!data->is_active)
1697 //bug("String got button, lets activate\n");
1698 data->is_active = TRUE;
1699 data->msd_RedrawReason = WENT_ACTIVE;
1700 // redraw
1701 set(obj, MUIA_Background,
1702 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->
1703 string_bg_active);
1705 //DoMethod(obj, MUIM_GoActive);
1706 set(_win(obj), MUIA_Window_ActiveObject, obj);
1707 // let other objects a chance to get desactivated
1708 //retval = 0;
1711 if (!(data->ehn.ehn_Events & IDCMP_MOUSEMOVE))
1713 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1714 (IPTR) & data->ehn);
1715 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
1716 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1717 (IPTR) & data->ehn);
1720 text_left = GetTextLeft(cl, obj);
1721 text_right = GetTextRight(cl, obj);
1723 /* Check if mouseclick is inside displayed text */
1724 if ((x >= text_left) && (x <= text_right))
1726 /* Find new cursor pos. */
1727 struct TextExtent te;
1728 ULONG newpos;
1729 STRPTR dispstr = data->Buffer + data->DispPos;
1731 newpos = data->DispPos
1732 + TextFit(_rp(obj), dispstr,
1733 data->NumChars - data->DispPos, &te, NULL, 1,
1734 x - text_left, _rp(obj)->Font->tf_YSize);
1736 if (data->BufferPos != newpos)
1738 data->BufferPos = newpos;
1739 update = 1;
1742 else if (x < text_left)
1744 /* Click on empty space at left. Set cursor to first
1745 * visible */
1746 if (data->BufferPos != data->DispPos)
1748 data->BufferPos = data->DispPos;
1749 update = 1;
1752 else
1754 /* Click on empty space at right. Set cursor to last
1755 * visible */
1756 if (data->BufferPos !=
1757 data->DispPos + data->DispCount)
1759 data->BufferPos =
1760 data->DispPos + data->DispCount;
1761 update = 1;
1763 } /* if (click is on text or not) */
1765 data->MarkPos = data->BufferPos;
1767 if (data->MultiClick == 0)
1769 if (data->msd_Flags & MSDF_MARKING)
1771 data->msd_Flags &= ~MSDF_MARKING;
1772 update = 1;
1775 else if (data->MultiClick
1776 && Buffer_GetMarkedRange(data, NULL, NULL))
1778 data->msd_Flags |= MSDF_MARKING;
1779 update = 1;
1783 } /* is in object */
1784 else if (data->is_active
1785 && !(data->msd_Flags & MSDF_STAYACTIVE))
1786 /* and click not on object */
1788 data->is_active = FALSE;
1789 set(obj, MUIA_Background,
1790 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->
1791 string_bg_inactive);
1792 //DoMethod(obj, MUIM_GoInactive);
1793 // let other objects a chance to get activated
1794 //retval = 0;
1796 } /* if (code == SELECTDOWN) */
1797 else if (code == SELECTUP)
1799 if (data->ehn.ehn_Events & IDCMP_MOUSEMOVE)
1801 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1802 (IPTR) & data->ehn);
1803 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
1804 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1805 (IPTR) & data->ehn);
1808 break;
1810 case IDCMP_MOUSEMOVE:
1811 if (data->is_active)
1813 UWORD text_left, text_right;
1815 if (!(data->msd_Flags & MSDF_MARKING))
1817 data->msd_Flags |= MSDF_MARKING;
1820 text_left = GetTextLeft(cl, obj);
1821 text_right = GetTextRight(cl, obj);
1823 /* Check if mouseclick is inside displayed text */
1824 if ((x >= text_left) && (x <= text_right))
1826 /* Find new cursor pos. */
1827 struct TextExtent te;
1828 ULONG newpos;
1829 STRPTR dispstr = data->Buffer + data->DispPos;
1831 newpos = data->DispPos
1832 + TextFit(_rp(obj), dispstr,
1833 data->NumChars - data->DispPos, &te, NULL, 1,
1834 x - text_left, _rp(obj)->Font->tf_YSize);
1836 if (data->BufferPos != newpos)
1838 WORD old_markstart = 0, old_markstop = 0;
1839 WORD markstart = 0, markstop = 0;
1840 BOOL was_marked, is_marked;
1842 was_marked = Buffer_AnythingMarked(data) &&
1843 Buffer_GetMarkedRange(data, &old_markstart,
1844 &old_markstop);
1846 data->BufferPos = newpos;
1848 is_marked = Buffer_AnythingMarked(data) &&
1849 Buffer_GetMarkedRange(data, &markstart,
1850 &markstop);
1852 if ((was_marked != is_marked) ||
1853 (old_markstart != markstart) ||
1854 (old_markstop != markstop))
1856 update = 1;
1860 else if ((x < text_left) && (data->BufferPos > 0))
1862 data->BufferPos--;
1863 update = 1;
1864 data->msd_RedrawReason = DO_CURSOR_LEFT;
1866 else if ((x > text_right)
1867 && (data->BufferPos < data->NumChars))
1869 data->BufferPos++;
1870 update = 1;
1871 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1873 //kprintf(" ---- bp: %d\n", data->BufferPos);
1875 break;
1877 case IDCMP_RAWKEY:
1879 unsigned char code;
1881 //bug("String_HandleEvent: idcmp_rawkey\n");
1883 if (!data->is_active)
1884 break;
1886 code = ConvertKey(msg->imsg);
1887 if (!code)
1889 switch (msg->imsg->Code)
1891 case 0x64: /* LALT */
1892 case 0x65: /* RALT */
1893 case 0x64 | IECODE_UP_PREFIX:
1894 case 0x65 | IECODE_UP_PREFIX:
1895 if (msg->imsg->
1896 Qualifier & (IEQUALIFIER_LALT |
1897 IEQUALIFIER_RALT))
1899 data->MarkPos = data->BufferPos;
1900 data->msd_Flags |=
1901 (MSDF_MARKING | MSDF_KEYMARKING);
1903 else
1905 data->msd_Flags &= ~MSDF_KEYMARKING;
1907 break;
1912 if (code)
1914 update =
1915 String_HandleVanillakey(cl, obj, code,
1916 msg->imsg->Qualifier);
1917 if (update)
1919 retval = MUI_EventHandlerRC_Eat;
1920 edited = TRUE;
1924 break;
1928 if (edited)
1929 set(obj, MUIA_String_Contents, data->Buffer); // trigger notification
1931 if (update)
1933 MUI_Redraw(obj, MADF_DRAWUPDATE);
1935 //D(bug("String eh return %ld\n", retval));
1937 return retval;
1941 /**************************************************************************
1942 MUIM_Export : to export an object's "contents" to a dataspace object.
1943 **************************************************************************/
1944 IPTR String__MUIM_Export(struct IClass *cl, Object *obj,
1945 struct MUIP_Export *msg)
1947 struct MUI_StringData *data = INST_DATA(cl, obj);
1948 ULONG id;
1949 STRPTR buf = NULL;
1951 if (data->msd_useSecret)
1952 buf = data->SecBuffer;
1953 else
1954 buf = data->Buffer;
1956 if ((id = muiNotifyData(obj)->mnd_ObjectID))
1958 if (buf != NULL)
1959 DoMethod(msg->dataspace, MUIM_Dataspace_Add,
1960 (IPTR) buf, data->NumChars + 1, (IPTR) id);
1961 else
1962 DoMethod(msg->dataspace, MUIM_Dataspace_Remove, (IPTR) id);
1965 return 0;
1969 /**************************************************************************
1970 MUIM_Import : to import an object's "contents" from a dataspace object.
1971 **************************************************************************/
1972 IPTR String__MUIM_Import(struct IClass *cl, Object *obj,
1973 struct MUIP_Import *msg)
1975 ULONG id;
1976 STRPTR s;
1978 if ((id = muiNotifyData(obj)->mnd_ObjectID))
1980 if ((s = (STRPTR) DoMethod(msg->dataspace, MUIM_Dataspace_Find,
1981 (IPTR) id)))
1983 set(obj, MUIA_String_Contents, s);
1987 return 0;
1990 /**************************************************************************
1991 MUIM_GoActive
1992 **************************************************************************/
1993 IPTR String__MUIM_GoActive(struct IClass *cl, Object *obj, Msg msg)
1995 struct MUI_StringData *data =
1996 (struct MUI_StringData *)INST_DATA(cl, obj);
1998 //D(bug("String_GoActive %p\n", obj));
1999 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
2000 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
2001 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
2002 data->is_active = TRUE;
2003 data->msd_Flags &= ~MSDF_KEYMARKING;
2004 data->msd_RedrawReason = WENT_ACTIVE;
2005 // redraw
2006 set(obj, MUIA_Background,
2007 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_active);
2009 return 0;
2012 /**************************************************************************
2013 MUIM_GoInactive
2014 **************************************************************************/
2015 IPTR String__MUIM_GoInactive(struct IClass *cl, Object *obj, Msg msg)
2017 struct MUI_StringData *data =
2018 (struct MUI_StringData *)INST_DATA(cl, obj);
2020 //D(bug("String_GoInactive %p\n", obj));
2022 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
2023 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
2024 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
2025 data->is_active = FALSE;
2026 data->msd_RedrawReason = WENT_INACTIVE;
2027 data->MultiClick = 0;
2029 // redraw
2030 set(obj, MUIA_Background,
2031 (IPTR) muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
2033 return 0;
2036 /**************************************************************************
2037 MUIM_String_ClearSelected (BetterString)
2038 **************************************************************************/
2039 IPTR String__MUIM_ClearSelected(struct IClass *cl, Object *obj,
2040 struct MUIP_String_ClearSelected *msg)
2042 struct MUI_StringData *data =
2043 (struct MUI_StringData *)INST_DATA(cl, obj);
2045 //D(bug("String_ClearSelected %p\n", obj));
2047 if (Buffer_KillMarked(data))
2049 MUI_Redraw(obj, MADF_DRAWUPDATE);
2052 return 0;
2055 /**************************************************************************
2056 MUIM_String_Insert (BetterString)
2057 **************************************************************************/
2058 IPTR String__MUIM_Insert(struct IClass *cl, Object *obj,
2059 struct MUIP_String_Insert *msg)
2061 struct MUI_StringData *data =
2062 (struct MUI_StringData *)INST_DATA(cl, obj);
2063 LONG pos;
2064 ULONG old_bufferpos;
2065 ULONG num_inserted = 0;
2067 //D(bug("String_Insert %p\n", obj));
2069 switch ((ULONG) msg->pos)
2071 case MUIV_String_Insert_StartOfString:
2072 pos = 0;
2073 break;
2075 case MUIV_String_Insert_EndOfString:
2076 pos = data->NumChars;
2077 break;
2079 case MUIV_String_Insert_BufferPos:
2080 pos = data->BufferPos;
2081 break;
2083 default:
2084 pos = msg->pos;
2085 break;
2088 if ((pos < 0) || (pos > data->NumChars))
2089 return 0;
2091 old_bufferpos = data->BufferPos;
2092 data->BufferPos = pos;
2094 while (msg->text[num_inserted]
2095 && Buffer_AddChar(data, msg->text[num_inserted]))
2097 num_inserted++;
2100 if (num_inserted)
2102 if (old_bufferpos >= pos)
2104 data->BufferPos = old_bufferpos + num_inserted;
2106 else
2108 data->BufferPos = old_bufferpos;
2111 MUI_Redraw(obj, MADF_DRAWUPDATE);
2114 return 0;
2117 /**************************************************************************
2118 MUIM_String_FileNameStart (BetterString)
2119 **************************************************************************/
2120 IPTR String__MUIM_FileNameStart(struct IClass *cl, Object *obj,
2121 struct MUIP_String_FileNameStart *msg)
2123 struct MUI_StringData *data =
2124 (struct MUI_StringData *)INST_DATA(cl, obj);
2125 STRPTR buf;
2127 //D(bug("String_FileNameStart %p\n", obj));
2129 if (data->msd_useSecret)
2131 buf = data->SecBuffer;
2133 else
2135 buf = data->Buffer;
2137 // TODO: Implement String_FileNameStart correctly!
2139 return (IPTR) buf;
2142 BOOPSI_DISPATCHER(IPTR, String_Dispatcher, cl, obj, msg)
2144 switch (msg->MethodID)
2146 case OM_NEW:
2147 return String__OM_NEW(cl, obj, (struct opSet *)msg);
2148 case OM_DISPOSE:
2149 return String__OM_DISPOSE(cl, obj, msg);
2150 case OM_SET:
2151 return String__OM_SET(cl, obj, (struct opSet *)msg);
2152 case OM_GET:
2153 return String__OM_GET(cl, obj, (struct opGet *)msg);
2155 case MUIM_Setup:
2156 return String__MUIM_Setup(cl, obj, (APTR) msg);
2157 case MUIM_Cleanup:
2158 return String__MUIM_Cleanup(cl, obj, (APTR) msg);
2159 case MUIM_AskMinMax:
2160 return String__MUIM_AskMinMax(cl, obj, (APTR) msg);
2161 case MUIM_Draw:
2162 return String__MUIM_Draw(cl, obj, (APTR) msg);
2163 case MUIM_Export:
2164 return String__MUIM_Export(cl, obj, (APTR) msg);
2165 case MUIM_Import:
2166 return String__MUIM_Import(cl, obj, (APTR) msg);
2167 case MUIM_GoActive:
2168 return String__MUIM_GoActive(cl, obj, (APTR) msg);
2169 case MUIM_GoInactive:
2170 return String__MUIM_GoInactive(cl, obj, (APTR) msg);
2171 case MUIM_HandleEvent:
2172 return String__MUIM_HandleEvent(cl, obj, (APTR) msg);
2174 /* BetterString */
2175 case MUIM_String_ClearSelected:
2176 return String__MUIM_ClearSelected(cl, obj, (APTR) msg);
2177 case MUIM_String_Insert:
2178 return String__MUIM_Insert(cl, obj, (APTR) msg);
2179 case MUIM_String_FileNameStart:
2180 return String__MUIM_FileNameStart(cl, obj, (APTR) msg);
2183 return DoSuperMethodA(cl, obj, msg);
2185 BOOPSI_DISPATCHER_END
2188 * Class descriptor.
2190 const struct __MUIBuiltinClass _MUI_String_desc =
2192 MUIC_String,
2193 MUIC_Area,
2194 sizeof(struct MUI_StringData),
2195 (void *)String_Dispatcher