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 ***************************************************************************/
23 #if defined(__amigaos4__)
24 #include <hardware/blit.h>
27 #include <graphics/gfxmacros.h>
28 #include <graphics/text.h>
29 #include <clib/alib_protos.h>
30 #include <proto/graphics.h>
31 #include <proto/intuition.h>
37 ULONG
ConvertStyle(UWORD style
)
39 ULONG result
= FS_NORMAL
;
43 if(isFlagSet(style
, BOLD
))
44 setFlag(result
, FSF_BOLD
);
45 if(isFlagSet(style
, ITALIC
))
46 setFlag(result
, FSF_ITALIC
);
47 if(isFlagSet(style
, UNDERLINE
))
48 setFlag(result
, FSF_UNDERLINED
);
56 ULONG
ConvertPen(struct InstData
*data
, UWORD color
, BOOL highlight
)
64 if(data
->colormap
!= NULL
)
65 pen
= MUIPEN(data
->colormap
[color
-1]);
67 pen
= _pens(data
->object
)[color
-1];
74 pen
= MUIPEN(data
->highlightcolor
);
76 pen
= MUIPEN(data
->textcolor
);
85 void DrawSeparator(struct InstData
*data
, struct RastPort
*rp
, LONG X
, LONG Y
, LONG Width
, LONG Height
)
91 SetAPen(rp
, MUIPEN(data
->separatorshadow
));
92 RectFill(rp
, X
, Y
, X
+Width
-2, Y
);
93 RectFill(rp
, X
, Y
, X
, Y
+Height
);
95 SetAPen(rp
, MUIPEN(data
->separatorshine
));
96 RectFill(rp
, X
+1, Y
+Height
, X
+Width
-1, Y
+Height
);
97 RectFill(rp
, X
+Width
-1, Y
, X
+Width
-1, Y
+Height
);
105 LONG
PrintLine(struct InstData
*data
, LONG x
, struct line_node
*line
, LONG line_nr
, BOOL doublebuffer
)
107 STRPTR text
= line
->line
.Contents
;
109 struct RastPort
*rp
= &data
->doublerp
;
113 length
= LineCharsWidth(data
, text
+x
);
115 if(doublebuffer
== FALSE
)
118 if(line_nr
> 0 && data
->update
== TRUE
&& isFlagClear(data
->flags
, FLG_Quiet
) && data
->rport
!= NULL
&& data
->shown
== TRUE
)
120 LONG c_length
= length
;
121 LONG startx
= 0, stopx
= 0;
122 LONG starty
= 0, xoffset
= 0;
125 struct LineStyle
*styles
= line
->line
.Styles
;
126 struct LineColor
*colors
= line
->line
.Colors
;
127 struct marking block
;
130 if(line
->line
.Highlight
== TRUE
&& x
== 0 && line
->line
.Length
== 1)
131 line
->line
.Highlight
= FALSE
;
133 if(doublebuffer
== FALSE
)
135 starty
= data
->ypos
+(data
->fontheight
* (line_nr
-1));
136 xoffset
= _mleft(data
->object
);
139 flow
= FlowSpace(data
, line
->line
.Flow
, text
+x
);
140 Move(rp
, xoffset
+flow
, starty
+rp
->TxBaseline
);
144 struct line_node
*blkline
;
146 NiceBlock(&data
->blockinfo
, &block
);
148 blkline
= GetNextLine(block
.startline
);
150 if(block
.startline
== block
.stopline
)
152 if(block
.startline
== line
)
154 startx
= block
.startx
;
160 if(block
.startline
== line
)
162 startx
= block
.startx
;
163 stopx
= line
->line
.Length
;
167 if(block
.stopline
== line
)
173 while((blkline
!= block
.stopline
) && (!stopx
))
177 stopx
= line
->line
.Length
;
179 blkline
= GetNextLine(blkline
);
189 struct RastPort
*old
= _rp(data
->object
);
191 if(startx
< x
+c_length
&& stopx
> x
)
194 blockstart
= TextLengthNew(&data
->tmprp
, text
+x
, startx
-x
, data
->TabSizePixels
);
198 blockwidth
= ((stopx
>= c_length
+x
) ? _mwidth(data
->object
)-(blockstart
+flow
) : TextLengthNew(&data
->tmprp
, text
+startx
, stopx
-startx
, data
->TabSizePixels
));
200 else if(isFlagClear(data
->flags
, FLG_ReadOnly
) &&
201 isFlagClear(data
->flags
, FLG_Ghosted
) &&
202 line
== data
->actualline
&&
204 data
->CPos_X
< x
+c_length
&&
206 (isFlagSet(data
->flags
, FLG_Active
) || data
->inactiveCursor
== TRUE
))
209 blockstart
= TextLengthNew(&data
->tmprp
, text
+x
, data
->CPos_X
-x
, data
->TabSizePixels
);
211 // calculate the cursor width
212 // if it is set to 6 then we should find out how the width of the current char is
213 if(data
->CursorWidth
== 6)
214 blockwidth
= TextLengthNew(&data
->tmprp
, (text
[data
->CPos_X
] < ' ') ? (char *)" " : (char *)&text
[data
->CPos_X
], 1, data
->TabSizePixels
);
216 blockwidth
= data
->CursorWidth
;
220 _rp(data
->object
) = rp
;
222 // clear the background first
223 DoMethod(data
->object
, MUIM_DrawBackground
, xoffset
, starty
,
224 flow
+blockstart
, data
->fontheight
,
225 isFlagSet(data
->flags
, FLG_InVGrp
) ? 0 : _mleft(data
->object
),
226 isFlagSet(data
->flags
, FLG_InVGrp
) ? data
->fontheight
*(data
->visual_y
+line_nr
-2) : _mtop(data
->object
)+data
->fontheight
* (data
->visual_y
+line_nr
-2),
233 // in case the gadget is in inactive state we use a different background
234 // color for our selected area
235 if(isFlagClear(data
->flags
, FLG_Active
) &&
236 isFlagClear(data
->flags
, FLG_Activated
) &&
237 isFlagSet(data
->flags
, FLG_ActiveOnClick
))
239 color
= MUIPEN(data
->inactivecolor
);
242 color
= MUIPEN(data
->markedcolor
);
244 // if selectmode == 2 then a whole line should be drawn as being marked, so
245 // we have to start at xoffset instead of xoffset+flow+blockstart.
246 // Please note that the second part of the following "empiric" evaluation should
247 // prevent that centered or right aligned lines are not correctly marked right
248 // from the beginning of the line. However, it seems to be not cover 100% of all different
249 // cases so that the evaluation if a line should be completely marked should be probably
250 // moved elsewhere in future.
251 if(data
->selectmode
== 2 ||
252 (flow
&& data
->selectmode
!= 1 && startx
-x
== 0 && cursor
== FALSE
&&
253 ((data
->blockinfo
.startline
!= data
->blockinfo
.stopline
) || x
> 0)))
255 LONG right
= MIN(_mright(data
->object
), xoffset
+flow
+blockwidth
-1);
258 RectFill(rp
, xoffset
, starty
, right
, starty
+data
->fontheight
-1);
262 LONG right
= MIN(_mright(data
->object
), xoffset
+flow
+blockstart
+blockwidth
-1);
264 SetAPen(rp
, cursor
? data
->cursorcolor
: color
);
265 RectFill(rp
, xoffset
+flow
+blockstart
, starty
, right
, starty
+data
->fontheight
-1);
267 // if the gadget is in inactive state we just draw a skeleton cursor instead
269 isFlagClear(data
->flags
, FLG_Active
) &&
270 isFlagClear(data
->flags
, FLG_Activated
))
272 DoMethod(data
->object
, MUIM_DrawBackground
, xoffset
+flow
+blockstart
+1, starty
+1,
273 blockwidth
-2, data
->fontheight
-2,
274 isFlagSet(data
->flags
, FLG_InVGrp
) ? 0 : _mleft(data
->object
),
275 isFlagSet(data
->flags
, FLG_InVGrp
) ? data
->fontheight
*(data
->visual_y
+line_nr
-2) : _mtop(data
->object
)+data
->fontheight
* (data
->visual_y
+line_nr
-2),
283 LONG x_start
= xoffset
+blockstart
+blockwidth
,
285 x_width
= _mwidth(data
->object
)-(blockstart
+blockwidth
),
286 y_width
= data
->fontheight
,
287 x_ptrn
= blockstart
+blockwidth
,
288 y_ptrn
= data
->fontheight
*(data
->visual_y
+line_nr
-2);
296 if(isFlagClear(data
->flags
, FLG_InVGrp
))
298 x_ptrn
+= _mleft(data
->object
);
299 y_ptrn
+= _mtop(data
->object
);
302 DoMethod(data
->object
, MUIM_DrawBackground
, x_start
, y_start
, x_width
, y_width
, x_ptrn
, y_ptrn
, 0);
304 _rp(data
->object
) = old
;
307 if(doublebuffer
== FALSE
)
310 SetAPen(rp
, line
->line
.Highlight
? MUIPEN(data
->highlightcolor
) : MUIPEN(data
->textcolor
));
312 maxwidth
= _mwidth(data
->object
) - flow
;
315 LONG p_length
= c_length
;
316 struct TextExtent te
;
318 SetSoftStyle(rp
, ConvertStyle(GetStyle(x
, line
)), AskSoftStyle(rp
));
321 while(styles
->column
-1 <= x
)
324 if(styles
->column
-x
-1 < p_length
)
325 p_length
= styles
->column
-x
-1;
330 while(colors
->column
-1 <= x
)
332 SetAPen(rp
, ConvertPen(data
, colors
->color
, line
->line
.Highlight
));
336 if(colors
->column
-x
-1 < p_length
)
337 p_length
= colors
->column
-x
-1;
342 if((startx > x) && (startx-x < p_length))
349 if((stopx > x) && (stopx-x < p_length))
355 SetAPen(rp, line->color ? MUIPEN(data->highlightcolor) : MUIPEN(data->textcolor));
360 // check if there is space left to print some text
363 // calculate how many character really fit in the remaining space
364 ULONG fitting
= TextFitNew(rp
, text
+x
, p_length
, &te
, NULL
, 1, maxwidth
, data
->fontheight
, data
->TabSizePixels
);
368 if(text
[x
+fitting
-1] < ' ')
369 TextNew(rp
, text
+x
, fitting
-1, data
->TabSizePixels
);
371 TextNew(rp
, text
+x
, fitting
, data
->TabSizePixels
);
374 // adjust the available horizontal pixel space
375 maxwidth
-= te
.te_Width
;
378 // add the length calculated before no matter how many character really fitted
380 c_length
-= p_length
;
382 SetSoftStyle(rp
, FS_NORMAL
, AskSoftStyle(rp
));
384 if(line
->line
.Separator
!= LNSF_None
)
386 LONG LeftX
, LeftWidth
;
387 LONG RightX
, RightWidth
;
393 RightWidth
= xoffset
+_mwidth(data
->object
) - RightX
;
395 Height
= isFlagSet(line
->line
.Separator
, LNSF_Thick
) ? 2 : 1;
397 if(isFlagSet(line
->line
.Separator
, LNSF_Middle
))
398 Y
+= (data
->fontheight
/2)-Height
;
399 else if(isFlagSet(line
->line
.Separator
, LNSF_Bottom
))
400 Y
+= data
->fontheight
-(2*Height
);
402 if(isFlagSet(line
->line
.Separator
, LNSF_StrikeThru
) || line
->line
.Length
== 1)
404 LeftWidth
= _mwidth(data
->object
);
408 DrawSeparator(data
, rp
, RightX
, Y
, RightWidth
, Height
);
410 DrawSeparator(data
, rp
, LeftX
, Y
, LeftWidth
, Height
);
414 if(isFlagSet(data
->flags
, FLG_Ghosted
) && isFlagClear(data
->flags
, FLG_MUI4
))
416 UWORD newPattern
[] = {0x1111, 0x4444};
418 if(doublebuffer
== TRUE
)
420 ULONG ptrn1
= 0x11111111UL
;
421 ULONG ptrn2
= 0x44444444UL
;
423 ptrn1
= ptrn1
>>((_mleft(data
->object
)-xoffset
)%16);
424 ptrn2
= ptrn2
>>((_mleft(data
->object
)-xoffset
)%16);
426 if((data
->fontheight
*(data
->visual_y
+line_nr
-2))%2 == 0)
428 newPattern
[0] = ptrn2
;
429 newPattern
[1] = ptrn1
;
433 newPattern
[0] = ptrn1
;
434 newPattern
[1] = ptrn2
;
439 if((data
->fontheight
*(data
->visual_y
-1))%2 == 0)
441 newPattern
[0] = 0x4444;
442 newPattern
[1] = 0x1111;
447 SetAPen(rp
, _pens(data
->object
)[MPEN_SHADOW
]);
448 SetAfPt(rp
, newPattern
, 1);
449 RectFill(rp
, xoffset
, starty
, xoffset
+_mwidth(data
->object
)-1, starty
+data
->fontheight
-1);
450 SetAfPt(rp
, NULL
, (UBYTE
)-1);
453 if(doublebuffer
== FALSE
)
454 RemoveClipping(data
);
459 BltBitMapRastPort(rp
->BitMap
, xoffset
, _mtop(data
->object
)-data
->ypos
, data
->rport
, _mleft(data
->object
), _mtop(data
->object
)+(data
->fontheight
* (line_nr
-1)), _mwidth(data
->object
), data
->fontheight
-(_mtop(data
->object
)-data
->ypos
), (ABC
|ABNC
));
463 if(line_nr
== data
->maxlines
+1)
465 if(_mtop(data
->object
) != data
->ypos
)
467 BltBitMapRastPort(rp
->BitMap
, xoffset
, 0, data
->rport
, _mleft(data
->object
), data
->ypos
+(data
->fontheight
* (line_nr
-1)), _mwidth(data
->object
), _mtop(data
->object
)-data
->ypos
, (ABC
|ABNC
));
472 BltBitMapRastPort(rp
->BitMap
, xoffset
, 0, data
->rport
, _mleft(data
->object
), data
->ypos
+(data
->fontheight
* (line_nr
-1)), _mwidth(data
->object
), data
->fontheight
, (ABC
|ABNC
));
478 if(isFlagSet(data
->flags
, FLG_HScroll
))
479 length
= line
->line
.Length
;