grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / classes / zune / texteditor / mcc / MixedFunctions.c
blobb00d0a8aa846448f136503ffd6a7281a0d1216cf
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 <graphics/gfxmacros.h>
26 #include <graphics/text.h>
27 #include <libraries/mui.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 <proto/muimaster.h>
36 /*************************************************************************/
38 #include "private.h"
39 #include "Debug.h"
41 /// AddClipping()
42 void AddClipping(struct InstData *data)
44 ENTER();
46 if(data->clipcount == 0)
48 data->cliphandle = MUI_AddClipping(muiRenderInfo(data->object), _mleft(data->object), _mtop(data->object), _mwidth(data->object), _mheight(data->object));
50 data->clipcount++;
52 LEAVE();
55 ///
56 /// RemoveClipping()
57 void RemoveClipping(struct InstData *data)
59 ENTER();
61 data->clipcount--;
62 if(data->clipcount == 0)
64 MUI_RemoveClipping(muiRenderInfo(data->object), data->cliphandle);
67 LEAVE();
70 ///
71 /// FreeTextMem
72 void FreeTextMem(struct InstData *data, struct MinList *lines)
74 struct line_node *line;
76 ENTER();
78 while((line = RemFirstLine(lines)) != NULL)
80 FreeVecPooled(data->mypool, line->line.Contents);
81 if(line->line.Styles != NULL)
82 FreeVecPooled(data->mypool, line->line.Styles);
83 if(line->line.Colors != NULL)
84 FreeVecPooled(data->mypool, line->line.Colors);
86 FreeVecPooled(data->mypool, line);
89 InitLines(lines);
91 LEAVE();
94 ///
95 /// Init_LineNode()
96 /*-----------------------------------*
97 * Initializes a line_node structure *
98 *-----------------------------------*/
99 BOOL Init_LineNode(struct InstData *data, struct line_node *line, CONST_STRPTR text)
101 BOOL success = FALSE;
102 LONG textlength;
103 const char *p;
104 char *ctext;
106 ENTER();
108 textlength = 0;
109 p = text;
110 while(*p != '\n' && *p != '\0')
112 p++;
113 textlength++;
115 // count one byte more for the trailing LF byte
116 textlength++;
118 // and allocate yet another additional byte for the trailing NUL byte
119 if((ctext = AllocVecPooled(data->mypool, textlength+1)) != NULL)
121 strlcpy(ctext, text, textlength+1);
123 line->line.Contents = ctext;
124 line->line.Length = textlength;
125 line->line.allocatedContents = textlength+1;
126 if(data->rport != NULL)
127 line->visual = VisualHeight(data, line);
128 line->line.Highlight = FALSE;
129 line->line.Styles = NULL;
130 line->line.Colors = NULL;
131 line->line.Flow = MUIV_TextEditor_Flow_Left;
132 line->line.Separator = LNSF_None;
134 success = TRUE;
137 RETURN(success);
138 return(success);
142 /// ExpandLine()
143 BOOL ExpandLine(struct InstData *data, struct line_node *line, LONG length)
145 BOOL result = FALSE;
146 char *newbuffer;
147 LONG expandedSize;
149 ENTER();
151 if(line->line.allocatedContents >= 2 && line->line.Length >= line->line.allocatedContents)
153 E(DBF_STYLE, "line length (%ld) > allocated size (%ld)", line->line.Length, line->line.allocatedContents-1);
156 expandedSize = line->line.allocatedContents+40+length;
158 if((newbuffer = AllocVecPooled(data->mypool, expandedSize)) != NULL)
160 strlcpy(newbuffer, line->line.Contents, expandedSize);
161 FreeVecPooled(data->mypool, line->line.Contents);
162 line->line.Contents = newbuffer;
163 line->line.allocatedContents = expandedSize;
164 result = TRUE;
167 RETURN(result);
168 return result;
172 /// CompressLine()
173 BOOL CompressLine(struct InstData *data, struct line_node *line)
175 BOOL result = FALSE;
176 LONG compressedSize;
178 ENTER();
180 compressedSize = strlen(line->line.Contents)+1;
181 if(compressedSize < line->line.allocatedContents)
183 char *newbuffer;
185 if((newbuffer = AllocVecPooled(data->mypool, compressedSize)) != NULL)
187 strlcpy(newbuffer, line->line.Contents, compressedSize);
188 FreeVecPooled(data->mypool, line->line.Contents);
189 line->line.Contents = newbuffer;
190 line->line.Length = strlen(newbuffer);
191 line->line.allocatedContents = compressedSize;
192 result = TRUE;
195 else
197 // no compression necessary
198 result = TRUE;
201 RETURN(result);
202 return result;
206 /// InsertLines
207 void InsertLines(struct MinList *lines, struct line_node *after)
209 struct line_node *line;
211 ENTER();
213 // insert all lines backwards after the given line
214 // this will effectively add all lines in exactly the same order
215 while((line = RemLastLine(lines)) != NULL)
217 InsertLine(line, after);
220 LEAVE();
224 /// LineCharsWidth()
225 /*-----------------------------------------------------*
226 * Returns the number of chars that will fit on a line *
227 *-----------------------------------------------------*/
228 LONG LineCharsWidth(struct InstData *data, CONST_STRPTR text)
230 LONG c;
231 LONG textlen;
232 LONG width = _mwidth(data->object);
234 ENTER();
236 textlen = text != NULL ? strlen(text)-1 : 0; // the last char is always a "\n"
238 // check the innerwidth as well. But we also check if we need to
239 // take care of any of the word wrapping techniques we provide
240 if(width > 0 && textlen > 0 && data->WrapMode != MUIV_TextEditor_WrapMode_NoWrap)
242 struct TextExtent tExtend;
243 ULONG fontheight = data->font ? data->font->tf_YSize : 0;
245 // see how many chars of our text fit to the current innerwidth of the
246 // texteditor
247 c = TextFitNew(&data->tmprp, text, textlen, &tExtend, NULL, 1, width, fontheight, data->TabSizePixels);
248 if(c >= textlen)
250 // if all text fits, then we have to do the calculations once more and
251 // see if also the ending cursor might fit on the line
252 width -= (data->CursorWidth == 6) ? TextLength(&data->tmprp, " ", 1) : data->CursorWidth;
253 c = TextFitNew(&data->tmprp, text, textlen, &tExtend, NULL, 1, width, fontheight, data->TabSizePixels);
256 // if the user selected soft wrapping with a defined wrapborder
257 // we have to check if we take that border or do the soft wrapping
258 // at the innerwidth of the texteditor
259 if(data->WrapBorder > 0 && c > data->WrapBorder && data->WrapMode == MUIV_TextEditor_WrapMode_SoftWrap)
260 c = data->WrapBorder;
262 // now we check whether all chars fit on the current innerwidth
263 // or if we have to do soft word wrapping by searching for the last
264 // occurance of a linear white space character
265 if(c < textlen)
267 if(data->WrapWords)
269 LONG tc = c-1;
271 // search backwards for a linear whitespace (LWSP)
272 while(tc >= 0 && text[tc] != ' ' && text[tc] != '\t')
273 tc--;
275 if(tc >= 0)
276 c = tc+1;
279 else
281 // otherwise always +1 because an ending line should always contain the cursor
282 c++;
285 else
286 c = textlen+1;
288 RETURN(c);
289 return c;
293 /// VisualHeight()
294 /*-------------------------------------------------------*
295 * Return the number of visual lines that the line fills *
296 *-------------------------------------------------------*/
297 ULONG VisualHeight(struct InstData *data, struct line_node *line)
299 ULONG lines = 0;
301 ENTER();
303 if(isFlagSet(data->flags, FLG_HScroll))
304 lines = 1;
305 else
307 ULONG c=0;
308 ULONG length = strlen(line->line.Contents);
310 while(c < length)
312 LONG d = LineCharsWidth(data, &line->line.Contents[c]);
314 if(d > 0)
315 c += d;
316 else
317 break;
319 lines++;
323 RETURN(lines);
324 return(lines);
328 /// OffsetToLines()
329 /*-----------------------------------------*
330 * Convert an xoffset to a number of lines *
331 *-----------------------------------------*/
332 void OffsetToLines(struct InstData *data, LONG x, struct line_node *line, struct pos_info *pos)
334 ENTER();
336 if(data->shown == TRUE)
338 LONG c = 0;
339 LONG d = 0;
340 LONG lines = 0;
342 while(c <= x)
344 LONG e = LineCharsWidth(data, &line->line.Contents[c]);
346 d = c;
348 if(e > 0)
350 c += e;
351 lines++;
353 else
354 break;
357 pos->lines = lines;
358 pos->x = x - d;
359 pos->bytes = d;
360 pos->extra = c;
362 else
364 pos->lines = 1;
365 pos->x = x;
366 pos->bytes = 0;
367 pos->extra = line->line.Length-1;
370 LEAVE();
374 /// LineNr()
375 LONG LineNr(struct InstData *data, struct line_node *line)
377 LONG result = 1;
378 struct line_node *actual = GetFirstLine(&data->linelist);
380 ENTER();
382 while(line != actual)
384 result++;
385 actual = GetNextLine(actual);
388 RETURN(result);
389 return(result);
393 /// LineNode()
394 struct line_node *LineNode(struct InstData *data, LONG linenr)
396 struct line_node *actual = GetFirstLine(&data->linelist);
397 struct line_node *next;
399 ENTER();
401 while(--linenr && (next = GetNextLine(actual)) != NULL)
403 actual = next;
406 RETURN(actual);
407 return(actual);
411 /// SetCursor()
412 /*------------------*
413 * Place the cursor *
414 *------------------*/
415 void SetCursor(struct InstData *data, LONG x, struct line_node *line, BOOL Set)
417 unsigned char chars[4] = " \0";
418 LONG line_nr;
419 struct pos_info pos;
420 LONG xplace;
421 LONG yplace;
422 LONG cursorxplace;
423 LONG cursor_width;
424 BOOL clipping = FALSE;
425 struct RastPort *rp = data->rport;
427 UWORD styles[3] = {0, 0, 0};
428 UWORD colors[3] = {0, 0, 0};
429 LONG start = 0;
430 LONG stop = 0;
431 LONG c;
432 UWORD flow;
434 ENTER();
436 if(Enabled(data) ||
437 data->update == FALSE ||
438 (data->scrollaction == TRUE && Set == TRUE) ||
439 data->ypos != _mtop(data->object) ||
440 data->shown == FALSE ||
441 isFlagSet(data->flags, FLG_ReadOnly) ||
442 isFlagSet(data->flags, FLG_Quiet) ||
443 isFlagSet(data->flags, FLG_Ghosted))
445 data->cursor_shown = FALSE;
447 LEAVE();
448 return;
451 line_nr = LineToVisual(data, line) - 1;
452 OffsetToLines(data, x, line, &pos);
454 if(line_nr + pos.lines <= data->maxlines && line_nr + pos.lines > 0)
456 for(c = -1; c < 2; c++)
458 if(x+c >= pos.bytes && x+c < pos.extra)
460 if(c < start)
461 start = c;
462 if(c > stop)
463 stop = c;
465 styles[c+1] = GetStyle(x+c, line);
466 colors[c+1] = GetColor(x+c, line);
467 chars[c+1] = (line->line.Contents[x+c] != '\n') ? line->line.Contents[x+c] : ' ';
471 // calculate the cursor width
472 // if it is set to 6 then we should find out how the width of the current char is
473 if(data->CursorWidth == 6)
474 cursor_width = TextLengthNew(&data->tmprp, (chars[1] < ' ') ? (char *)" " : (char *)&chars[1], 1, data->TabSizePixels);
475 else
476 cursor_width = data->CursorWidth;
478 xplace = _mleft(data->object) + TextLengthNew(&data->tmprp, &line->line.Contents[x-pos.x], pos.x+start, data->TabSizePixels);
479 flow = FlowSpace(data, line->line.Flow, &line->line.Contents[pos.bytes]);
480 xplace += flow;
481 yplace = data->ypos + (data->fontheight * (line_nr + pos.lines - 1));
482 cursorxplace = xplace + TextLengthNew(&data->tmprp, &line->line.Contents[x+start], 0-start, data->TabSizePixels);
484 //D(DBF_STARTUP, "xplace: %ld, yplace: %ld cplace: %ld, innerwidth: %ld width: %ld %ld", xplace, yplace, cursorxplace, _mwidth(data->object), _width(data->object), _mleft(data->object));
486 if(xplace <= _mright(data->object))
488 // clear area near the cursor first
489 DoMethod(data->object, MUIM_DrawBackground, xplace, yplace,
490 TextLengthNew(&data->tmprp, start == 0 ? (STRPTR)chars+1 : (STRPTR)chars, stop-start+1, data->TabSizePixels),
491 data->fontheight,
492 cursorxplace - (isFlagSet(data->flags, FLG_InVGrp) ? _mleft(data->object) : 0),
493 (isFlagSet(data->flags, FLG_InVGrp) ? 0 : _mtop(data->object)) + data->fontheight*(data->visual_y+line_nr+pos.lines-2),
496 if(Set == TRUE ||
497 (data->inactiveCursor == TRUE && isFlagClear(data->flags, FLG_Active) && isFlagClear(data->flags, FLG_Activated)))
499 SetAPen(rp, MUIPEN(data->cursorcolor));
500 SetDrMd(rp, JAM2);
502 // if the gadget is in inactive state we just draw a skeleton cursor instead
503 if(data->inactiveCursor == TRUE && isFlagClear(data->flags, FLG_Active) && isFlagClear(data->flags, FLG_Activated))
505 LONG cwidth = cursor_width;
507 if(data->CursorWidth != 6)
508 cwidth = TextLengthNew(&data->tmprp, chars[1] < ' ' ? (char *)" " : (char *)&chars[1], 1, data->TabSizePixels);
510 if(Set == TRUE || data->currentCursorState != CS_INACTIVE)
512 // draw a "new" skeleton cursor
513 Move(rp, cursorxplace, yplace);
514 Draw(rp, cursorxplace+cwidth-1, yplace);
515 Draw(rp, cursorxplace+cwidth-1, yplace+data->fontheight-1);
516 Draw(rp, cursorxplace, yplace+data->fontheight-1);
517 Draw(rp, cursorxplace, yplace);
520 // remember the inactive state
521 data->currentCursorState = CS_INACTIVE;
523 else
525 // draw a normal cursor
526 RectFill(rp, cursorxplace, yplace, cursorxplace+cursor_width-1, yplace+data->fontheight-1);
528 // remember the active state
529 data->currentCursorState = CS_ACTIVE;
532 else
534 // remember the off state
535 data->currentCursorState = CS_OFF;
538 SetDrMd(rp, JAM1);
539 SetFont(rp, data->font);
540 Move(rp, xplace, yplace + rp->TxBaseline);
542 if(data->font->tf_Flags & FPF_PROPORTIONAL)
544 clipping = TRUE;
545 AddClipping(data);
548 for(c = start; c <= stop; c++)
550 SetAPen(rp, ConvertPen(data, colors[1+c], line->line.Highlight));
551 SetSoftStyle(rp, ConvertStyle(styles[1+c]), AskSoftStyle(rp));
552 TextNew(rp, (STRPTR)&chars[1+c], 1, data->TabSizePixels);
554 SetSoftStyle(rp, FS_NORMAL, AskSoftStyle(rp));
556 /* This is really bad code!!! */
557 if(line->line.Separator != LNSF_None)
559 LONG LeftX, LeftWidth;
560 LONG RightX, RightWidth;
561 LONG Y, Height;
563 LeftX = _mleft(data->object);
564 LeftWidth = flow-3;
565 RightX = _mleft(data->object) + flow + TextLengthNew(&data->tmprp, &line->line.Contents[pos.bytes], pos.extra-pos.bytes-1, data->TabSizePixels) + 3;
566 RightWidth = _mleft(data->object)+_mwidth(data->object) - RightX;
567 Y = yplace;
568 Height = isFlagSet(line->line.Separator, LNSF_Thick) ? 2 : 1;
570 if(isFlagSet(line->line.Separator, LNSF_Middle))
571 Y += (data->fontheight/2)-Height;
572 else if(isFlagSet(line->line.Separator, LNSF_Bottom))
573 Y += data->fontheight-(2*Height);
575 if(isFlagSet(line->line.Separator, LNSF_StrikeThru) || line->line.Length == 1)
577 LeftWidth = _mwidth(data->object);
579 else
581 DrawSeparator(data, rp, RightX, Y, RightWidth, Height);
583 DrawSeparator(data, rp, LeftX, Y, LeftWidth, Height);
586 if(clipping)
587 RemoveClipping(data);
591 LEAVE();
595 /// DumpText()
596 /*-----------------------------------------*
597 * Dump text from buffer and out to screen *
598 *-----------------------------------------*/
599 void DumpText(struct InstData *data, LONG visual_y, LONG line_nr, LONG lines, BOOL doublebuffer)
601 struct pos_info pos;
602 struct line_node *line;
603 LONG x;
604 BOOL drawbottom = (visual_y + (lines-line_nr) - 1) > data->totallines;
606 ENTER();
608 if(data->update == TRUE && data->shown == TRUE && isFlagClear(data->flags, FLG_Quiet))
610 GetLine(data, visual_y, &pos);
611 line = pos.line;
612 x = pos.x;
614 if(lines-line_nr < 3 || doublebuffer == TRUE)
616 doublebuffer = TRUE;
618 else
620 AddClipping(data);
621 doublebuffer = FALSE;
624 while(line != NULL && line_nr != lines)
626 while(x < line->line.Length && line_nr != lines)
627 x = x + PrintLine(data, x, line, ++line_nr, doublebuffer);
629 line = GetNextLine(line);
630 x = 0;
633 if(drawbottom && (data->maxlines > (data->totallines-data->visual_y+1)))
635 DoMethod(data->object, MUIM_DrawBackground,
636 _mleft(data->object),
637 data->ypos+((data->totallines-data->visual_y+1)*data->fontheight),
638 _mwidth(data->object),
639 (data->maxlines*data->fontheight) - ((data->totallines-data->visual_y+1)*data->fontheight),
640 (isFlagSet(data->flags, FLG_InVGrp) ? 0 : _mleft(data->object)),
641 (isFlagSet(data->flags, FLG_InVGrp) ? 0 : _mtop(data->object)) + data->totallines*data->fontheight,
644 if(isFlagSet(data->flags, FLG_Ghosted) && isFlagClear(data->flags, FLG_MUI4))
646 UWORD newPattern[2];
648 if(((data->visual_y-1)*data->fontheight)%2 == 0)
650 newPattern[0] = 0x4444;
651 newPattern[1] = 0x1111;
653 else
655 newPattern[0] = 0x1111;
656 newPattern[1] = 0x4444;
658 SetDrMd(data->rport, JAM1);
659 SetAPen(data->rport, _pens(data->object)[MPEN_SHADOW]);
660 SetAfPt(data->rport, newPattern, 1);
661 RectFill(data->rport,
662 _mleft(data->object),
663 data->ypos+((data->totallines-data->visual_y+1)*data->fontheight),
664 _mright(data->object),
665 data->ypos+((data->totallines-data->visual_y+1)*data->fontheight)+(data->maxlines*data->fontheight) - ((data->totallines-data->visual_y+1)*data->fontheight)-1);
666 SetAfPt(data->rport, NULL, (UBYTE)-1);
670 if(doublebuffer == FALSE)
671 RemoveClipping(data);
674 LEAVE();
678 /// ScrollUpDOwn()
679 void ScrollUpDown(struct InstData *data)
681 ENTER();
683 if(data->update == TRUE && isFlagClear(data->flags, FLG_Quiet) && data->shown == TRUE)
685 DumpText(data, data->visual_y, 0, data->maxlines, FALSE);
688 LEAVE();
692 /// GetLine()
693 /*----------------------------------------------*
694 * Find a line and fillout a pos_info structure *
695 *----------------------------------------------*/
696 void GetLine(struct InstData *data, LONG realline, struct pos_info *pos)
698 struct line_node *line = GetFirstLine(&data->linelist);
699 struct line_node *next;
700 LONG x = 0;
702 ENTER();
704 while(realline > line->visual && (next = GetNextLine(line)) != NULL)
706 realline = realline - line->visual;
707 line = next;
710 pos->line = line;
711 pos->lines = realline;
713 if(HasNextLine(line) == FALSE && realline > line->visual)
715 x = line->line.Length-1;
717 else if(realline > 0)
719 while(--realline)
721 x += LineCharsWidth(data, &line->line.Contents[x]);
725 pos->x = x;
727 LEAVE();
731 /// LineToVisual()
732 /*----------------------------*
733 * Find visual line on screen *
734 *----------------------------*/
735 LONG LineToVisual(struct InstData *data, struct line_node *line)
737 LONG line_nr = 2 - data->visual_y; // Top line!
738 struct line_node *tline = GetFirstLine(&data->linelist);
740 ENTER();
742 while(tline != line && tline != NULL)
744 line_nr = line_nr + tline->visual;
745 tline = GetNextLine(tline);
748 RETURN(line_nr);
749 return(line_nr);
753 /// CountLines
754 // count all lines in the list and return the number of visual lines
755 LONG CountLines(struct InstData *data, struct MinList *lines)
757 LONG lineCount = 0;
758 struct line_node *line;
760 ENTER();
762 line = GetFirstLine(lines);
763 while(line != NULL)
765 LONG vh;
767 vh = VisualHeight(data, line);
768 lineCount += vh;
769 line->visual = vh;
770 line = GetNextLine(line);
773 RETURN(lineCount);
774 return lineCount;