revert between 56095 -> 55830 in arch
[AROS.git] / workbench / classes / zune / texteditor / mcc / EditorStuff.c
blobf0b683470a41534523ac72a459e1ed9d3780bea1
1 /***************************************************************************
3 TextEditor.mcc - Textediting MUI Custom Class
4 Copyright (C) 1997-2000 Allan Odgaard
5 Copyright (C) 2005-2014 TextEditor.mcc Open Source Team
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 TextEditor class Support Site: http://www.sf.net/projects/texteditor-mcc
19 $Id$
21 ***************************************************************************/
23 #include <string.h>
25 #include <devices/clipboard.h>
26 #include <libraries/iffparse.h>
28 #include <clib/alib_protos.h>
29 #include <proto/graphics.h>
30 #include <proto/layers.h>
31 #include <proto/exec.h>
32 #include <proto/intuition.h>
34 #include "private.h"
35 #include "Debug.h"
37 #if defined(__MORPHOS__)
38 #include <proto/keymap.h>
39 #include <proto/locale.h>
41 ///utf8_to_ansi()
42 static char *utf8_to_ansi(STRPTR src)
44 static struct KeyMap *keymap;
45 CONST_STRPTR ptr;
46 STRPTR dst;
47 ULONG octets, strlength;
49 ENTER();
51 keymap = AskKeyMapDefault();
53 strlength = 0;
54 ptr = src;
58 WCHAR wc;
59 UBYTE c;
61 ptr += (octets = UTF8_Decode(ptr, &wc));
62 c = ToANSI(wc, keymap);
64 strlength++;
66 /* ToANSI() returns '?' if there is not matching code point in the current keymap */
67 if (c == '?' && wc != '?')
69 /* If direct conversion fails try compatibility decomposition (but without recursion) */
70 CONST_WSTRPTR p = UCS4_Decompose(wc);
72 if (p)
74 while (p[1])
76 strlength++;
77 p++;
82 while (octets > 0);
84 // the new string must be AllocVec()'d instead of AllocVecPooled()'d, because
85 // we handle data from the clipboard server which also uses AllocVec()
86 dst = AllocVecShared(strlength, MEMF_ANY);
88 if (dst)
90 STRPTR bufptr = dst;
92 ptr = src;
96 WCHAR wc;
97 UBYTE c;
99 ptr += (octets = UTF8_Decode(ptr, &wc));
100 c = ToANSI(wc, keymap);
102 *bufptr++ = c;
104 if (c == '?' && wc != '?')
106 CONST_WSTRPTR p = UCS4_Decompose(wc);
108 if (p)
110 bufptr--;
112 while (*p)
114 *bufptr++ = ToANSI(*p, keymap);
115 p++;
120 while (octets > 0);
122 // free original buffer
123 FreeVec(src);
126 if(dst == NULL)
127 dst = src;
129 RETURN(dst);
130 return dst;
134 #endif
136 /// DumpLine()
137 #if defined(DEBUG)
138 void DumpLine(struct line_node *line)
140 ENTER();
142 D(DBF_DUMP, "length %3ld, contents '%s'", line->line.Length, line->line.Contents);
144 if(line->line.Styles != NULL)
146 struct LineStyle *styles = line->line.Styles;
147 int numStyles = 0;
149 D(DBF_DUMP, "styles:");
150 while(styles->column != EOS)
152 D(DBF_DUMP, "style 0x%04lx starting at column %3ld", styles->style, styles->column);
153 styles++;
154 numStyles++;
156 D(DBF_DUMP, "%ld style changes", numStyles);
159 if(line->line.Colors != NULL)
161 struct LineColor *colors = line->line.Colors;
162 int numColors = 0;
164 D(DBF_DUMP, "colors:");
165 while(colors->column != EOC)
167 D(DBF_DUMP, "color %3ld starting at column %3ld", colors->color, colors->column);
168 colors++;
169 numColors++;
171 D(DBF_DUMP, "%ld color changes", numColors);
174 if(line->line.Highlight == TRUE)
175 D(DBF_DUMP, "line is highlighted");
177 LEAVE();
179 #else
180 #define DumpLine(line) ((void)0)
181 #endif
184 /// PasteClip()
185 /*----------------------*
186 * Paste from Clipboard *
187 *----------------------*/
188 BOOL PasteClip(struct InstData *data, LONG x, struct line_node *actline)
190 BOOL res = FALSE;
191 IPTR clipSession;
193 ENTER();
195 if((clipSession = ClientStartSession(IFFF_READ)) != (IPTR)NULL)
197 LONG error;
198 BOOL newline = TRUE;
199 struct MinList importedLines;
201 InitLines(&importedLines);
205 struct line_node *line = NULL;
206 ULONG codeset = 0;
208 error = ClientReadLine(clipSession, &line, &codeset);
209 SHOWVALUE(DBF_CLIPBOARD, error);
210 SHOWVALUE(DBF_CLIPBOARD, line);
211 SHOWVALUE(DBF_CLIPBOARD, codeset);
213 if(error == 0 && line != NULL)
215 struct LineStyle *styles = NULL;
216 struct LineColor *colors = NULL;
217 BOOL ownclip = FALSE;
219 SHOWVALUE(DBF_CLIPBOARD, line->line.Styles);
220 if(line->line.Styles != NULL)
222 // check whether styles are wanted when pasting the clip
223 if(isFlagSet(data->flags, FLG_PasteStyles))
225 struct Grow styleGrow;
226 struct LineStyle *style = line->line.Styles;
228 InitGrow(&styleGrow, data->mypool, sizeof(struct LineStyle));
230 while(style->column != EOS)
232 AddToGrow(&styleGrow, style);
233 style++;
235 // add the terminating entry as well
236 AddToGrow(&styleGrow, style);
238 styles = (struct LineStyle *)styleGrow.array;
241 // the clipboard server used AllocVec() before
242 FreeVec(line->line.Styles);
243 line->line.Styles = NULL;
245 // we found styles, this mean the clip was created by ourselves
246 ownclip = TRUE;
249 SHOWVALUE(DBF_CLIPBOARD, line->line.Colors);
250 if(line->line.Colors != NULL)
252 // check whether colors are wanted when pasting the clip
253 if(isFlagSet(data->flags, FLG_PasteColors))
255 struct Grow colorGrow;
256 struct LineColor *color = line->line.Colors;
258 InitGrow(&colorGrow, data->mypool, sizeof(struct LineColor));
260 while(color->column != EOC)
262 AddToGrow(&colorGrow, color);
263 color++;
265 // add the terminating entry as well
266 AddToGrow(&colorGrow, color);
268 colors = (struct LineColor *)colorGrow.array;
271 // the clipboard server used AllocVec() before
272 FreeVec(line->line.Colors);
273 line->line.Colors = NULL;
275 // we found colors, this mean the clip was created by ourselves
276 ownclip = TRUE;
279 if(line->line.Highlight == TRUE || line->line.Flow != MUIV_TextEditor_Flow_Left || line->line.Separator != LNSF_None)
281 // we found some of our own stuff, this mean the clip was created by ourselves
282 ownclip = TRUE;
285 SHOWVALUE(DBF_CLIPBOARD, line->line.Highlight);
286 SHOWVALUE(DBF_CLIPBOARD, line->line.Flow);
287 SHOWVALUE(DBF_CLIPBOARD, line->line.clearFlow);
288 SHOWVALUE(DBF_CLIPBOARD, line->line.Separator);
289 SHOWVALUE(DBF_CLIPBOARD, line->line.Contents);
290 if(line->line.Contents != NULL)
292 STRPTR contents = line->line.Contents;
293 ULONG length = line->line.Length;
295 if(ownclip == FALSE)
297 struct MinList importedBlock;
299 // this is a foreign clip
300 D(DBF_CLIPBOARD, "importing foreign clip");
302 if(contents[length-1] != '\n')
303 newline = FALSE;
304 else
305 length--;
306 contents[length] = '\0';
308 #if defined(__MORPHOS__)
309 if(codeset == CODESET_UTF8 && IS_MORPHOS2)
311 // convert UTF8 string to ANSI
312 line->line.Contents = utf8_to_ansi(line->line.Contents);
313 // and update the contents pointer as well
314 contents = line->line.Contents;
316 #endif
318 SHOWSTRING(DBF_CLIPBOARD, contents);
320 if(ImportText(data, contents, &ImPlainHook, data->ImportWrap, &importedBlock) == TRUE)
322 // append the imported lines
323 MoveLines(&importedLines, &importedBlock);
326 else
328 struct line_node *importedLine;
330 // this is one of our own clips
331 D(DBF_CLIPBOARD, "importing TextEditor.mcc clip");
333 if(contents[length-1] != '\n')
335 newline = FALSE;
336 contents[length] = '\n';
337 length++;
339 contents[length] = '\0';
341 SHOWSTRING(DBF_CLIPBOARD, contents);
343 if((importedLine = AllocVecPooled(data->mypool, sizeof(struct line_node))) != NULL)
345 if((contents = AllocVecPooled(data->mypool, length+1)) != NULL)
347 strcpy(contents, line->line.Contents);
348 importedLine->line.Contents = contents;
349 importedLine->line.Length = length;
350 importedLine->line.allocatedContents = length+1;
351 importedLine->line.Highlight = line->line.Highlight;
352 importedLine->line.Flow = line->line.Flow;
353 importedLine->line.clearFlow = line->line.clearFlow;
354 importedLine->line.Separator = line->line.Separator;
355 importedLine->line.Styles = styles;
356 importedLine->line.Colors = colors;
358 AddLine(&importedLines, importedLine);
360 else
362 FreeVecPooled(data->mypool, importedLine);
363 importedLine = NULL;
368 // the clipboard server used AllocVec() before
369 FreeVec(line->line.Contents);
370 line->line.Contents = NULL;
373 FreeVec(line);
374 line = NULL;
376 else
378 // we either encountered an error or we just finished importing the complete clip
379 break;
382 while(error == 0 || error != IFFERR_EOF);
384 ClientEndSession(clipSession);
385 //error = 42;
387 SHOWVALUE(DBF_CLIPBOARD, error);
388 SHOWVALUE(DBF_CLIPBOARD, IFFERR_EOF);
389 SHOWVALUE(DBF_CLIPBOARD, ContainsLines(&importedLines));
390 if(error == IFFERR_EOF && ContainsLines(&importedLines) == TRUE)
392 BOOL oneline = FALSE;
393 struct line_node *lastLine;
394 LONG updatefrom;
396 // sum up the visual heights of all imported lines
397 data->totallines += CountLines(data, &importedLines);
398 SplitLine(data, x, actline, FALSE, NULL);
399 // get the last imported line, this is needed for further actions
400 lastLine = GetLastLine(&importedLines);
401 InsertLines(&importedLines, actline);
402 data->CPos_X = lastLine->line.Length-1;
403 if(GetNextLine(actline) == lastLine)
405 data->CPos_X += actline->line.Length-1;
406 oneline = TRUE;
408 if(newline == FALSE)
410 D(DBF_CLIPBOARD, "merging line");
411 MergeLines(data, lastLine);
413 D(DBF_CLIPBOARD, "merging actline");
414 MergeLines(data, actline);
416 if(oneline == TRUE)
417 lastLine = actline;
418 if(newline == TRUE)
420 lastLine = GetNextLine(lastLine);
421 data->CPos_X = 0;
423 data->actualline = lastLine;
425 data->update = TRUE;
427 ScrollIntoDisplay(data);
428 updatefrom = LineToVisual(data, actline)-1;
429 if(updatefrom < 0)
430 updatefrom = 0;
431 DumpText(data, data->visual_y+updatefrom, updatefrom, data->maxlines, TRUE);
433 if(data->update == TRUE)
434 res = TRUE;
435 else
436 data->update = TRUE;
438 else
440 // in case of an error we free all imported lines so far
441 FreeTextMem(data, &importedLines);
443 switch(error)
445 case IFFERR_MANGLED:
446 case IFFERR_SYNTAX:
447 case IFFERR_NOTIFF:
448 D(DBF_CLIPBOARD, "no FTXT clip!");
449 DoMethod(data->object, MUIM_TextEditor_HandleError, Error_ClipboardIsNotFTXT);
450 break;
452 default:
453 D(DBF_CLIPBOARD, "clipboard is empty!");
454 DoMethod(data->object, MUIM_TextEditor_HandleError, Error_ClipboardIsEmpty);
455 break;
460 RETURN(res);
461 return res;
465 /// MergeLines()
466 /*--------------------------*
467 * Merge two lines into one *
468 *--------------------------*/
469 BOOL MergeLines(struct InstData *data, struct line_node *line)
471 BOOL result = FALSE;
472 struct line_node *next;
473 char *newbuffer;
474 ULONG newbufferSize;
475 LONG visual, oldvisual, line_nr;
476 BOOL emptyline = FALSE;
477 BOOL highlight = line->line.Highlight;
478 UWORD flow = line->line.Flow;
479 UWORD separator = line->line.Separator;
481 ENTER();
483 D(DBF_DUMP, "before merge");
484 DumpLine(line);
486 next = GetNextLine(line);
488 data->HasChanged = TRUE;
489 if(line->line.Length == 1)
491 emptyline = TRUE;
492 highlight = next->line.Highlight;
493 flow = next->line.Flow;
494 separator = next->line.Separator;
496 visual = line->visual + next->visual;
498 newbufferSize = line->line.Length+next->line.Length+1;
499 if((newbuffer = AllocVecPooled(data->mypool, newbufferSize)) != NULL)
501 // substract one character, because we don't need the first line's trailing LF anymore
502 strlcpy(newbuffer, line->line.Contents, line->line.Length);
503 // append the second line, including its trailing LF
504 strlcat(newbuffer, next->line.Contents, newbufferSize);
506 FreeVecPooled(data->mypool, line->line.Contents);
507 FreeVecPooled(data->mypool, next->line.Contents);
509 if(emptyline == TRUE)
511 if(line->line.Styles != NULL)
512 FreeVecPooled(data->mypool, line->line.Styles);
514 line->line.Styles = next->line.Styles;
516 if(line->line.Colors != NULL)
517 FreeVecPooled(data->mypool, line->line.Colors);
519 line->line.Colors = next->line.Colors;
521 else
523 struct LineStyle *line1Styles;
524 struct LineStyle *line2Styles = next->line.Styles;
525 struct LineColor *line1Colors;
526 struct LineColor *line2Colors = next->line.Colors;
527 struct Grow styleGrow;
528 struct Grow colorGrow;
529 UWORD style = 0;
530 UWORD end_color = 0;
532 InitGrow(&styleGrow, data->mypool, sizeof(struct LineStyle));
533 InitGrow(&colorGrow, data->mypool, sizeof(struct LineColor));
535 if((line2Styles = next->line.Styles) != NULL)
537 struct LineStyle *t_line2Styles = line2Styles;
539 // collect all styles which start at the beginning of the line to be appended
540 while(t_line2Styles->column == 1)
542 D(DBF_STYLE, "collecting style 0x%04lx", t_line2Styles->style);
543 if(t_line2Styles->style > 0xff)
544 style &= t_line2Styles->style;
545 else
546 style |= t_line2Styles->style;
548 t_line2Styles++;
552 if((line1Styles = line->line.Styles) != NULL)
554 while(line1Styles->column != EOS)
556 if(line1Styles->column == line->line.Length && ((~line1Styles->style & style) == (line1Styles->style ^ 0xffff)))
558 D(DBF_STYLE, "ignoring style 0x%04lx at column %ld (1)", line1Styles->style, line1Styles->column);
559 style &= line1Styles->style;
560 line1Styles++;
562 else
564 D(DBF_STYLE, "prepending style 0x%04lx at column %ld", line1Styles->style, line1Styles->column);
565 AddToGrow(&styleGrow, line1Styles);
566 line1Styles++;
570 FreeVecPooled(data->mypool, line->line.Styles);
573 if((line2Styles = next->line.Styles) != NULL)
575 while(line2Styles->column != EOS)
577 if(line2Styles->column == 1 && (line2Styles->style & style) == 0)
579 D(DBF_STYLE, "ignoring style 0x%04lx at column %ld (2)", line2Styles->style, line2Styles->column);
580 line2Styles++;
582 else
584 struct LineStyle newStyle;
586 D(DBF_STYLE, "appending style 0x%04lx at column %ld from column %ld", line2Styles->style, line2Styles->column + line->line.Length - 1, line2Styles->column);
587 newStyle.column = line2Styles->column + line->line.Length - 1;
588 newStyle.style = line2Styles->style;
589 AddToGrow(&styleGrow, &newStyle);
591 line2Styles++;
595 FreeVecPooled(data->mypool, next->line.Styles);
598 if(styleGrow.itemCount > 0)
600 struct LineStyle terminator;
602 terminator.column = EOS;
603 terminator.style = 0;
604 AddToGrow(&styleGrow, &terminator);
607 line->line.Styles = (struct LineStyle *)styleGrow.array;
609 if((line1Colors = line->line.Colors) != NULL)
611 while(line1Colors->column != EOC && line1Colors->column < line->line.Length)
613 D(DBF_STYLE, "applying color change from %ld to %ld in column %ld (1)", end_color, line1Colors->color, line1Colors->column);
614 end_color = line1Colors->color;
615 AddToGrow(&colorGrow, line1Colors);
616 line1Colors++;
619 FreeVecPooled(data->mypool, line->line.Colors);
622 if(end_color != 0 && (line2Colors == NULL || (line2Colors->column != 1 && line2Colors->column != EOC)))
624 struct LineColor newColor;
626 D(DBF_STYLE, "resetting color in column %ld (1)", line->line.Length - 1);
627 end_color = 0;
628 newColor.column = line->line.Length;
629 newColor.color = 0;
630 AddToGrow(&colorGrow, &newColor);
633 if((line2Colors = next->line.Colors) != NULL)
635 if(line2Colors->column == 1 && line2Colors->color == end_color)
637 D(DBF_STYLE, "skipping 1st color change of 2nd line");
638 line2Colors++;
641 while(line2Colors->column != EOC)
643 struct LineColor newColor;
645 D(DBF_STYLE, "applying color change from %ld to %ld in column %ld (2)", end_color, line2Colors->color, line2Colors->column + line->line.Length - 1);
646 newColor.column = line2Colors->column + line->line.Length-1;
647 newColor.color = line2Colors->color;
648 AddToGrow(&colorGrow, &newColor);
650 end_color = line2Colors->color;
651 line2Colors++;
654 FreeVecPooled(data->mypool, next->line.Colors);
656 if(end_color != 0)
658 struct LineColor newColor;
660 D(DBF_STYLE, "resetting color in column %ld (2)", newbufferSize - next->line.Length - 1);
661 newColor.column = newbufferSize - next->line.Length - 1;
662 newColor.color = 0;
663 AddToGrow(&colorGrow, &newColor);
665 end_color = 0;
669 if(colorGrow.itemCount > 0)
671 struct LineColor terminator;
673 terminator.column = EOC;
674 terminator.color = 0;
675 AddToGrow(&colorGrow, &terminator);
678 line->line.Colors = (struct LineColor *)colorGrow.array;
681 line->line.Contents = newbuffer;
682 line->line.Length = strlen(newbuffer);
683 line->line.allocatedContents = newbufferSize;
685 // check for possible references first
686 CheckBlock(data, next);
687 // now remove and free the line
688 RemLine(next);
689 FreeVecPooled(data->mypool, next);
691 oldvisual = line->visual;
692 line->visual = VisualHeight(data, line);
693 line->line.Highlight = highlight;
694 line->line.Flow = flow;
695 line->line.Separator = separator;
697 D(DBF_DUMP, "after merge");
698 DumpLine(line);
700 line_nr = LineToVisual(data, line);
702 // handle that we have to scroll up/down due to word wrapping
703 // that occurrs when merging lines
704 if(visual > line->visual)
706 data->totallines -= 1;
707 if(line_nr+line->visual-1 < data->maxlines)
709 if(emptyline == TRUE && line_nr > 0)
710 DumpText(data, data->visual_y+line_nr-1, line_nr-1, data->maxlines, TRUE);
711 else
712 DumpText(data, data->visual_y+line_nr+line->visual-1, line_nr+line->visual-1, data->maxlines, TRUE);
715 else if(visual < line->visual)
717 data->totallines += 1;
718 if(line_nr+line->visual-1 < data->maxlines)
719 ScrollUpDown(data);
722 if(emptyline == FALSE || line_nr + line->visual - 1 >= data->maxlines)
724 LONG t_oldvisual = oldvisual;
725 LONG t_line_nr = line_nr;
726 LONG c = 0;
728 while((--t_oldvisual) && t_line_nr <= data->maxlines)
730 c += LineCharsWidth(data, &line->line.Contents[c]);
731 t_line_nr++;
734 while(c < line->line.Length && t_line_nr <= data->maxlines)
736 c += PrintLine(data, c, line, t_line_nr, TRUE);
737 t_line_nr++;
741 if(line_nr + oldvisual == 1 && line->visual == visual-1)
743 data->visual_y--;
744 data->totallines -= 1;
746 DumpText(data, data->visual_y, 0, data->maxlines, TRUE);
749 result = TRUE;
752 RETURN(result);
753 return result;
757 /// SplitLine()
758 /*---------------------*
759 * Split line into two *
760 *---------------------*/
761 BOOL SplitLine(struct InstData *data, LONG x, struct line_node *line, BOOL move_crsr, struct UserAction *buffer)
763 BOOL result = FALSE;
764 struct line_node *newline;
765 struct pos_info pos;
766 LONG line_nr, lines;
767 LONG c;
768 LONG crsr_x = data->CPos_X;
769 struct line_node *crsr_l = data->actualline;
771 ENTER();
773 D(DBF_DUMP, "before split, x=%ld",x);
774 DumpLine(line);
776 OffsetToLines(data, x, line, &pos);
777 lines = pos.lines;
779 if((newline = AllocVecPooled(data->mypool, sizeof(struct line_node))) != NULL)
781 struct LineStyle *styles = line->line.Styles;
782 struct LineColor *colors = line->line.Colors;
783 struct Grow newStyleGrow;
784 struct Grow newColorGrow;
786 data->HasChanged = TRUE;
787 Init_LineNode(data, newline, &line->line.Contents[x]);
788 newline->line.Highlight = line->line.Highlight;
789 newline->line.Flow = line->line.Flow;
790 newline->line.Separator = line->line.Separator;
791 if(buffer != NULL)
793 newline->line.Highlight = buffer->del.highlight;
794 newline->line.Flow = buffer->del.flow;
795 newline->line.Separator = buffer->del.separator;
798 InitGrow(&newStyleGrow, data->mypool, sizeof(struct LineStyle));
799 InitGrow(&newColorGrow, data->mypool, sizeof(struct LineColor));
801 if(styles != NULL)
803 struct Grow oldStyleGrow;
804 UWORD style = 0;
806 InitGrow(&oldStyleGrow, data->mypool, sizeof(struct LineStyle));
808 // collect the applied styles up to the given position
809 while(styles->column <= x+1)
811 D(DBF_STYLE, "collecting style 0x%04lx at column %ld", styles->style, styles->column);
812 if(styles->style > 0xff)
813 style &= styles->style;
814 else
815 style |= styles->style;
816 SHOWVALUE(DBF_STYLE, style);
818 AddToGrow(&oldStyleGrow, styles);
820 styles++;
823 if(isFlagSet(style, BOLD))
825 struct LineStyle newStyle;
827 D(DBF_STYLE, "adding new bold style");
828 newStyle.column = 1;
829 newStyle.style = BOLD;
830 AddToGrow(&newStyleGrow, &newStyle);
832 if(isFlagSet(style, ITALIC))
834 struct LineStyle newStyle;
836 D(DBF_STYLE, "adding new italic style");
837 newStyle.column = 1;
838 newStyle.style = ITALIC;
839 AddToGrow(&newStyleGrow, &newStyle);
841 if(isFlagSet(style, UNDERLINE))
843 struct LineStyle newStyle;
845 D(DBF_STYLE, "adding new underline style");
846 newStyle.column = 1;
847 newStyle.style = UNDERLINE;
848 AddToGrow(&newStyleGrow, &newStyle);
851 // add the remaining style changes to the new line
852 while(styles->column != EOS)
854 struct LineStyle newStyle;
856 D(DBF_STYLE, "copying style 0x%04lx from column %ld to column %ld", styles->style, styles->column, styles->column-x);
857 newStyle.column = styles->column - x;
858 newStyle.style = styles->style;
859 AddToGrow(&newStyleGrow, &newStyle);
861 styles++;
864 if(newStyleGrow.itemCount > 0)
866 struct LineStyle terminator;
868 terminator.column = EOS;
869 terminator.style = 0;
870 AddToGrow(&newStyleGrow, &terminator);
873 // if there was any style active at the end of the old line we remove that style here
874 if(isFlagSet(style, BOLD))
876 struct LineStyle newStyle;
878 D(DBF_STYLE, "removing old bold style at column %ld", x+1);
879 newStyle.column = x+1;
880 newStyle.style = ~BOLD;
881 AddToGrow(&oldStyleGrow, &newStyle);
883 if(isFlagSet(style, ITALIC))
885 struct LineStyle newStyle;
887 D(DBF_STYLE, "removing old italic style at column %ld", x+1);
888 newStyle.column = x+1;
889 newStyle.style = ~ITALIC;
890 AddToGrow(&oldStyleGrow, &newStyle);
892 if(isFlagSet(style, UNDERLINE))
894 struct LineStyle newStyle;
896 D(DBF_STYLE, "removing old underline style at column %ld", x+1);
897 newStyle.column = x+1;
898 newStyle.style = ~UNDERLINE;
899 AddToGrow(&oldStyleGrow, &newStyle);
902 if(newStyleGrow.itemCount > 0)
904 struct LineStyle terminator;
906 terminator.column = EOS;
907 terminator.style = 0;
908 AddToGrow(&newStyleGrow, &terminator);
911 if(x == 0)
912 FreeGrow(&oldStyleGrow);
914 if(oldStyleGrow.itemCount > 0)
916 struct LineStyle terminator;
918 terminator.column = EOS;
919 terminator.style = 0;
920 AddToGrow(&oldStyleGrow, &terminator);
923 FreeVecPooled(data->mypool, line->line.Styles);
924 line->line.Styles = (struct LineStyle *)oldStyleGrow.array;
927 newline->line.Styles = (struct LineStyle *)newStyleGrow.array;
929 if(colors != NULL)
931 struct Grow oldColorGrow;
932 UWORD color = GetColor(x, line);
934 InitGrow(&oldColorGrow, data->mypool, sizeof(struct LineColor));
936 // ignore all color changes up to the given position
937 while(colors->column <= x+1)
939 D(DBF_STYLE, "collecting color %ld at column %ld", colors->color, colors->column);
940 AddToGrow(&oldColorGrow, colors);
942 colors++;
945 if(color != 0 && colors->column-x != 1)
947 struct LineColor newColor;
949 D(DBF_STYLE, "adding new color %ld", color);
950 newColor.column = 1;
951 newColor.color = color;
952 AddToGrow(&newColorGrow, &newColor);
955 // add the remaining color changes to the new line
956 while(colors->column != EOC)
958 struct LineColor newColor;
960 D(DBF_STYLE, "copying color %ld from column %ld to column %ld", colors->color, colors->column, colors->column-x);
961 newColor.column = colors->column - x;
962 newColor.color = colors->color;
963 AddToGrow(&newColorGrow, &newColor);
965 colors++;
968 if(newColorGrow.itemCount > 0)
970 struct LineColor terminator;
972 terminator.column = EOC;
973 terminator.color = 0;
974 AddToGrow(&newColorGrow, &terminator);
977 if(x == 0)
978 FreeGrow(&oldColorGrow);
980 if(oldColorGrow.itemCount > 0)
982 struct LineColor terminator;
984 terminator.column = EOC;
985 terminator.color = 0;
986 AddToGrow(&oldColorGrow, &terminator);
989 FreeVecPooled(data->mypool, line->line.Colors);
990 line->line.Colors = (struct LineColor *)oldColorGrow.array;
993 newline->line.Colors = (struct LineColor *)newColorGrow.array;
995 InsertLine(newline, line);
997 line->line.Contents[x] = '\n';
998 line->line.Contents[x+1] = '\0';
999 line->line.Length = x+1;
1001 c = line->visual;
1002 line->visual = VisualHeight(data, line);
1003 CompressLine(data, line);
1005 line_nr = LineToVisual(data, line) + line->visual - 1;
1006 if(line_nr < 0)
1007 line_nr = 0;
1009 if(move_crsr == TRUE)
1011 data->CPos_X = 0;
1012 data->actualline = GetNextLine(data->actualline);
1015 if(x == 0)
1017 // split at the beginning of the line
1018 line->line.Highlight = FALSE;
1019 line->line.Separator = LNSF_None;
1020 if(HasPrevLine(line) == FALSE)
1022 line->line.Flow = MUIV_TextEditor_Flow_Left;
1024 else
1026 struct line_node *prev = GetPrevLine(line);
1028 if(prev->line.Flow != line->line.Flow)
1029 line->line.Flow = MUIV_TextEditor_Flow_Left;
1032 if(line_nr != data->maxlines)
1034 data->totallines += 1;
1035 DumpText(data, data->visual_y+line_nr-1, line_nr-1, data->maxlines, TRUE);
1037 else
1039 data->visual_y++;
1040 data->totallines += 1;
1041 if(isFlagClear(data->flags, FLG_Quiet))
1043 struct Hook *oldhook;
1045 oldhook = InstallLayerHook(data->rport->Layer, LAYERS_NOBACKFILL);
1046 ScrollRasterBF(data->rport, 0, data->fontheight,
1047 _mleft(data->object), data->ypos,
1048 _mright(data->object), (data->ypos + ((data->maxlines-1) * data->fontheight)) - 1);
1049 InstallLayerHook(data->rport->Layer, oldhook);
1051 PrintLine(data, 0, line, data->maxlines-1, FALSE);
1052 DumpText(data, data->visual_y+data->maxlines-1, data->maxlines-1, data->maxlines, TRUE);
1056 D(DBF_DUMP, "after split, old line");
1057 DumpLine(line);
1058 D(DBF_DUMP, "after split, new line");
1059 DumpLine(newline);
1061 result = TRUE;
1063 else if(x == (LONG)(line->line.Length + newline->line.Length - 2))
1065 // split at the end of the line
1066 data->totallines += 1;
1067 if(buffer == NULL)
1069 struct line_node *next = GetNextLine(line);
1071 next->line.Highlight = FALSE;
1072 next->line.Separator = LNSF_None;
1074 SetCursor(data, crsr_x, crsr_l, FALSE);
1075 if(line_nr < data->maxlines)
1076 DumpText(data, data->visual_y+line_nr, line_nr, data->maxlines, TRUE);
1078 D(DBF_DUMP, "after split, old line");
1079 DumpLine(line);
1080 D(DBF_DUMP, "after split, new line");
1081 DumpLine(newline);
1083 result = TRUE;
1085 else
1087 struct line_node *next = GetNextLine(line);
1089 // split somewhere in the middle
1090 x = line->line.Length;
1092 OffsetToLines(data, x-1, line, &pos);
1093 if(line->visual + next->visual >= c && line->visual == lines)
1095 if(line->visual + next->visual > c)
1096 data->totallines += 1;
1098 PrintLine(data, pos.bytes, line, line_nr, TRUE);
1100 if(line_nr+next->visual-1 < data->maxlines && line->visual + next->visual > c)
1102 ScrollUpDown(data);
1105 else
1107 PrintLine(data, (x-1)-pos.x, line, line_nr, TRUE);
1109 if(line_nr < data->maxlines && line->visual + next->visual < c)
1111 data->totallines -= 1;
1112 ScrollUpDown(data);
1115 /*------------------*/
1116 line = next;
1117 line_nr++;
1118 c = 0;
1119 while(c < line->line.Length && line_nr <= data->maxlines)
1121 c = c + PrintLine(data, c, line, line_nr, TRUE);
1122 line_nr++;
1124 /* Her printes !HELE! den nye linie, burde optimeres! */
1126 D(DBF_DUMP, "after split, old line");
1127 DumpLine(line);
1128 D(DBF_DUMP, "after split, new line");
1129 DumpLine(newline);
1131 result = TRUE;
1135 RETURN(result);
1136 return result;
1140 /// OptimizedPrint()
1141 /* ------------------------------------ *
1142 * Functions which updates the display *
1143 * ------------------------------------ */
1144 static void OptimizedPrint(struct InstData *data, LONG x, struct line_node *line, LONG line_nr, LONG width)
1146 ENTER();
1150 LONG twidth;
1152 twidth = PrintLine(data, x, line, line_nr, TRUE);
1153 line_nr++;
1155 if(twidth != width && x+twidth < line->line.Length && line_nr <= data->maxlines)
1157 x += twidth;
1158 width += LineCharsWidth(data, &line->line.Contents[x]) - twidth;
1160 else
1161 break;
1163 while(TRUE);
1165 LEAVE();
1169 /// UpdateChange()
1170 static void UpdateChange(struct InstData *data, LONG x, struct line_node *line, LONG length, const char *characters, struct UserAction *buffer)
1172 LONG diff;
1173 LONG skip=0;
1174 LONG line_nr;
1175 LONG orgline_nr;
1176 LONG width=0;
1177 LONG lineabove_width=0;
1179 ENTER();
1181 line_nr = LineToVisual(data, line);
1182 orgline_nr = line_nr;
1186 width = LineCharsWidth(data, &line->line.Contents[skip]);
1188 // don't exceed the line length!
1189 if(width <= 0 || skip + width >= x || skip + width >= (LONG)line->line.Length)
1190 break;
1192 lineabove_width = width;
1193 skip += width;
1194 line_nr++;
1196 while(TRUE);
1198 if(characters != NULL)
1200 // make some room for the additional characters
1201 memmove(&line->line.Contents[x+length], &line->line.Contents[x], line->line.Length-x+1);
1202 // insert them
1203 memcpy(&line->line.Contents[x], characters, length);
1204 // adjust the length information
1205 width += length;
1206 line->line.Length += length;
1207 // correct the styles
1208 if(buffer != NULL)
1210 UWORD style = buffer->del.style;
1212 AddStyleToLine(data, x, line, 1, isFlagSet(style, BOLD) ? BOLD : ~BOLD);
1213 AddStyleToLine(data, x, line, 1, isFlagSet(style, ITALIC) ? ITALIC : ~ITALIC);
1214 AddStyleToLine(data, x, line, 1, isFlagSet(style, UNDERLINE) ? UNDERLINE : ~UNDERLINE);
1215 line->line.Flow = buffer->del.flow;
1216 line->line.Separator = buffer->del.separator;
1217 line->line.Highlight = buffer->del.highlight;
1220 else
1222 // remove the requested amount of characters
1223 memmove(&line->line.Contents[x], &line->line.Contents[x+length], line->line.Length-x+1-length);
1224 // adjust the length information
1225 width -= length;
1226 line->line.Length -= length;
1229 diff = VisualHeight(data, line) - line->visual;
1230 if(diff != 0)
1232 LONG movement;
1234 movement = orgline_nr + line->visual - 1;
1236 line->visual += diff;
1237 data->totallines += diff;
1239 if(diff > 0)
1241 if(movement < data->maxlines)
1242 ScrollUpDown(data);
1244 else
1246 movement = orgline_nr + line->visual - 1;
1247 if(movement <= data->maxlines)
1248 ScrollUpDown(data);
1252 if(orgline_nr != line_nr)
1254 if(skip-lineabove_width >= 0 && skip-lineabove_width < line->line.Length)
1256 if(lineabove_width != LineCharsWidth(data, &line->line.Contents[skip-lineabove_width]))
1258 LONG newwidth;
1260 newwidth = PrintLine(data, skip-lineabove_width, line, line_nr-1, TRUE) - lineabove_width;
1261 skip += newwidth;
1262 width -= newwidth;
1267 if(skip >= 0 && skip < line->line.Length)
1269 OptimizedPrint(data, skip, line, line_nr, width);
1270 ScrollIntoDisplay(data);
1271 data->HasChanged = TRUE;
1274 LEAVE();
1278 /// PasteChars()
1279 /*------------------------------*
1280 * Paste n characters to a line *
1281 *------------------------------*/
1282 BOOL PasteChars(struct InstData *data, LONG x, struct line_node *line, LONG length, const char *characters, struct UserAction *buffer)
1284 BOOL success = TRUE;
1286 ENTER();
1288 // check if we need more space for the contents first
1289 // include 2 extra bytes for LF and NUL
1290 if(line->line.Length + 1 + length + 1 > line->line.allocatedContents)
1292 success = ExpandLine(data, line, length);
1295 // continue only if the possible expansion succeeded
1296 if(success == TRUE)
1298 if(line->line.Styles != NULL)
1300 struct LineStyle *stylePtr = line->line.Styles;
1302 // skip all styles up to the given position
1303 while(stylePtr->column <= x+1)
1304 stylePtr++;
1306 // move all style positions by the given length
1307 while(stylePtr->column != EOS)
1309 stylePtr->column += length;
1310 stylePtr++;
1314 if(line->line.Colors != NULL && line->line.Colors[0].column != EOC)
1316 struct LineColor *colorPtr = line->line.Colors;
1318 // skip all colors up to the given position
1319 while(colorPtr->column <= x+1)
1320 colorPtr++;
1322 // move all color positions by the given length
1323 while(colorPtr->column != EOC)
1325 colorPtr->column += length;
1326 colorPtr++;
1330 UpdateChange(data, x, line, length, characters, buffer);
1333 RETURN(success);
1334 return(success);
1338 /// RemoveChars()
1339 /*----------------------------*
1340 * Remove n chars from a line *
1341 *----------------------------*/
1342 BOOL RemoveChars(struct InstData *data, LONG x, struct line_node *line, LONG length)
1344 ENTER();
1346 D(DBF_DUMP, "before remove %ld %ld", x, length);
1347 DumpLine(line);
1349 // check if there are any style changes at all
1350 if(line->line.Styles != NULL && line->line.Styles[0].column != EOS)
1352 struct Grow styleGrow;
1353 UWORD start_style = GetStyle(x-1, line);
1354 UWORD end_style = GetStyle(x+length, line);
1355 ULONG c = 0;
1357 InitGrow(&styleGrow, data->mypool, sizeof(struct LineStyle));
1359 // skip all styles before the the starting column
1360 while(line->line.Styles[c].column <= x)
1362 AddToGrow(&styleGrow, &line->line.Styles[c]);
1363 c++;
1366 // if the style differs between the start and the end of the range
1367 // then we must add style changes accordingly
1368 D(DBF_DUMP, "start style %04lx, end style %04lx", start_style, end_style);
1369 if(start_style != end_style)
1371 UWORD turn_off = start_style & ~end_style;
1372 UWORD turn_on = end_style & ~start_style;
1374 if(isFlagSet(turn_off, BOLD))
1376 struct LineStyle newStyle;
1378 newStyle.column = x+1;
1379 newStyle.style = ~BOLD;
1380 AddToGrow(&styleGrow, &newStyle);
1382 c++;
1384 if(isFlagSet(turn_off, ITALIC))
1386 struct LineStyle newStyle;
1388 newStyle.column = x+1;
1389 newStyle.style = ~ITALIC;
1390 AddToGrow(&styleGrow, &newStyle);
1392 c++;
1394 if(isFlagSet(turn_off, UNDERLINE))
1396 struct LineStyle newStyle;
1398 newStyle.column = x+1;
1399 newStyle.style = ~UNDERLINE;
1400 AddToGrow(&styleGrow, &newStyle);
1402 c++;
1404 if(isFlagSet(turn_on, BOLD))
1406 struct LineStyle newStyle;
1408 newStyle.column = x+1;
1409 newStyle.style = BOLD;
1410 AddToGrow(&styleGrow, &newStyle);
1412 c++;
1414 if(isFlagSet(turn_on, ITALIC))
1416 struct LineStyle newStyle;
1418 newStyle.column = x+1;
1419 newStyle.style = ITALIC;
1420 AddToGrow(&styleGrow, &newStyle);
1422 c++;
1424 if(isFlagSet(turn_on, UNDERLINE))
1426 struct LineStyle newStyle;
1428 newStyle.column = x+1;
1429 newStyle.style = UNDERLINE;
1430 AddToGrow(&styleGrow, &newStyle);
1432 c++;
1436 // skip all style changes until we reach the end of the range
1437 while(line->line.Styles[c].column <= x+length+1)
1438 c++;
1440 // move all remaining style changes towards the beginning
1441 while(line->line.Styles[c].column != EOS)
1443 struct LineStyle newStyle;
1445 newStyle.column = line->line.Styles[c].column-length;
1446 newStyle.style = line->line.Styles[c].style;
1447 AddToGrow(&styleGrow, &newStyle);
1449 c++;
1452 // put a new style termination
1453 if(styleGrow.itemCount > 0)
1455 struct LineStyle terminator;
1457 terminator.column = EOS;
1458 terminator.style = 0;
1459 AddToGrow(&styleGrow, &terminator);
1462 // free the old styles and remember the newly created styles (maybe NULL)
1463 FreeVecPooled(data->mypool, line->line.Styles);
1464 line->line.Styles = (struct LineStyle *)styleGrow.array;
1467 // check if there are any color changes at all
1468 if(line->line.Colors != NULL && line->line.Colors[0].column != EOC)
1470 struct Grow colorGrow;
1471 UWORD start_color = GetColor(x-1, line);
1472 UWORD end_color = GetColor(x+length, line);
1473 ULONG c = 0;
1475 InitGrow(&colorGrow, data->mypool, sizeof(struct LineColor));
1477 // skip all colors before the the starting column
1478 while(line->line.Colors[c].column <= x)
1480 AddToGrow(&colorGrow, &line->line.Colors[c]);
1481 c++;
1484 // if the colors differs between the start and the end of the range
1485 // then we must add color changes accordingly
1486 if(start_color != end_color)
1488 struct LineColor newColor;
1490 newColor.column = x+1;
1491 newColor.color = end_color;
1492 AddToGrow(&colorGrow, &newColor);
1493 c++;
1496 // skip all color changes until we reach the end of the range
1497 while(line->line.Colors[c].column <= x+length+1)
1498 c++;
1500 // move all remaining color changes towards the beginning
1501 while(line->line.Colors[c].column != EOC)
1503 struct LineColor newColor;
1505 newColor.column = line->line.Colors[c].column-length;
1506 newColor.color = line->line.Colors[c].color;
1507 AddToGrow(&colorGrow, &newColor);
1509 c++;
1512 // put a new color termination
1513 if(colorGrow.itemCount > 0)
1515 struct LineColor terminator;
1517 terminator.column = EOC;
1518 terminator.color = 0;
1519 AddToGrow(&colorGrow, &terminator);
1522 // free the old styles and remember the newly created colors (maybe NULL)
1523 FreeVecPooled(data->mypool, line->line.Colors);
1524 line->line.Colors = (struct LineColor *)colorGrow.array;
1527 UpdateChange(data, x, line, length, NULL, NULL);
1529 D(DBF_DUMP, "after remove");
1530 DumpLine(line);
1532 RETURN(TRUE);
1533 return(TRUE);