Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / libs / muimaster / classes / string.c
blob750c1e39e68fc31cfa93beb63067654019e02d38
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 {
47 ULONG msd_Flags;
48 CONST_STRPTR msd_Accept; /* MUIA_String_Accept */
49 CONST_STRPTR msd_Reject; /* MUIA_String_Reject */
50 LONG msd_Align;
51 struct Hook *msd_EditHook;
52 Object *msd_AttachedList;
53 LONG msd_RedrawReason;
55 ULONG msd_useSecret;
56 /* Fields mostly ripped from rom/intuition/strgadgets.c */
57 STRPTR Buffer; /* char container */
58 ULONG BufferSize; /* memory allocated */
59 STRPTR SecBuffer; /* Buffer for secret string */
60 ULONG NumChars; /* string length */
61 ULONG BufferPos; /* cursor (insert/delete) position */
62 ULONG MarkPos; /* cursor text marking start pos */
63 LONG DispPos; /* leftmost visible char */
64 ULONG DispCount; /* number of visible chars */
66 ULONG OldClick_Sec;
67 ULONG OldClick_Micro;
68 ULONG NewClick_Sec;
69 ULONG NewClick_Micro;
70 WORD MultiClick;
72 WORD Columns;
74 struct MUI_EventHandlerNode ehn;
75 struct MUI_PenSpec_intern inactive_text;
76 struct MUI_PenSpec_intern active_text;
77 struct MUI_PenSpec_intern marked_text;
78 struct MUI_PenSpec_intern marked_bg;
79 struct MUI_PenSpec_intern cursor;
81 BOOL is_active;
84 #define MSDF_ADVANCEONCR (1<<0)
85 #define MSDF_LONELYEDITHOOK (1<<1)
86 #define MSDF_MARKING (1<<2)
87 #define MSDF_KEYMARKING (1<<3)
88 #define MSDF_NOINPUT (1<<4)
89 #define MSDF_STAYACTIVE (1<<5)
91 enum {
92 NO_REASON = 0,
93 WENT_ACTIVE = 1,
94 WENT_INACTIVE,
95 DO_CURSOR_LEFT = 3,
96 DO_CURSOR_RIGHT,
97 DO_DELETE = 5,
98 DO_BACKSPACE,
99 DO_ADDCHAR = 7,
100 NEW_CONTENTS,
101 MOVE_CURSOR,
102 DO_UNKNOWN,
106 /**************************************************************************
107 Buffer_SetNewContents
108 Allocate memory for buffer
109 **************************************************************************/
110 static BOOL Buffer_Alloc (struct MUI_StringData *data)
112 data->Buffer = (STRPTR)AllocVec(data->BufferSize * sizeof(char), MEMF_ANY);
113 if (NULL == data->Buffer)
115 bug("MUIC_String: Can't allocate %ld bytes for buffer1\n",
116 data->BufferSize * sizeof(char));
117 return FALSE;
119 if (data->msd_useSecret)
121 data->SecBuffer = (STRPTR)AllocVec(data->BufferSize * sizeof(char), MEMF_ANY);
122 if (NULL == data->SecBuffer)
124 bug("MUIC_String: Can't allocate %ld bytes for buffer2\n",
125 data->BufferSize * sizeof(char));
126 FreeVec(data->Buffer);
127 data->Buffer = NULL;
128 return FALSE;
131 return TRUE;
134 /**************************************************************************
135 Buffer_SetNewContents
136 Initialize buffer with a string, replace former content if any
137 **************************************************************************/
138 static BOOL Buffer_SetNewContents (struct MUI_StringData *data, CONST_STRPTR str)
140 if (NULL == data->Buffer)
141 return FALSE;
143 if (NULL == str)
145 data->Buffer[0] = 0;
146 if (data->msd_useSecret) data->SecBuffer[0] = 0;
147 data->NumChars = 0;
149 else
151 data->NumChars = strlen(str);
152 if (data->NumChars >= data->BufferSize)
153 data->NumChars = data->BufferSize - 1;
155 if (data->msd_useSecret)
157 strncpy(data->SecBuffer, str, data->BufferSize);
158 data->SecBuffer[data->BufferSize - 1] = 0;
159 int i;
160 for (i=0; i < data->NumChars; i++) data->Buffer[i]=0x78;
161 data->Buffer[data->NumChars] = 0;
163 else
165 strncpy(data->Buffer, str, data->BufferSize);
166 data->Buffer[data->BufferSize - 1] = 0;
170 data->BufferPos = data->NumChars;
171 data->DispPos = 0;
172 return TRUE;
175 /**************************************************************************
176 Buffer_AddChar
177 Add a char on cursor position
178 **************************************************************************/
179 static BOOL Buffer_AddChar (struct MUI_StringData *data, unsigned char code)
181 STRPTR dst;
183 if (data->Buffer == NULL)
184 return FALSE;
186 if (data->NumChars + 1 >= data->BufferSize)
187 return FALSE;
189 if (data->msd_useSecret)
191 dst = &data->SecBuffer[data->BufferPos + 1];
193 memmove(dst, &data->SecBuffer[data->BufferPos],
194 data->NumChars - data->BufferPos);
196 data->Buffer[data->NumChars]=0x78;
197 data->Buffer[data->NumChars + 1]=0;
199 else
201 dst = &data->Buffer[data->BufferPos + 1];
203 memmove(dst, &data->Buffer[data->BufferPos],
204 data->NumChars - data->BufferPos);
208 dst[data->NumChars - data->BufferPos] = 0;
209 dst[-1] = code;
211 data->BufferPos++;
212 data->NumChars++;
213 return TRUE;
216 static WORD Buffer_GetWordStartIndex(struct MUI_StringData *data, WORD startindex)
218 WORD index = startindex;
220 while(index > 0)
222 if (data->Buffer[index - 1] == ' ')
224 break;
226 index--;
229 return index;
232 static WORD Buffer_GetWordEndIndex(struct MUI_StringData *data, WORD startindex)
234 WORD index = startindex;
236 while(index < data->NumChars)
238 if (data->Buffer[index] == ' ')
240 break;
242 index++;
245 return index;
248 static WORD Buffer_GetPrevWordIndex(struct MUI_StringData *data, WORD startindex)
250 WORD index = startindex;
252 while(index > 0)
254 index--;
256 if ((index == 0) ||
257 ((data->Buffer[index - 1] == ' ') &&
258 (data->Buffer[index] != ' ')))
260 break;
265 return index;
268 static WORD Buffer_GetSuccWordIndex(struct MUI_StringData *data, WORD startindex)
270 WORD index = startindex;
272 while(index < data->NumChars)
274 index++;
276 if ((index == data->NumChars) ||
277 ((data->Buffer[index - 1] == ' ') &&
278 (data->Buffer[index] != ' ')))
280 break;
284 return index;
287 static BOOL Buffer_GetMarkedRange(struct MUI_StringData *data, WORD *start, WORD *stop)
289 WORD markstart = data->MarkPos;
290 WORD markstop = data->BufferPos;
292 markstart = MIN(markstart, data->NumChars);
293 markstart = MAX(markstart, 0);
295 markstop = MIN(markstop, data->NumChars);
296 markstop = MAX(markstop, 0);
298 if (markstart > markstop)
300 markstart ^= markstop;
301 markstop ^= markstart;
302 markstart ^= markstop;
305 switch(data->MultiClick)
307 case 0:
308 /* char select */
309 break;
311 case 1:
312 /* word select */
313 markstart = Buffer_GetWordStartIndex(data, markstart);
314 markstop = Buffer_GetWordEndIndex(data, markstop);
315 break;
317 default:
318 /* select all */
319 markstart = 0;
320 markstop = data->NumChars;
321 break;
325 if (markstart == markstop) return FALSE;
327 if (start) *start = markstart;
328 if (stop) *stop = markstop;
330 //kprintf("Buffer_GetMarkedRange: returning %d .. %d\n", markstart, markstop);
332 return TRUE;
335 static BOOL Buffer_AnythingMarked(struct MUI_StringData *data)
337 if (!(data->msd_Flags & MSDF_MARKING)) return FALSE;
339 return Buffer_GetMarkedRange(data, NULL, NULL);
342 static BOOL Buffer_KillMarked(struct MUI_StringData *data)
344 WORD markstart = data->MarkPos;
345 WORD markstop = data->BufferPos;
346 WORD marklen;
348 //kprintf("\nBuffer_KillMarked 1 markpos %d bufferpos %d numchars %d\n", markstart, markstop, data->NumChars);
350 if (!(data->msd_Flags & MSDF_MARKING)) return FALSE;
352 data->msd_Flags &= ~MSDF_MARKING;
354 if (!Buffer_GetMarkedRange(data, &markstart, &markstop)) return FALSE;
356 //kprintf("Buffer_KillMarked 2 markstart %d markstop %d\n", markstart, markstop);
358 if (markstart > markstop)
360 markstart ^= markstop;
361 markstop ^= markstart;
362 markstart ^= markstop;
365 marklen = markstop - markstart;
367 //kprintf("Buffer_KillMarked: markstart %d markstop %d\n", markstart, markstop);
369 memmove(&data->Buffer[markstart],
370 &data->Buffer[markstart + marklen], data->NumChars - markstart - marklen + 1);
372 data->NumChars -= marklen;
373 data->BufferPos = markstart;
375 return TRUE;
378 /**************************************************************************
379 OM_NEW
380 **************************************************************************/
381 IPTR String__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
383 struct MUI_StringData *data;
384 struct TagItem *tags,*tag;
385 CONST_STRPTR str = NULL;
386 char integerbuf[20];
388 obj = (Object *)DoSuperNewTags(cl, obj, NULL,
389 /* MUIA_FillArea, TRUE, */
390 TAG_MORE, (IPTR) msg->ops_AttrList);
391 if (!obj)
392 return FALSE;
394 data = INST_DATA(cl, obj);
395 data->msd_useSecret = FALSE;
396 data->msd_Align = MUIV_String_Format_Left;
397 data->BufferSize = 80;
398 data->Columns = -1;
400 Buffer_SetNewContents(data, ""); /* <-- isnt this pointless? */
402 /* parse initial taglist */
403 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags)); )
405 switch (tag->ti_Tag)
407 case MUIA_String_Accept:
408 data->msd_Accept = (CONST_STRPTR)tag->ti_Data;
409 break;
411 case MUIA_String_Reject:
412 data->msd_Reject = (CONST_STRPTR)tag->ti_Data;
413 break;
415 case MUIA_String_AdvanceOnCR:
416 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_ADVANCEONCR);
417 break;
419 case MUIA_String_AttachedList:
420 data->msd_AttachedList = (Object *)tag->ti_Data;
421 break;
423 case MUIA_String_Secret:
424 data->msd_useSecret = (BOOL)tag->ti_Data;
425 break;
427 case MUIA_String_Contents:
428 str = (CONST_STRPTR)tag->ti_Data;
429 break;
431 case MUIA_String_EditHook:
432 data->msd_EditHook = (struct Hook *)tag->ti_Data;
433 break;
435 case MUIA_String_Format:
436 data->msd_Align = (LONG)tag->ti_Data;
437 break;
439 case MUIA_String_Integer:
440 snprintf(integerbuf, 19, "%ld", tag->ti_Data);
441 str = integerbuf;
442 break;
444 case MUIA_String_LonelyEditHook:
445 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_LONELYEDITHOOK);
446 break;
448 case MUIA_String_MaxLen:
449 data->BufferSize = tag->ti_Data;
450 if (data->BufferSize < 1)
451 data->BufferSize = 1;
452 break;
454 case MUIA_String_Columns: /* BetterString */
455 data->Columns = (WORD)tag->ti_Data;
456 break;
458 case MUIA_String_NoInput: /* BetterString */
459 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_NOINPUT);
460 break;
462 case MUIA_String_StayActive: /* BetterString */
463 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_STAYACTIVE);
464 break;
469 if (Buffer_Alloc(data))
471 Buffer_SetNewContents(data, str);
474 if (NULL == data->Buffer)
476 CoerceMethod(cl, obj, OM_DISPOSE);
477 return 0;
480 D(bug("String_New(%p)\n",obj));
482 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
483 data->ehn.ehn_Priority = 0;
484 data->ehn.ehn_Flags = 0;
485 data->ehn.ehn_Object = obj;
486 data->ehn.ehn_Class = cl;
488 CurrentTime(&data->OldClick_Sec, &data->OldClick_Micro);
490 return (IPTR)obj;
493 /**************************************************************************
494 OM_DISPOSE
495 **************************************************************************/
496 IPTR String__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
498 struct MUI_StringData *data = INST_DATA(cl, obj);
500 FreeVec(data->Buffer);
501 FreeVec(data->SecBuffer);
503 D(bug("String_Dispose %p\n", obj));
505 return DoSuperMethodA(cl, obj, msg);
508 /**************************************************************************
509 OM_SET
510 **************************************************************************/
511 IPTR String__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
513 struct MUI_StringData *data = INST_DATA(cl, obj);
514 struct TagItem *tags = msg->ops_AttrList;
515 struct TagItem *tag;
517 while ((tag = NextTagItem((const struct TagItem **)&tags)) != NULL)
519 switch (tag->ti_Tag)
521 case MUIA_String_Contents:
522 Buffer_SetNewContents(data, (STRPTR)tag->ti_Data);
523 data->msd_RedrawReason = NEW_CONTENTS;
524 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
525 MUI_Redraw(obj, MADF_DRAWOBJECT);
526 break;
528 case MUIA_String_Accept:
529 data->msd_Accept = (CONST_STRPTR)tag->ti_Data;
530 break;
532 case MUIA_String_Reject:
533 data->msd_Reject = (CONST_STRPTR)tag->ti_Data;
534 break;
536 case MUIA_String_AttachedList:
537 data->msd_AttachedList = (Object *)tag->ti_Data;
538 break;
540 case MUIA_String_Integer:
542 char buf[20];
544 snprintf(buf, 19, "%ld", tag->ti_Data);
545 set(obj, MUIA_String_Contents, buf);
547 break;
549 case MUIA_String_AdvanceOnCR:
550 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_ADVANCEONCR);
551 break;
553 case MUIA_String_BufferPos:
554 data->BufferPos = (ULONG)tag->ti_Data;
555 data->msd_Flags &= ~MSDF_MARKING;
556 data->msd_RedrawReason = MOVE_CURSOR;
557 MUI_Redraw(obj, MADF_DRAWUPDATE);
558 break;
560 case MUIA_String_DisplayPos:
561 data->BufferPos = (ULONG)tag->ti_Data;
562 data->DispPos = data->BufferPos; // move both pos
563 data->msd_Flags &= ~MSDF_MARKING;
564 data->msd_RedrawReason = MOVE_CURSOR;
565 MUI_Redraw(obj, MADF_DRAWUPDATE);
566 break;
568 case MUIA_String_NoInput: /* BetterString */
569 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_NOINPUT);
570 break;
572 case MUIA_String_StayActive: /* BetterString */
573 _handle_bool_tag(data->msd_Flags, tag->ti_Data, MSDF_STAYACTIVE);
574 break;
576 case MUIA_String_SelectSize: /* BetterString */
577 #warning "TODO: Implement OM_SET(MUIA_String_SelectSize)!"
578 break;
583 return DoSuperMethodA(cl, obj, (Msg)msg);
587 /**************************************************************************
588 OM_GET
589 **************************************************************************/
590 IPTR String__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
592 struct MUI_StringData *data = INST_DATA(cl, obj);
594 #define STORE *(msg->opg_Storage)
595 switch(msg->opg_AttrID)
597 case MUIA_String_Contents:
598 if (data->msd_useSecret) STORE = (IPTR) data->SecBuffer;
599 else STORE = (IPTR) data->Buffer;
600 return TRUE;
602 case MUIA_String_Secret:
603 STORE = (IPTR) data->msd_useSecret;
604 return TRUE;
606 case MUIA_String_Accept:
607 STORE = (IPTR) data->msd_Accept;
608 return TRUE;
610 case MUIA_String_Reject:
611 STORE = (IPTR) data->msd_Reject;
612 return TRUE;
614 case MUIA_String_AttachedList:
615 STORE = (IPTR) data->msd_AttachedList;
616 return TRUE;
618 case MUIA_String_Integer:
620 STRPTR buf = NULL;
621 STORE = 0;
622 get(obj, MUIA_String_Contents, &buf);
623 if (NULL != buf)
625 LONG val = 0;
626 StrToLong(buf, &val);
627 STORE = val;
629 return TRUE;
632 case MUIA_String_MaxLen:
633 STORE = (IPTR) data->BufferSize;
634 return TRUE;
636 case MUIA_String_AdvanceOnCR:
637 STORE = (data->msd_Flags & MSDF_ADVANCEONCR) ? TRUE : FALSE;
638 return TRUE;
640 case MUIA_String_BufferPos:
641 STORE = data->BufferPos;
642 return TRUE;
644 case MUIA_String_DisplayPos:
645 STORE = data->DispPos;
646 return TRUE;
648 case MUIA_String_NoInput: /* BetterString */
649 STORE = (data->msd_Flags & MSDF_NOINPUT) ? TRUE : FALSE;
650 return TRUE;
652 case MUIA_String_StayActive: /* BetterString */
653 STORE = (data->msd_Flags & MSDF_STAYACTIVE) ? TRUE : FALSE;
654 return TRUE;
656 case MUIA_String_SelectSize: /* BetterString */
657 if (data->msd_Flags & MSDF_MARKING)
659 WORD markstart, markstop;
661 if (Buffer_GetMarkedRange(data, &markstart, &markstop))
663 LONG size = markstop - markstart;
665 if (data->MarkPos < data->BufferPos) size = -size;
667 STORE = (IPTR)size;
669 return 1;
674 STORE = 0;
675 return TRUE;
679 return DoSuperMethodA(cl, obj, (Msg) msg);
680 #undef STORE
683 /**************************************************************************
684 MUIM_Setup
685 **************************************************************************/
686 IPTR String__MUIM_Setup(struct IClass *cl, Object *obj, struct MUIP_Setup *msg)
688 struct MUI_StringData *data = INST_DATA(cl, obj);
690 if (0 == DoSuperMethodA(cl, obj, (Msg) msg))
691 return FALSE;
693 data->is_active = FALSE;
694 set(obj, MUIA_Background,
695 (IPTR)muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
697 zune_pen_spec_to_intern(
698 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->string_text_inactive,
699 &data->inactive_text);
700 zune_penspec_setup(&data->inactive_text, muiRenderInfo(obj));
702 zune_pen_spec_to_intern(
703 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->string_text_active,
704 &data->active_text);
705 zune_penspec_setup(&data->active_text, muiRenderInfo(obj));
707 zune_pen_spec_to_intern(
708 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->string_text_marked,
709 &data->marked_text);
710 zune_penspec_setup(&data->marked_text, muiRenderInfo(obj));
712 zune_pen_spec_to_intern(
713 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->string_bg_marked,
714 &data->marked_bg);
715 zune_penspec_setup(&data->marked_bg, muiRenderInfo(obj));
717 zune_pen_spec_to_intern(
718 (const struct MUI_PenSpec *)muiGlobalInfo(obj)->mgi_Prefs->string_cursor,
719 &data->cursor);
720 zune_penspec_setup(&data->cursor, muiRenderInfo(obj));
722 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
723 return TRUE;
726 /**************************************************************************
727 MUIM_Cleanup
728 **************************************************************************/
729 IPTR String__MUIM_Cleanup(struct IClass *cl, Object *obj, struct MUIP_Cleanup *msg)
731 struct MUI_StringData *data = INST_DATA(cl, obj);
733 D(bug("String_Cleanup %p\n", obj));
734 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
736 zune_penspec_cleanup(&data->inactive_text);
737 zune_penspec_cleanup(&data->active_text);
738 zune_penspec_cleanup(&data->marked_text);
739 zune_penspec_cleanup(&data->marked_bg);
740 zune_penspec_cleanup(&data->cursor);
742 return (DoSuperMethodA(cl, obj, (Msg) msg));
745 /**************************************************************************
746 MUIM_AskMinMax
747 **************************************************************************/
748 IPTR String__MUIM_AskMinMax(struct IClass *cl, Object *obj, struct MUIP_AskMinMax *msg)
750 struct MUI_StringData *data = INST_DATA(cl, obj);
752 DoSuperMethodA(cl, obj, (Msg)msg);
754 if (data->Columns >= 0)
756 msg->MinMaxInfo->MinWidth += _font(obj)->tf_XSize * data->Columns;
757 msg->MinMaxInfo->DefWidth += _font(obj)->tf_XSize * data->Columns;
758 msg->MinMaxInfo->MaxWidth += _font(obj)->tf_XSize * data->Columns;
760 else
762 msg->MinMaxInfo->MinWidth += _font(obj)->tf_XSize * 4;
763 msg->MinMaxInfo->DefWidth += _font(obj)->tf_XSize * 12;
764 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
767 msg->MinMaxInfo->MinHeight += _font(obj)->tf_YSize;
768 msg->MinMaxInfo->DefHeight += _font(obj)->tf_YSize;
769 msg->MinMaxInfo->MaxHeight += _font(obj)->tf_YSize;
771 /* D(bug("String_AskMinMax(%p): Min=%ldx%ld Max=%ldx%ld Def=%ldx%ld\n", obj, */
772 /* msg->MinMaxInfo->MinWidth, msg->MinMaxInfo->MinHeight, */
773 /* msg->MinMaxInfo->MaxWidth, msg->MinMaxInfo->MaxHeight, */
774 /* msg->MinMaxInfo->DefWidth, msg->MinMaxInfo->DefHeight)); */
776 return TRUE;
780 static WORD MaxDispPos(struct IClass *cl, Object *obj)
782 struct MUI_StringData *data = INST_DATA(cl, obj);
783 WORD numfit, max_disppos, numchars;
784 struct TextExtent te;
785 BOOL cursor_at_end;
787 cursor_at_end = (data->BufferPos == data->NumChars);
789 /* D(bug("MaxDispPos(current length: %d, bufferpos=%d)\n", */
790 /* data->NumChars, data->BufferPos)); */
792 /* D(bug("cursor_at_end: %d\n", cursor_at_end)); */
794 if (cursor_at_end) /* Cursor at end of string ? */
796 /* D(bug("Making cursor last char\n")); */
797 numchars = data->NumChars + 1; /* Take cursor into account */
799 /* This has already been done by UpdateDisp() which called us
800 strinfo->Buffer[strinfo->NumChars] = 0x20;
804 else
806 numchars = data->NumChars;
809 /* Find the amount of characters that fit into the bbox, counting
810 ** from the last character in the buffer and forward,
812 numfit = TextFit(_rp(obj),
813 &(data->Buffer[numchars - 1]),
814 numchars, &te, NULL,
815 -1, _mwidth(obj), _mheight(obj));
817 max_disppos = numchars - numfit;
819 /* if ((max_disppos > 0) && (!cursor_at_end))
820 max_disppos --;
823 /* D(bug("Numchars w/cursor: %d, Numfit: %d, maxdisppos=%d " */
824 /* "bbox->Width = %d te->te_Width = %d\n", */
825 /* numchars, numfit, max_disppos, _mwidth(obj), te.te_Width)); */
827 return max_disppos;
831 static void UpdateDisp(struct IClass *cl, Object *obj)
833 struct MUI_StringData *data = INST_DATA(cl, obj);
834 struct TextExtent te;
835 STRPTR dispstr;
837 /* If the cursor is at the trailing \0, insert a SPACE instead */
838 if (data->BufferPos == data->NumChars)
839 data->Buffer[data->NumChars] = 0x20;
841 /* In this function we check if the cursor has gone outside
842 ** of the visible area (because of application setting
843 ** strinfo->BufferPos or strinfo->DispPos to a different value, or
844 ** because of user input).
845 ** This is made a bit difficult by the rule (R), that there
846 ** should NOT be available space on the right, and characters
847 ** scrolled out at the left, at the same time.
848 ** We have 3 possible scenarios:
849 ** 1) Cursor to the left of DispPos:
850 ** Set DispPos to the lowest of BufferPos and the
851 ** maximum allowed disppos (according to (R) ).
852 ** 2) Cursor to the right of visible area:
853 ** Set dispose sou that the cursor is the last visible character.
854 ** This afheres to (R).
855 ** 3) Cursor inside visible area. Do a check on rule (R),
856 ** and if DispPos > max allowed, then adjust it down,
857 ** so that the last character in the buffer becomes last character
858 ** displayed. (The cursor will still be visible after adjustion)
861 /* 1) Cursor to the left of visible area */
862 if (data->BufferPos < data->DispPos)
864 WORD max_disppos;
866 max_disppos = MaxDispPos(cl, obj);
867 data->DispPos = MIN(data->BufferPos, max_disppos);
869 else /* Cursor equal to the right of disppos [ 2) or 3) ] */
871 UWORD strsize;
873 /* How many pixels are there from current 1st displayed to the cursor ? */
874 strsize = TextLength(_rp(obj),
875 data->Buffer + data->DispPos,
876 data->BufferPos - data->DispPos + 1);
878 /* 2) More than fits into the gadget ? */
879 if (strsize > _mwidth(obj))
881 /* Compute new DispPos such that the cursor is at the right */
882 data->DispPos = data->BufferPos
883 - TextFit(_rp(obj),
884 &(data->Buffer[data->BufferPos]),
885 data->NumChars, &te, NULL, -1,
886 _mwidth(obj), _mheight(obj))
887 + 1;
889 /* D(bug("cursor right of visible area, new disppos: %d\n", data->DispPos)); */
891 else /* 3). Cursor inside gadget */
893 WORD max_disppos;
895 max_disppos = MaxDispPos(cl, obj);
896 if (data->DispPos > max_disppos)
897 data->DispPos = max_disppos;
899 } /* if (cursor inside or to the right of visible area )*/
903 /* Update the DispCount */
904 /* It might be necessary with special handling for centre aligned gads */
905 dispstr = &(data->Buffer[data->DispPos]);
906 /* D(bug("DispCount before = %d\n", data->DispCount)); */
907 data->DispCount = TextFit(_rp(obj), dispstr,
908 data->NumChars - data->DispPos,
909 &te, NULL, 1,
910 _mwidth(obj),
911 _mheight(obj));
912 /* D(bug("DispCount after = %d\n", data->DispCount)); */
914 /* 0-terminate string */
915 data->Buffer[data->NumChars] = 0x00;
919 /* Gets left position of text in the string gadget */
920 static UWORD GetTextLeft(struct IClass *cl, Object *obj)
922 struct MUI_StringData *data = INST_DATA(cl, obj);
923 UWORD text_left = 0;
924 STRPTR dispstr = &(data->Buffer[data->DispPos]);
925 UWORD dispstrlen;
926 BOOL cursor_at_end;
928 cursor_at_end = (data->BufferPos == data->NumChars);
929 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
931 switch (data->msd_Align)
933 case MUIV_String_Format_Left:
934 text_left = _mleft(obj);
935 break;
937 case MUIV_String_Format_Center: {
938 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
939 if (cursor_at_end) textwidth += TextLength(_rp(obj), " ", 1);
940 text_left = _mleft(obj) + ((_mwidth(obj) - textwidth) / 2);
941 /* D(bug("GetTextLeft: dispstr=%s, dispstrlen=%d, textw=%d, textl=%d\n", */
942 /* dispstr, dispstrlen, textwidth, text_left)); */
943 } break;
945 case MUIV_String_Format_Right: {
946 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
948 if (cursor_at_end) textwidth += TextLength(_rp(obj), " ", 1);
949 text_left = _mleft(obj) + (_mwidth(obj) - 1 - textwidth);
950 } break;
952 return (text_left);
955 /* Gets right offset of text in the string gadget */
956 static UWORD GetTextRight(struct IClass *cl, Object *obj)
958 struct MUI_StringData *data = INST_DATA(cl, obj);
959 UWORD text_right = 0;
960 STRPTR dispstr = &(data->Buffer[data->DispPos]);
961 UWORD dispstrlen;
962 BOOL cursor_at_end;
964 cursor_at_end = (data->BufferPos == data->NumChars);
965 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
967 switch (data->msd_Align)
969 case MUIV_String_Format_Left:
970 text_right = _mleft(obj) + TextLength(_rp(obj), dispstr, dispstrlen);
971 break;
973 case MUIV_String_Format_Center: {
974 WORD textwidth = TextLength(_rp(obj), dispstr, dispstrlen);
976 if (cursor_at_end) textwidth += TextLength(_rp(obj), " ", 1);
977 text_right = _mright(obj) - ((_mwidth(obj) - textwidth) / 2);
978 } break;
980 case MUIV_String_Format_Right:
981 text_right = _mright(obj);
982 break;
984 return (text_right);
988 /* Updates the stringdata in case user has set some fields */
989 static VOID UpdateStringData(struct IClass *cl, Object *obj)
991 struct MUI_StringData *data = INST_DATA(cl, obj);
993 data->NumChars = strlen(data->Buffer);
995 if (data->BufferPos > data->NumChars)
997 data->BufferPos = data->NumChars;
1001 static VOID TextM(Object *obj, struct MUI_StringData *data,
1002 STRPTR text, WORD textlen, WORD markstart, WORD markend)
1004 struct RastPort *rp = _rp(obj);
1005 ULONG textpen;
1006 WORD len;
1008 if (data->is_active)
1009 textpen = data->active_text.p_pen;
1010 else
1011 textpen = data->inactive_text.p_pen;
1013 //kprintf("TextM: textlen %d markstart %d markend %d ... \n", textlen, markstart, markend);
1015 /* <unmarked><marked><unmarked> */
1017 /* <unmarked> */
1019 len = MIN(markstart, textlen);
1020 len = MAX(len, 0);
1022 if (len)
1024 //kprintf("A: %d ", len);
1026 SetABPenDrMd(rp, textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1027 Text(rp, text, len);
1029 text += len; textlen -= len;
1033 len = MIN(markend - len, textlen);
1034 len = MAX(len, 0);
1036 if (len)
1038 //kprintf("B: %d ", len);
1039 SetABPenDrMd(_rp(obj), data->marked_text.p_pen, data->marked_bg.p_pen, JAM2);
1040 Text(rp, text, len);
1042 text += len; textlen -= len;
1045 if (textlen)
1047 //kprintf("C: %d ", textlen);
1049 SetABPenDrMd(rp, textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1050 Text(rp, text, textlen);
1052 //kprintf("\n");
1055 /**************************************************************************
1056 MUIM_Draw
1057 **************************************************************************/
1058 IPTR String__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1060 struct MUI_StringData *data = INST_DATA(cl, obj);
1061 UWORD text_left;
1062 UWORD text_top;
1063 STRPTR dispstr;
1064 UWORD dispstrlen;
1065 ULONG textpen;
1066 UWORD textleft_save;
1067 WORD markstart = 0, markstop = 0;
1069 /* D(bug("\nString_Draw(%p) %ldx%ldx%ldx%ld reason=%ld msgflgs=%ld curs=%d " */
1070 /* "displ=%ld len=%ld buf='%s'\n",obj,_mleft(obj),_mtop(obj), */
1071 /* _mwidth(obj),_mheight(obj), data->msd_RedrawReason, msg->flags, */
1072 /* data->BufferPos, data->DispPos, data->NumChars, data->Buffer)); */
1074 DoSuperMethodA(cl,obj,(Msg)msg);
1076 if (!(msg->flags & MADF_DRAWUPDATE) && !(msg->flags & MADF_DRAWOBJECT))
1077 return 0;
1079 SetFont(_rp(obj), _font(obj));
1080 if (data->is_active)
1081 textpen = data->active_text.p_pen;
1082 else
1083 textpen = data->inactive_text.p_pen;
1085 /* Update the stringdata in case of user change */
1086 UpdateStringData(cl, obj);
1087 /* Update the DispPos and DispCount fields so that the gadget renders properly */
1088 UpdateDisp(cl, obj);
1090 text_top = _mtop(obj)
1091 + ((_mheight(obj) - _rp(obj)->Font->tf_YSize) >> 1)
1092 + _rp(obj)->Font->tf_Baseline;
1094 dispstr = data->Buffer + data->DispPos;
1095 dispstrlen = MIN(data->DispCount, data->NumChars - data->DispPos);
1096 textleft_save = text_left = GetTextLeft(cl, obj);
1098 // little flicker improvement, dont redraw first part of string
1099 // when adding a char
1100 if (msg->flags & MADF_DRAWUPDATE &&
1101 data->msd_RedrawReason == DO_ADDCHAR &&
1102 data->msd_Align == MUIV_String_Format_Left &&
1103 data->DispPos == 0)
1105 text_left += TextLength(_rp(obj), dispstr, data->BufferPos - 1);
1106 dispstr += data->BufferPos - 1;
1107 dispstrlen -= data->BufferPos - 1;
1108 DoMethod(obj, MUIM_DrawBackground, text_left, _mtop(obj),
1109 _mwidth(obj) - text_left + _mleft(obj), _mheight(obj),
1110 text_left, _mtop(obj), 0);
1112 else if (msg->flags & MADF_DRAWUPDATE)
1114 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1115 _mwidth(obj), _mheight(obj), _mleft(obj), _mtop(obj), 0);
1118 SetABPenDrMd(_rp(obj), textpen, _pens(obj)[MPEN_BACKGROUND], JAM1);
1119 Move(_rp(obj), text_left, text_top);
1121 if ((data->msd_Flags & MSDF_MARKING) && Buffer_GetMarkedRange(data, &markstart, &markstop))
1123 TextM(obj, data, dispstr, dispstrlen, markstart - data->DispPos,
1124 markstop - data->DispPos);
1127 else
1129 Text(_rp(obj), dispstr, dispstrlen);
1131 if (data->is_active) // active, draw cursor
1133 UWORD cursoroffset = data->BufferPos - data->DispPos;
1135 dispstr = data->Buffer + data->DispPos;
1136 text_left = textleft_save;
1138 SetABPenDrMd(_rp(obj), data->active_text.p_pen, data->cursor.p_pen, JAM2);
1139 text_left += TextLength(_rp(obj), dispstr, cursoroffset);
1142 Move(_rp(obj), text_left, text_top);
1143 Text(_rp(obj),
1144 ((data->BufferPos < data->NumChars)
1145 ? dispstr + cursoroffset
1146 : (STRPTR)" "),
1147 1 );
1151 data->msd_RedrawReason = NO_REASON;
1152 return TRUE;
1155 /**************************************************************************
1156 Returns wether object needs redrawing
1157 **************************************************************************/
1158 static int String_HandleVanillakey(struct IClass *cl, Object * obj,
1159 unsigned char code, UWORD qual)
1161 struct MUI_StringData *data = (struct MUI_StringData*)INST_DATA(cl, obj);
1162 BOOL doinput;
1164 D(bug("String_HandleVanillakey: code=%d qual=%d\n", code, qual));
1166 if (0 == code)
1167 return 0;
1169 doinput = (data->msd_Flags & MSDF_NOINPUT) ? FALSE : TRUE;
1171 if (doinput && (code == '\b')) /* backspace */
1173 if (Buffer_KillMarked(data))
1175 return 1;
1178 if (data->BufferPos > 0)
1180 LONG shift;
1182 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
1184 shift = data->BufferPos;
1185 data->msd_RedrawReason = NEW_CONTENTS;
1187 else
1189 shift = 1;
1190 data->msd_RedrawReason = DO_BACKSPACE;
1193 strcpy(&data->Buffer[data->BufferPos - shift],
1194 &data->Buffer[data->BufferPos]);
1195 data->BufferPos -= shift;
1196 data->NumChars -= shift;
1197 return 1;
1199 return 0;
1202 if (doinput && (code == 21)) // ctrl-u == NAK (like shift-bs)
1204 if (Buffer_KillMarked(data))
1206 return 1;
1209 if (data->BufferPos > 0)
1211 strcpy(&data->Buffer[0],
1212 &data->Buffer[data->BufferPos]);
1213 data->NumChars -= data->BufferPos;
1214 data->BufferPos = 0;
1215 data->msd_RedrawReason = NEW_CONTENTS;
1216 return 1;
1218 return 0;
1221 if (doinput && (code == 127)) /* del */
1223 if (!Buffer_KillMarked(data))
1225 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
1227 data->Buffer[data->BufferPos] = 0;
1228 data->NumChars = data->BufferPos;
1229 data->msd_RedrawReason = NEW_CONTENTS;
1231 else
1233 if (data->BufferPos < data->NumChars)
1235 strcpy(&data->Buffer[data->BufferPos],
1236 &data->Buffer[data->BufferPos+1]);
1237 data->NumChars--;
1240 data->msd_RedrawReason = DO_DELETE;
1243 return 1;
1246 if (doinput && (code == 11)) // ctrl-k == VT == \v (like shift-del)
1248 if (!Buffer_KillMarked(data))
1250 data->Buffer[data->BufferPos] = 0;
1251 data->NumChars = data->BufferPos;
1252 data->msd_RedrawReason = NEW_CONTENTS;
1254 return 1;
1257 if (doinput && (code == 24)) /* ctrl x == ascii cancel */
1259 if (!Buffer_KillMarked(data))
1261 data->Buffer[0] = 0;
1262 data->BufferPos = 0;
1263 data->NumChars = 0;
1264 data->msd_RedrawReason = NEW_CONTENTS;
1266 return 1;
1269 if (code == 1) // ctrl-a, linestart
1271 data->BufferPos = 0;
1272 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
1273 return 1;
1276 if (code == 26) // ctrl-z, lineend
1278 data->BufferPos = data->NumChars;
1279 data->msd_Flags &= ~(MSDF_MARKING | MSDF_KEYMARKING);
1280 return 1;
1283 if (((ToLower(code) == 'c') || (ToLower(code) == 'x')) &&
1284 (qual & IEQUALIFIER_RCOMMAND))
1286 WORD markstart, markstop;
1288 if ((data->msd_Flags & MSDF_MARKING) && Buffer_GetMarkedRange(data, &markstart, &markstop))
1290 clipboard_write_text(&data->Buffer[markstart], markstop - markstart);
1292 if (doinput && (ToLower(code) == 'x'))
1294 Buffer_KillMarked(data);
1296 else
1298 data->BufferPos = markstop;
1299 data->msd_Flags &= ~MSDF_MARKING;
1301 return 1;
1303 return 0;
1306 if (doinput && (ToLower(code) == 'v') && (qual & IEQUALIFIER_RCOMMAND))
1308 STRPTR text;
1309 int retval;
1310 struct Locale *locale = OpenLocale(NULL);
1312 retval = Buffer_KillMarked(data);
1313 if ((text = clipboard_read_text()))
1315 STRPTR text2 = text;
1316 UBYTE c;
1318 while((c = *text2++))
1320 if (!IsPrint(locale, c)) break;
1321 if (!(Buffer_AddChar(data, c))) break;
1322 if (!retval) retval = 1;
1325 clipboard_free_text(text);
1328 CloseLocale(locale);
1330 return retval;
1333 if (data->msd_Accept != NULL)
1335 /* Check if character is accepted */
1336 if (NULL == strchr(data->msd_Accept, code))
1337 return 0;
1340 if (data->msd_Reject != NULL)
1342 /* Check if character is rejected */
1343 if (NULL != strchr(data->msd_Reject, code))
1345 DisplayBeep(NULL);
1346 return 0;
1350 if (doinput)
1352 struct Locale *locale = OpenLocale(NULL);
1354 if(!(code >= 0x09 && code <= 0x0D) && IsPrint(locale, code))
1356 Buffer_KillMarked(data);
1357 if (Buffer_AddChar(data, code))
1359 data->msd_RedrawReason = DO_ADDCHAR;
1360 return 2;
1364 CloseLocale(locale);
1367 data->msd_RedrawReason = DO_UNKNOWN;
1368 return 0;
1372 /**************************************************************************
1373 MUIM_HandleEvent
1374 **************************************************************************/
1375 IPTR String__MUIM_HandleEvent(struct IClass *cl, Object * obj,
1376 struct MUIP_HandleEvent *msg)
1378 struct MUI_StringData *data = (struct MUI_StringData*) INST_DATA(cl, obj);
1379 ULONG retval = 0;
1380 int update = 0;
1381 LONG muikey = msg->muikey;
1382 BOOL cursor_kills_marking = FALSE;
1384 if ((data->msd_Flags & MSDF_MARKING) && !(data->msd_Flags & MSDF_KEYMARKING))
1386 cursor_kills_marking = TRUE;
1389 if (muikey == MUIKEY_NONE)
1391 if (msg->imsg->Class == IDCMP_RAWKEY)
1393 static LONG muikeytable[3][2] =
1395 {MUIKEY_LEFT , MUIKEY_RIGHT },
1396 {MUIKEY_WORDLEFT , MUIKEY_WORDRIGHT },
1397 {MUIKEY_LINESTART , MUIKEY_LINEEND }
1399 WORD dirindex = -1, amountindex = 0;
1401 switch(msg->imsg->Code)
1403 case 0x4F:
1404 dirindex = 0;
1405 break;
1407 case 0x4E:
1408 dirindex = 1;
1409 break;
1411 #ifdef __AROS__
1412 case RAWKEY_HOME:
1413 muikey = MUIKEY_LINESTART;
1414 break;
1416 case RAWKEY_END:
1417 muikey = MUIKEY_LINEEND;
1418 break;
1419 #endif
1423 if ((dirindex != -1) && (muikey == MUIKEY_NONE))
1425 if (msg->imsg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
1427 amountindex = 2;
1429 else if (msg->imsg->Qualifier & IEQUALIFIER_CONTROL)
1431 amountindex = 1;
1434 muikey = muikeytable[amountindex][dirindex];
1440 D(bug("String_HandleEvent: muikey %d, imsg %p is_active=%d\n", muikey,
1441 msg->imsg, data->is_active));
1442 if (muikey != MUIKEY_NONE && data->is_active)
1444 retval = MUI_EventHandlerRC_Eat;
1446 switch (muikey)
1448 case MUIKEY_LEFT:
1449 if (cursor_kills_marking)
1451 update = 1;
1452 data->BufferPos = MIN(data->BufferPos, data->MarkPos);
1453 if (data->BufferPos > 0) data->BufferPos--;
1455 data->msd_Flags &= ~MSDF_MARKING;
1457 else if (data->BufferPos > 0)
1459 update = 1;
1461 data->BufferPos--;
1462 data->msd_RedrawReason = DO_CURSOR_LEFT;
1464 break;
1465 case MUIKEY_RIGHT:
1466 if (cursor_kills_marking)
1468 update = 1;
1469 data->BufferPos = MAX(data->BufferPos, data->MarkPos);
1470 data->msd_Flags &= ~MSDF_MARKING;
1472 else if (data->BufferPos < data->NumChars)
1474 update = 1;
1475 data->BufferPos++;
1476 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1478 break;
1479 case MUIKEY_WORDLEFT:
1480 if (data->BufferPos > 0)
1482 data->BufferPos = Buffer_GetPrevWordIndex(data, data->BufferPos);
1483 update = 1;
1484 data->msd_RedrawReason = DO_CURSOR_LEFT;
1486 if (cursor_kills_marking)
1488 data->msd_Flags &= ~MSDF_MARKING;
1489 update = 1;
1491 break;
1492 case MUIKEY_WORDRIGHT:
1493 if (data->BufferPos < data->NumChars)
1495 data->BufferPos = Buffer_GetSuccWordIndex(data, data->BufferPos);
1496 update = 1;
1497 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1499 if (cursor_kills_marking)
1501 data->msd_Flags &= ~MSDF_MARKING;
1502 update = 1;
1504 break;
1505 case MUIKEY_LINESTART:
1506 data->BufferPos = 0;
1507 update = 1;
1508 if (cursor_kills_marking)
1510 data->msd_Flags &= ~MSDF_MARKING;
1512 break;
1514 case MUIKEY_LINEEND:
1515 data->BufferPos = data->NumChars;
1516 update = 1;
1517 if (cursor_kills_marking)
1519 data->msd_Flags &= ~MSDF_MARKING;
1521 break;
1523 case MUIKEY_UP:
1524 if (data->msd_AttachedList)
1525 set(data->msd_AttachedList,
1526 MUIA_List_Active, MUIV_List_Active_Up);
1527 break;
1528 case MUIKEY_DOWN:
1529 if (data->msd_AttachedList)
1530 set(data->msd_AttachedList,
1531 MUIA_List_Active, MUIV_List_Active_Down);
1532 break;
1533 case MUIKEY_PAGEUP:
1534 if (data->msd_AttachedList)
1535 set(data->msd_AttachedList,
1536 MUIA_List_Active, MUIV_List_Active_PageUp);
1537 break;
1538 case MUIKEY_PAGEDOWN:
1539 if (data->msd_AttachedList)
1540 set(data->msd_AttachedList,
1541 MUIA_List_Active, MUIV_List_Active_PageDown);
1542 break;
1543 case MUIKEY_TOP:
1544 if (data->msd_AttachedList)
1545 set(data->msd_AttachedList,
1546 MUIA_List_Active, MUIV_List_Active_Top);
1547 break;
1548 case MUIKEY_BOTTOM:
1549 if (data->msd_AttachedList)
1550 set(data->msd_AttachedList,
1551 MUIA_List_Active, MUIV_List_Active_Bottom);
1552 break;
1553 case MUIKEY_PRESS: {
1554 UBYTE *buf = NULL;
1556 get(obj, MUIA_String_Contents, &buf);
1558 if (data->msd_Flags & MSDF_STAYACTIVE)
1560 /* Do not change active object */
1562 else if (data->msd_Flags & MSDF_ADVANCEONCR)
1564 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_Next);
1566 else if (!(data->msd_Flags & MSDF_STAYACTIVE))
1568 set(_win(obj), MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
1571 set(obj, MUIA_String_Acknowledge, buf);
1572 } break;
1574 case MUIKEY_WINDOW_CLOSE:
1575 data->is_active = FALSE;
1576 set(obj, MUIA_Background,
1577 (IPTR)muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
1578 DoMethod(obj, MUIM_GoInactive);
1579 retval = 0;
1580 break;
1582 default:
1583 retval = 0;
1584 } // switch(muikey)
1585 } // if (muikey != MUIKEY_NONE)
1587 if (msg->imsg)
1589 UWORD code = msg->imsg->Code;
1590 //UWORD qual = msg->imsg->Qualifier;
1591 WORD x = msg->imsg->MouseX;
1592 WORD y = msg->imsg->MouseY;
1594 //bug("String_HandleEvent: parsing imsg %p, class=%ld\n", msg->imsg, msg->imsg->Class);
1596 switch (msg->imsg->Class)
1598 case IDCMP_MOUSEBUTTONS: /* set cursor and activate it */
1599 if (code == SELECTDOWN)
1601 //bug("String_HandleEvent: code == SELECTDOWN, x=%d y=%d\n", x, y);
1603 if (_isinobject(x, y))
1605 UWORD text_left, text_right;
1607 retval = MUI_EventHandlerRC_Eat;
1609 CurrentTime(&data->NewClick_Sec, &data->NewClick_Micro);
1610 if (DoubleClick(data->OldClick_Sec, data->OldClick_Micro,
1611 data->NewClick_Sec, data->NewClick_Micro))
1613 data->MultiClick++;
1615 else
1617 data->MultiClick = 0;
1619 data->OldClick_Sec = data->NewClick_Sec;
1620 data->OldClick_Micro = data->NewClick_Micro;
1622 //kprintf("multiclick %d\n", data->MultiClick);
1624 if (!data->is_active)
1626 //bug("String got button, lets activate\n");
1627 data->is_active = TRUE;
1628 data->msd_RedrawReason = WENT_ACTIVE;
1629 // redraw
1630 set(obj, MUIA_Background,
1631 (IPTR)muiGlobalInfo(obj)->mgi_Prefs->string_bg_active);
1633 //DoMethod(obj, MUIM_GoActive);
1634 set(_win(obj), MUIA_Window_ActiveObject, obj);
1635 // let other objects a chance to get desactivated
1636 //retval = 0;
1639 if (!(data->ehn.ehn_Events & IDCMP_MOUSEMOVE))
1641 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
1642 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
1643 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
1646 text_left = GetTextLeft (cl, obj);
1647 text_right = GetTextRight(cl, obj);
1649 /* Check if mouseclick is inside displayed text */
1650 if ((x >= text_left) && (x <= text_right))
1652 /* Find new cursor pos. */
1653 struct TextExtent te;
1654 ULONG newpos;
1655 STRPTR dispstr = data->Buffer + data->DispPos;
1657 newpos = data->DispPos
1658 + TextFit(_rp(obj), dispstr, data->NumChars - data->DispPos,
1659 &te, NULL, 1,
1660 x - text_left, _rp(obj)->Font->tf_YSize);
1662 if (data->BufferPos != newpos)
1664 data->BufferPos = newpos;
1665 update = 1;
1668 else if (x < text_left)
1670 /* Click on empty space at left. Set cursor to first visible */
1671 if (data->BufferPos != data->DispPos)
1673 data->BufferPos = data->DispPos;
1674 update = 1;
1677 else
1679 /* Click on empty space at right. Set cursor to last visible */
1680 if (data->BufferPos != data->DispPos + data->DispCount)
1682 data->BufferPos = data->DispPos + data->DispCount;
1683 update = 1;
1685 } /* if (click is on text or not) */
1687 data->MarkPos = data->BufferPos;
1689 if (data->MultiClick == 0)
1691 if (data->msd_Flags & MSDF_MARKING)
1693 data->msd_Flags &= ~MSDF_MARKING;
1694 update = 1;
1697 else if (data->MultiClick && Buffer_GetMarkedRange(data, NULL, NULL))
1699 data->msd_Flags |= MSDF_MARKING;
1700 update = 1;
1704 } /* is in object */
1705 else if (data->is_active && !(data->msd_Flags & MSDF_STAYACTIVE)) /* and click not on object */
1707 data->is_active = FALSE;
1708 set(obj, MUIA_Background,
1709 (IPTR)muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
1710 //DoMethod(obj, MUIM_GoInactive);
1711 // let other objects a chance to get activated
1712 //retval = 0;
1714 } /* if (code == SELECTDOWN) */
1715 else if (code == SELECTUP)
1717 if (data->ehn.ehn_Events & IDCMP_MOUSEMOVE)
1719 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
1720 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
1721 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
1724 break;
1726 case IDCMP_MOUSEMOVE:
1727 if (data->is_active)
1729 UWORD text_left, text_right;
1731 if (!(data->msd_Flags & MSDF_MARKING))
1733 data->msd_Flags |= MSDF_MARKING;
1736 text_left = GetTextLeft (cl, obj);
1737 text_right = GetTextRight(cl, obj);
1739 /* Check if mouseclick is inside displayed text */
1740 if ((x >= text_left) && (x <= text_right))
1742 /* Find new cursor pos. */
1743 struct TextExtent te;
1744 ULONG newpos;
1745 STRPTR dispstr = data->Buffer + data->DispPos;
1747 newpos = data->DispPos
1748 + TextFit(_rp(obj), dispstr, data->NumChars - data->DispPos,
1749 &te, NULL, 1,
1750 x - text_left, _rp(obj)->Font->tf_YSize);
1752 if (data->BufferPos != newpos)
1754 WORD old_markstart = 0, old_markstop = 0;
1755 WORD markstart = 0, markstop = 0;
1756 BOOL was_marked, is_marked;
1758 was_marked = Buffer_AnythingMarked(data) &&
1759 Buffer_GetMarkedRange(data, &old_markstart, &old_markstop);
1761 data->BufferPos = newpos;
1763 is_marked = Buffer_AnythingMarked(data) &&
1764 Buffer_GetMarkedRange(data, &markstart, &markstop);
1766 if ((was_marked != is_marked) ||
1767 (old_markstart != markstart) ||
1768 (old_markstop != markstop))
1770 update = 1;
1774 else if ((x < text_left) && (data->BufferPos > 0))
1776 data->BufferPos--;
1777 update = 1;
1778 data->msd_RedrawReason = DO_CURSOR_LEFT;
1780 else if ((x > text_right) && (data->BufferPos < data->NumChars))
1782 data->BufferPos++;
1783 update = 1;
1784 data->msd_RedrawReason = DO_CURSOR_RIGHT;
1786 //kprintf(" ---- bp: %d\n", data->BufferPos);
1788 break;
1790 case IDCMP_RAWKEY:
1792 unsigned char code;
1794 //bug("String_HandleEvent: idcmp_rawkey\n");
1796 if (!data->is_active)
1797 break;
1799 code = ConvertKey(msg->imsg);
1800 if (!code)
1802 switch(msg->imsg->Code)
1804 case 0x64: /* LALT */
1805 case 0x65: /* RALT */
1806 case 0x64 | IECODE_UP_PREFIX:
1807 case 0x65 | IECODE_UP_PREFIX:
1808 if (msg->imsg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
1810 data->MarkPos = data->BufferPos;
1811 data->msd_Flags |= (MSDF_MARKING | MSDF_KEYMARKING);
1813 else
1815 data->msd_Flags &= ~MSDF_KEYMARKING;
1817 break;
1822 if (code)
1824 update = String_HandleVanillakey(cl, obj, code, msg->imsg->Qualifier);
1825 if (update)
1826 retval = MUI_EventHandlerRC_Eat;
1829 break;
1833 if (update)
1835 MUI_Redraw(obj, MADF_DRAWUPDATE);
1837 //D(bug("String eh return %ld\n", retval));
1838 return retval;
1842 /**************************************************************************
1843 MUIM_Export : to export an objects "contents" to a dataspace object.
1844 **************************************************************************/
1845 IPTR String__MUIM_Export(struct IClass *cl, Object *obj, struct MUIP_Export *msg)
1847 struct MUI_StringData *data = INST_DATA(cl, obj);
1848 ULONG id;
1849 STRPTR buf = NULL;
1851 if (data->msd_useSecret)
1852 buf = data->SecBuffer;
1853 else
1854 buf = data->Buffer;
1856 if ((id = muiNotifyData(obj)->mnd_ObjectID))
1858 if (buf != NULL)
1859 DoMethod(msg->dataspace, MUIM_Dataspace_Add,
1860 (IPTR)buf,
1861 data->NumChars + 1,
1862 (IPTR)id);
1863 else
1864 DoMethod(msg->dataspace, MUIM_Dataspace_Remove,
1865 (IPTR)id);
1867 return 0;
1871 /**************************************************************************
1872 MUIM_Import : to import an objects "contents" from a dataspace object.
1873 **************************************************************************/
1874 IPTR String__MUIM_Import(struct IClass *cl, Object *obj, struct MUIP_Import *msg)
1876 ULONG id;
1877 STRPTR s;
1879 if ((id = muiNotifyData(obj)->mnd_ObjectID))
1881 if ((s = (STRPTR)DoMethod(msg->dataspace, MUIM_Dataspace_Find, (IPTR)id)))
1883 set(obj, MUIA_String_Contents, s);
1886 return 0;
1889 /**************************************************************************
1890 MUIM_GoActive
1891 **************************************************************************/
1892 IPTR String__MUIM_GoActive(struct IClass * cl, Object * obj, Msg msg)
1894 struct MUI_StringData *data = (struct MUI_StringData*) INST_DATA(cl, obj);
1896 //D(bug("String_GoActive %p\n", obj));
1897 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
1898 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
1899 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
1900 data->is_active = TRUE;
1901 data->msd_Flags &= ~MSDF_KEYMARKING;
1902 data->msd_RedrawReason = WENT_ACTIVE;
1903 // redraw
1904 set(obj, MUIA_Background,
1905 (IPTR)muiGlobalInfo(obj)->mgi_Prefs->string_bg_active);
1906 return 0;
1909 /**************************************************************************
1910 MUIM_GoInactive
1911 **************************************************************************/
1912 IPTR String__MUIM_GoInactive(struct IClass * cl, Object * obj, Msg msg)
1914 struct MUI_StringData *data = (struct MUI_StringData*) INST_DATA(cl, obj);
1916 //D(bug("String_GoInactive %p\n", obj));
1918 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
1919 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
1920 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
1921 data->is_active = FALSE;
1922 data->msd_RedrawReason = WENT_INACTIVE;
1923 data->MultiClick = 0;
1925 // redraw
1926 set(obj, MUIA_Background,
1927 (IPTR)muiGlobalInfo(obj)->mgi_Prefs->string_bg_inactive);
1928 return 0;
1931 /**************************************************************************
1932 MUIM_String_ClearSelected (BetterString)
1933 **************************************************************************/
1934 IPTR String__MUIM_ClearSelected(struct IClass * cl, Object * obj, struct MUIP_String_ClearSelected *msg)
1936 struct MUI_StringData *data = (struct MUI_StringData*) INST_DATA(cl, obj);
1938 //D(bug("String_ClearSelected %p\n", obj));
1940 if (Buffer_KillMarked(data))
1942 MUI_Redraw(obj, MADF_DRAWUPDATE);
1945 return 0;
1948 /**************************************************************************
1949 MUIM_String_Insert (BetterString)
1950 **************************************************************************/
1951 IPTR String__MUIM_Insert(struct IClass * cl, Object * obj, struct MUIP_String_Insert *msg)
1953 struct MUI_StringData *data = (struct MUI_StringData*) INST_DATA(cl, obj);
1954 LONG pos;
1955 ULONG old_bufferpos;
1956 ULONG num_inserted = 0;
1958 //D(bug("String_Insert %p\n", obj));
1960 switch((ULONG)msg->pos)
1962 case MUIV_String_Insert_StartOfString:
1963 pos = 0;
1964 break;
1966 case MUIV_String_Insert_EndOfString:
1967 pos = data->NumChars;
1968 break;
1970 case MUIV_String_Insert_BufferPos:
1971 pos = data->BufferPos;
1972 break;
1974 default:
1975 pos = msg->pos;
1976 break;
1979 if ((pos < 0) || (pos > data->NumChars)) return 0;
1981 old_bufferpos = data->BufferPos;
1982 data->BufferPos = pos;
1984 while(msg->text[num_inserted] && Buffer_AddChar(data, msg->text[num_inserted]))
1986 num_inserted++;
1989 if (num_inserted)
1991 if (old_bufferpos >= pos)
1993 data->BufferPos = old_bufferpos + num_inserted;
1995 else
1997 data->BufferPos = old_bufferpos;
2000 MUI_Redraw(obj, MADF_DRAWUPDATE);
2003 return 0;
2006 /**************************************************************************
2007 MUIM_String_FileNameStart (BetterString)
2008 **************************************************************************/
2009 IPTR String__MUIM_FileNameStart(struct IClass * cl, Object * obj, struct MUIP_String_FileNameStart *msg)
2011 struct MUI_StringData *data = (struct MUI_StringData*) INST_DATA(cl, obj);
2012 STRPTR buf;
2014 //D(bug("String_FileNameStart %p\n", obj));
2016 if (data->msd_useSecret)
2018 buf = data->SecBuffer;
2020 else
2022 buf = data->Buffer;
2024 #warning "TODO: Implement String_FileNameStart correctly!"
2026 return (IPTR)buf;
2029 BOOPSI_DISPATCHER(IPTR, String_Dispatcher, cl, obj, msg)
2031 switch (msg->MethodID)
2033 case OM_NEW: return String__OM_NEW(cl, obj, (struct opSet *) msg);
2034 case OM_DISPOSE: return String__OM_DISPOSE(cl, obj, msg);
2035 case OM_SET: return String__OM_SET(cl, obj, (struct opSet *)msg);
2036 case OM_GET: return String__OM_GET(cl, obj, (struct opGet *)msg);
2038 case MUIM_Setup: return String__MUIM_Setup(cl, obj, (APTR)msg);
2039 case MUIM_Cleanup: return String__MUIM_Cleanup(cl, obj, (APTR)msg);
2040 case MUIM_AskMinMax: return String__MUIM_AskMinMax(cl, obj, (APTR)msg);
2041 case MUIM_Draw: return String__MUIM_Draw(cl, obj, (APTR)msg);
2042 case MUIM_Export: return String__MUIM_Export(cl, obj, (APTR)msg);
2043 case MUIM_Import: return String__MUIM_Import(cl, obj, (APTR)msg);
2044 case MUIM_GoActive: return String__MUIM_GoActive(cl, obj, (APTR)msg);
2045 case MUIM_GoInactive: return String__MUIM_GoInactive(cl,obj,(APTR)msg);
2046 case MUIM_HandleEvent: return String__MUIM_HandleEvent(cl,obj,(APTR)msg);
2047 case MUIM_String_ClearSelected: return String__MUIM_ClearSelected(cl,obj,(APTR)msg); /* BetterString */
2048 case MUIM_String_Insert: return String__MUIM_Insert(cl,obj,(APTR)msg); /* BetterString */
2049 case MUIM_String_FileNameStart: return String__MUIM_FileNameStart(cl,obj,(APTR)msg); /* BetterString */
2052 return DoSuperMethodA(cl, obj, msg);
2054 BOOPSI_DISPATCHER_END
2058 * Class descriptor.
2060 const struct __MUIBuiltinClass _MUI_String_desc = {
2061 MUIC_String,
2062 MUIC_Area,
2063 sizeof(struct MUI_StringData),
2064 (void*)String_Dispatcher