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
21 ***************************************************************************/
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>
37 #if defined(__MORPHOS__)
38 #include <proto/keymap.h>
39 #include <proto/locale.h>
42 static char *utf8_to_ansi(STRPTR src
)
44 static struct KeyMap
*keymap
;
47 ULONG octets
, strlength
;
51 keymap
= AskKeyMapDefault();
61 ptr
+= (octets
= UTF8_Decode(ptr
, &wc
));
62 c
= ToANSI(wc
, keymap
);
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
);
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
);
99 ptr
+= (octets
= UTF8_Decode(ptr
, &wc
));
100 c
= ToANSI(wc
, keymap
);
104 if (c
== '?' && wc
!= '?')
106 CONST_WSTRPTR p
= UCS4_Decompose(wc
);
114 *bufptr
++ = ToANSI(*p
, keymap
);
122 // free original buffer
138 void DumpLine(struct line_node
*line
)
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
;
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
);
156 D(DBF_DUMP
, "%ld style changes", numStyles
);
159 if(line
->line
.Colors
!= NULL
)
161 struct LineColor
*colors
= line
->line
.Colors
;
164 D(DBF_DUMP
, "colors:");
165 while(colors
->column
!= EOC
)
167 D(DBF_DUMP
, "color %3ld starting at column %3ld", colors
->color
, colors
->column
);
171 D(DBF_DUMP
, "%ld color changes", numColors
);
174 if(line
->line
.Highlight
== TRUE
)
175 D(DBF_DUMP
, "line is highlighted");
180 #define DumpLine(line) ((void)0)
185 /*----------------------*
186 * Paste from Clipboard *
187 *----------------------*/
188 BOOL
PasteClip(struct InstData
*data
, LONG x
, struct line_node
*actline
)
195 if((clipSession
= ClientStartSession(IFFF_READ
)) != (IPTR
)NULL
)
199 struct MinList importedLines
;
201 InitLines(&importedLines
);
205 struct line_node
*line
= NULL
;
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
);
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
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
);
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
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
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
;
297 struct MinList importedBlock
;
299 // this is a foreign clip
300 D(DBF_CLIPBOARD
, "importing foreign clip");
302 if(contents
[length
-1] != '\n')
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
;
318 SHOWSTRING(DBF_CLIPBOARD
, contents
);
320 if(ImportText(data
, contents
, &ImPlainHook
, data
->ImportWrap
, &importedBlock
) == TRUE
)
322 // append the imported lines
323 MoveLines(&importedLines
, &importedBlock
);
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')
336 contents
[length
] = '\n';
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
);
362 FreeVecPooled(data
->mypool
, importedLine
);
368 // the clipboard server used AllocVec() before
369 FreeVec(line
->line
.Contents
);
370 line
->line
.Contents
= NULL
;
378 // we either encountered an error or we just finished importing the complete clip
382 while(error
== 0 || error
!= IFFERR_EOF
);
384 ClientEndSession(clipSession
);
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
;
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;
410 D(DBF_CLIPBOARD
, "merging line");
411 MergeLines(data
, lastLine
);
413 D(DBF_CLIPBOARD
, "merging actline");
414 MergeLines(data
, actline
);
420 lastLine
= GetNextLine(lastLine
);
423 data
->actualline
= lastLine
;
427 ScrollIntoDisplay(data
);
428 updatefrom
= LineToVisual(data
, actline
)-1;
431 DumpText(data
, data
->visual_y
+updatefrom
, updatefrom
, data
->maxlines
, TRUE
);
433 if(data
->update
== TRUE
)
440 // in case of an error we free all imported lines so far
441 FreeTextMem(data
, &importedLines
);
448 D(DBF_CLIPBOARD
, "no FTXT clip!");
449 DoMethod(data
->object
, MUIM_TextEditor_HandleError
, Error_ClipboardIsNotFTXT
);
453 D(DBF_CLIPBOARD
, "clipboard is empty!");
454 DoMethod(data
->object
, MUIM_TextEditor_HandleError
, Error_ClipboardIsEmpty
);
466 /*--------------------------*
467 * Merge two lines into one *
468 *--------------------------*/
469 BOOL
MergeLines(struct InstData
*data
, struct line_node
*line
)
472 struct line_node
*next
;
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
;
483 D(DBF_DUMP
, "before merge");
486 next
= GetNextLine(line
);
488 data
->HasChanged
= TRUE
;
489 if(line
->line
.Length
== 1)
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
;
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
;
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
;
546 style
|= t_line2Styles
->style
;
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
;
564 D(DBF_STYLE
, "prepending style 0x%04lx at column %ld", line1Styles
->style
, line1Styles
->column
);
565 AddToGrow(&styleGrow
, 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
);
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
);
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
);
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);
628 newColor
.column
= line
->line
.Length
;
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");
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
;
654 FreeVecPooled(data
->mypool
, next
->line
.Colors
);
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;
663 AddToGrow(&colorGrow
, &newColor
);
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
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");
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
);
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
)
722 if(emptyline
== FALSE
|| line_nr
+ line
->visual
- 1 >= data
->maxlines
)
724 LONG t_oldvisual
= oldvisual
;
725 LONG t_line_nr
= line_nr
;
728 while((--t_oldvisual
) && t_line_nr
<= data
->maxlines
)
730 c
+= LineCharsWidth(data
, &line
->line
.Contents
[c
]);
734 while(c
< line
->line
.Length
&& t_line_nr
<= data
->maxlines
)
736 c
+= PrintLine(data
, c
, line
, t_line_nr
, TRUE
);
741 if(line_nr
+ oldvisual
== 1 && line
->visual
== visual
-1)
744 data
->totallines
-= 1;
746 DumpText(data
, data
->visual_y
, 0, data
->maxlines
, TRUE
);
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
)
764 struct line_node
*newline
;
768 LONG crsr_x
= data
->CPos_X
;
769 struct line_node
*crsr_l
= data
->actualline
;
773 D(DBF_DUMP
, "before split, x=%ld",x
);
776 OffsetToLines(data
, x
, line
, &pos
);
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
;
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
));
803 struct Grow oldStyleGrow
;
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
;
815 style
|= styles
->style
;
816 SHOWVALUE(DBF_STYLE
, style
);
818 AddToGrow(&oldStyleGrow
, styles
);
823 if(isFlagSet(style
, BOLD
))
825 struct LineStyle newStyle
;
827 D(DBF_STYLE
, "adding new bold style");
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");
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");
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
);
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
);
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
;
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
);
945 if(color
!= 0 && colors
->column
-x
!= 1)
947 struct LineColor newColor
;
949 D(DBF_STYLE
, "adding new color %ld", color
);
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
);
968 if(newColorGrow
.itemCount
> 0)
970 struct LineColor terminator
;
972 terminator
.column
= EOC
;
973 terminator
.color
= 0;
974 AddToGrow(&newColorGrow
, &terminator
);
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;
1002 line
->visual
= VisualHeight(data
, line
);
1003 CompressLine(data
, line
);
1005 line_nr
= LineToVisual(data
, line
) + line
->visual
- 1;
1009 if(move_crsr
== TRUE
)
1012 data
->actualline
= GetNextLine(data
->actualline
);
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
;
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
);
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");
1058 D(DBF_DUMP
, "after split, new line");
1063 else if(x
== (LONG
)(line
->line
.Length
+ newline
->line
.Length
- 2))
1065 // split at the end of the line
1066 data
->totallines
+= 1;
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");
1080 D(DBF_DUMP
, "after split, new line");
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
)
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;
1115 /*------------------*/
1119 while(c
< line
->line
.Length
&& line_nr
<= data
->maxlines
)
1121 c
= c
+ PrintLine(data
, c
, line
, line_nr
, TRUE
);
1124 /* Her printes !HELE! den nye linie, burde optimeres! */
1126 D(DBF_DUMP
, "after split, old line");
1128 D(DBF_DUMP
, "after split, new line");
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
)
1152 twidth
= PrintLine(data
, x
, line
, line_nr
, TRUE
);
1155 if(twidth
!= width
&& x
+twidth
< line
->line
.Length
&& line_nr
<= data
->maxlines
)
1158 width
+= LineCharsWidth(data
, &line
->line
.Contents
[x
]) - twidth
;
1170 static void UpdateChange(struct InstData
*data
, LONG x
, struct line_node
*line
, LONG length
, const char *characters
, struct UserAction
*buffer
)
1177 LONG lineabove_width
=0;
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
)
1192 lineabove_width
= width
;
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);
1203 memcpy(&line
->line
.Contents
[x
], characters
, length
);
1204 // adjust the length information
1206 line
->line
.Length
+= length
;
1207 // correct the styles
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
;
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
1226 line
->line
.Length
-= length
;
1229 diff
= VisualHeight(data
, line
) - line
->visual
;
1234 movement
= orgline_nr
+ line
->visual
- 1;
1236 line
->visual
+= diff
;
1237 data
->totallines
+= diff
;
1241 if(movement
< data
->maxlines
)
1246 movement
= orgline_nr
+ line
->visual
- 1;
1247 if(movement
<= data
->maxlines
)
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
]))
1260 newwidth
= PrintLine(data
, skip
-lineabove_width
, line
, line_nr
-1, TRUE
) - lineabove_width
;
1267 if(skip
>= 0 && skip
< line
->line
.Length
)
1269 OptimizedPrint(data
, skip
, line
, line_nr
, width
);
1270 ScrollIntoDisplay(data
);
1271 data
->HasChanged
= TRUE
;
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
;
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
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)
1306 // move all style positions by the given length
1307 while(stylePtr
->column
!= EOS
)
1309 stylePtr
->column
+= length
;
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)
1322 // move all color positions by the given length
1323 while(colorPtr
->column
!= EOC
)
1325 colorPtr
->column
+= length
;
1330 UpdateChange(data
, x
, line
, length
, characters
, buffer
);
1339 /*----------------------------*
1340 * Remove n chars from a line *
1341 *----------------------------*/
1342 BOOL
RemoveChars(struct InstData
*data
, LONG x
, struct line_node
*line
, LONG length
)
1346 D(DBF_DUMP
, "before remove %ld %ld", x
, length
);
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
);
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
]);
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
);
1384 if(isFlagSet(turn_off
, ITALIC
))
1386 struct LineStyle newStyle
;
1388 newStyle
.column
= x
+1;
1389 newStyle
.style
= ~ITALIC
;
1390 AddToGrow(&styleGrow
, &newStyle
);
1394 if(isFlagSet(turn_off
, UNDERLINE
))
1396 struct LineStyle newStyle
;
1398 newStyle
.column
= x
+1;
1399 newStyle
.style
= ~UNDERLINE
;
1400 AddToGrow(&styleGrow
, &newStyle
);
1404 if(isFlagSet(turn_on
, BOLD
))
1406 struct LineStyle newStyle
;
1408 newStyle
.column
= x
+1;
1409 newStyle
.style
= BOLD
;
1410 AddToGrow(&styleGrow
, &newStyle
);
1414 if(isFlagSet(turn_on
, ITALIC
))
1416 struct LineStyle newStyle
;
1418 newStyle
.column
= x
+1;
1419 newStyle
.style
= ITALIC
;
1420 AddToGrow(&styleGrow
, &newStyle
);
1424 if(isFlagSet(turn_on
, UNDERLINE
))
1426 struct LineStyle newStyle
;
1428 newStyle
.column
= x
+1;
1429 newStyle
.style
= UNDERLINE
;
1430 AddToGrow(&styleGrow
, &newStyle
);
1436 // skip all style changes until we reach the end of the range
1437 while(line
->line
.Styles
[c
].column
<= x
+length
+1)
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
);
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
);
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
]);
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
);
1496 // skip all color changes until we reach the end of the range
1497 while(line
->line
.Colors
[c
].column
<= x
+length
+1)
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
);
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");