1 /***************************************************************************
3 TextEditor.mcc - Textediting MUI Custom Class
4 Copyright (C) 1997-2000 Allan Odgaard
5 Copyright (C) 2005-2009 by 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 #include <intuition/classes.h>
24 #include <utility/tagitem.h>
25 #include <clib/alib_protos.h>
27 #include <proto/graphics.h>
28 #include <proto/utility.h>
29 #include <proto/layers.h>
30 #include <proto/intuition.h>
32 #include <libraries/mui.h>
33 #include <proto/muimaster.h>
39 IPTR
Get(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
41 struct InstData
*data
= INST_DATA(cl
, obj
);
46 switch(msg
->opg_AttrID
)
48 case MUIA_TextEditor_CursorPosition
:
50 UWORD xplace
, yplace
, cursor_width
;
51 UWORD x
= data
->CPos_X
;
52 struct line_node
*line
= data
->actualline
;
53 LONG line_nr
= LineToVisual(line
, data
) - 1;
56 OffsetToLines(x
, line
, &pos
, data
);
58 // calculate the cursor width
59 // if it is set to 6 then we should find out how the width of the current char is
60 if(data
->CursorWidth
== 6)
61 cursor_width
= TextLength(&data
->tmprp
, line
->line
.Contents
[x
] < ' ' ? (char *)" " : (char *)&line
->line
.Contents
[x
], 1);
63 cursor_width
= data
->CursorWidth
;
65 xplace
= data
->xpos
+ TextLength(&data
->tmprp
, &line
->line
.Contents
[x
-pos
.x
], pos
.x
);
66 xplace
+= FlowSpace(line
->line
.Flow
, line
->line
.Contents
+pos
.bytes
, data
);
67 yplace
= data
->ypos
+ (data
->height
* (line_nr
+ pos
.lines
- 1));
69 data
->CursorPosition
.MinX
= xplace
;
70 data
->CursorPosition
.MinY
= yplace
;
71 data
->CursorPosition
.MaxX
= xplace
+ cursor_width
- 1;
72 data
->CursorPosition
.MaxY
= yplace
+ data
->height
- 1;
73 ti_Data
= (IPTR
)&data
->CursorPosition
;
77 case MUIA_TextEditor_UndoAvailable
:
78 ti_Data
= data
->undolevel
> 0 && data
->undocur
> 0;
81 case MUIA_TextEditor_RedoAvailable
:
82 ti_Data
= data
->undolevel
> 0 && data
->undofill
> data
->undocur
;
85 case MUIA_TextEditor_ActiveObjectOnClick
:
86 ti_Data
= ((data
->flags
& FLG_ActiveOnClick
) ? TRUE
: FALSE
);
89 case MUIA_TextEditor_AutoClip
:
90 ti_Data
= ((data
->flags
& FLG_AutoClip
) ? TRUE
: FALSE
);
93 case MUIA_TextEditor_KeyUpFocus
:
94 ti_Data
= (IPTR
)data
->KeyUpFocus
;
98 ti_Data
= LIB_VERSION
;
102 ti_Data
= LIB_REVISION
;
105 case MUIA_ControlChar
:
106 ti_Data
= (IPTR
)data
->CtrlChar
;
109 case MUIA_TextEditor_AreaMarked
:
110 ti_Data
= Enabled(data
);
112 case MUIA_TextEditor_CursorX
:
113 ti_Data
= data
->CPos_X
;
115 case MUIA_TextEditor_CursorY
:
116 ti_Data
= LineNr(data
->actualline
, data
)-1;
118 case MUIA_TextEditor_ExportWrap
:
119 ti_Data
= data
->ExportWrap
;
121 case MUIA_TextEditor_FixedFont
:
122 ti_Data
= data
->use_fixedfont
;
124 case MUIA_TextEditor_Pen
:
127 case MUIA_TextEditor_Flow
:
128 ti_Data
= data
->Flow
;
130 case MUIA_TextEditor_Separator
:
131 ti_Data
= data
->Separator
;
133 case MUIA_TextEditor_HasChanged
:
134 ti_Data
= data
->HasChanged
;
136 case MUIA_TextEditor_HorizontalScroll
:
137 ti_Data
= ((data
->flags
& FLG_HScroll
) ? TRUE
: FALSE
);
139 case MUIA_TextEditor_ImportWrap
:
140 ti_Data
= data
->ImportWrap
;
142 /* case MUIA_TextEditor_InsertMode:
143 ti_Data = data->InsertMode;
146 case MUIA_TextEditor_Prop_Entries
:
147 ti_Data
= data
->totallines
;
149 case MUIA_TextEditor_Prop_Visible
:
150 ti_Data
= data
->maxlines
;
152 case MUIA_TextEditor_Prop_DeltaFactor
:
153 ti_Data
= data
->height
;
155 case MUIA_TextEditor_Prop_First
:
156 ti_Data
= (data
->visual_y
-1)*data
->height
;
158 case MUIA_TextEditor_ReadOnly
:
159 ti_Data
= ((data
->flags
& FLG_ReadOnly
) ? TRUE
: FALSE
);
161 case MUIA_TextEditor_Quiet
:
162 ti_Data
= ((data
->flags
& FLG_Quiet
) ? TRUE
: FALSE
);
164 case MUIA_TextEditor_StyleBold
:
165 ti_Data
= ((GetStyle(data
->CPos_X
, data
->actualline
) & BOLD
) ? TRUE
: FALSE
);
167 case MUIA_TextEditor_StyleItalic
:
168 ti_Data
= ((GetStyle(data
->CPos_X
, data
->actualline
) & ITALIC
) ? TRUE
: FALSE
);
170 case MUIA_TextEditor_StyleUnderline
:
171 ti_Data
= ((GetStyle(data
->CPos_X
, data
->actualline
) & UNDERLINE
) ? TRUE
: FALSE
);
173 case MUIA_TextEditor_TypeAndSpell
:
174 ti_Data
= data
->TypeAndSpell
;
177 case MUIA_TextEditor_WrapBorder
:
178 ti_Data
= data
->WrapBorder
;
181 case MUIA_TextEditor_WrapMode
:
182 ti_Data
= data
->WrapMode
;
186 ti_Data
= (IPTR
)data
->font
;
189 case MUIA_TextEditor_UndoLevels
:
190 ti_Data
= data
->undolevel
;
195 return(DoSuperMethodA(cl
, obj
, (Msg
)msg
));
197 *msg
->opg_Storage
= ti_Data
;
203 IPTR
Set(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
205 struct InstData
*data
= INST_DATA(cl
, obj
);
206 struct TagItem
*tags
, *tag
;
207 char *contents
= NULL
;
209 ULONG crsr_x
= 0xffff, crsr_y
= 0xffff;
213 if(data
->shown
&& !(data
->flags
& FLG_Draw
))
215 if((tag
= FindTagItem(MUIA_Disabled
, msg
->ops_AttrList
)))
218 data
->flags
|= FLG_Ghosted
;
219 else data
->flags
&= ~FLG_Ghosted
;
221 data
->UpdateInfo
= msg
;
222 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
224 RETURN((IPTR
)data
->UpdateInfo
);
225 return((IPTR
)data
->UpdateInfo
);
228 tags
= msg
->ops_AttrList
;
229 while((tag
= NextTagItem((APTR
)&tags
)))
231 ULONG ti_Data
= tag
->ti_Data
;
235 case MUIA_ControlChar
:
236 data
->CtrlChar
= (UBYTE
)ti_Data
;
241 data
->flags
|= FLG_Ghosted
;
243 data
->flags
&= ~FLG_Ghosted
;
245 // make sure an eventually existing slider is disabled as well
247 set(data
->slider
, MUIA_Disabled
, ti_Data
);
249 MUI_Redraw(obj
, MADF_DRAWOBJECT
);
252 case MUIA_TextEditor_Rows
:
253 data
->Rows
= ti_Data
;
256 case MUIA_TextEditor_Columns
:
257 data
->Columns
= ti_Data
;
260 case MUIA_TextEditor_AutoClip
:
262 data
->flags
|= FLG_AutoClip
;
264 data
->flags
&= ~FLG_AutoClip
;
267 case MUIA_TextEditor_ColorMap
:
268 data
->colormap
= (ULONG
*)ti_Data
;
270 case MUIA_TextEditor_InVirtualGroup
:
272 data
->flags
|= FLG_InVGrp
;
274 data
->flags
&= ~FLG_InVGrp
;
277 case MUIA_TextEditor_CursorX
:
282 case MUIA_TextEditor_CursorY
:
287 case MUIA_TextEditor_Prop_Release
:
288 data
->smooth_wait
= ti_Data
;
291 case MUIA_TextEditor_Prop_First
:
293 if(((data
->visual_y
-1)*data
->height
+(data
->realypos
- data
->ypos
) != (LONG
)ti_Data
) && (data
->shown
))
296 LONG lastpixel
= ((data
->visual_y
-1)*data
->height
) + (data
->realypos
- data
->ypos
);
297 struct Hook
*oldhook
;
300 diff
= data
->visual_y
- ((ti_Data
/data
->height
)+1);
302 data
->visual_y
= (ti_Data
/data
->height
)+1;
303 smooth
= ti_Data
- lastpixel
;
306 data
->scr_direction
= 1;
308 data
->scr_direction
= 0;
310 oldhook
= InstallLayerHook(data
->rport
->Layer
, LAYERS_NOBACKFILL
);
311 cliphandle
= MUI_AddClipping(muiRenderInfo(data
->object
), data
->xpos
, data
->realypos
, data
->innerwidth
, data
->maxlines
*data
->height
);
312 if(smooth
> 0 && smooth
< data
->maxlines
*data
->height
)
316 ScrollRasterBF(data
->rport
, 0, smooth
,
317 data
->xpos
, data
->realypos
,
318 data
->xpos
+ data
->innerwidth
- 1,
319 data
->realypos
+ (data
->maxlines
* data
->height
) - 1);
321 data
->ypos
= data
->realypos
- ti_Data
%data
->height
;
322 line_nr
= data
->maxlines
-(smooth
/data
->height
)-1;
325 struct Layer
*layer
= data
->rport
->Layer
;
327 if(layer
->DamageList
&& layer
->DamageList
->RegionRectangle
)
329 if(MUI_BeginRefresh(muiRenderInfo(data
->object
),0))
331 MUI_Redraw(data
->object
, MADF_DRAWOBJECT
);
332 MUI_EndRefresh(muiRenderInfo(data
->object
), 0);
337 DumpText(data
->visual_y
+line_nr
, line_nr
, data
->maxlines
+1, FALSE
, data
);
341 if(smooth
< 0 && -smooth
< data
->maxlines
*data
->height
)
345 ScrollRasterBF(data
->rport
, 0, smooth
,
346 data
->xpos
, data
->realypos
,
347 data
->xpos
+ data
->innerwidth
- 1,
348 data
->realypos
+ (data
->maxlines
* data
->height
) - 1);
349 data
->ypos
= data
->realypos
- ti_Data
%data
->height
;
350 lines
= (-smooth
/data
->height
)+2;
352 struct Layer
*layer
= data
->rport
->Layer
;
354 if(layer
->DamageList
&& layer
->DamageList
->RegionRectangle
)
355 if(MUI_BeginRefresh(muiRenderInfo(data
->object
),0))
357 MUI_Redraw(data
->object
, MADF_DRAWOBJECT
);
358 MUI_EndRefresh(muiRenderInfo(data
->object
), 0);
362 DumpText(data
->visual_y
, 0, lines
, FALSE
, data
);
367 DumpText(data
->visual_y
, 0, data
->maxlines
+1, FALSE
, data
);
370 MUI_RemoveClipping(muiRenderInfo(data
->object
), cliphandle
);
371 InstallLayerHook(data
->rport
->Layer
, oldhook
);
373 if(!data
->scrollaction
)
376 data
->smooth_wait
= 1;
377 data
->scrollaction
= TRUE
;
380 SetAttrs(obj
, MUIA_TextEditor_Prop_Entries
,
381 ((data
->totallines
-(data
->visual_y
-1) < data
->maxlines
) ?
382 ((data
->visual_y
-1)+data
->maxlines
) :
383 ((data
->maxlines
> data
->totallines
) ?
391 case MUIA_TextEditor_ReadOnly
:
395 SetCursor(data
->CPos_X
, data
->actualline
, FALSE
, data
);
396 data
->flags
|= FLG_ReadOnly
;
398 // force the activeOnClick to be turned off
399 // in case the user explicitly sets the readonly object
400 data
->flags
&= ~FLG_ActiveOnClick
;
402 // enable that the object will automatically get a border when
403 // the ActiveObjectOnClick option is active
404 _flags(obj
) &= ~(1<<7);
408 data
->flags
&= ~FLG_ReadOnly
;
411 if(data
->flags
& FLG_Active
)
412 SetCursor(data
->CPos_X
, data
->actualline
, TRUE
, data
);
415 // disable that the object will automatically get a border when
416 // the ActiveObjectOnClick option is active
417 if((data
->flags
& FLG_ActiveOnClick
) != 0)
418 _flags(obj
) |= (1<<7);
423 case MUIA_TextEditor_ActiveObjectOnClick
:
427 data
->flags
|= FLG_ActiveOnClick
;
429 // disable that the object will automatically get a border when
430 // the ActiveObjectOnClick option is active
431 _flags(obj
) |= (1<<7);
435 data
->flags
&= ~FLG_ActiveOnClick
;
437 // enable that the object will automatically get a border when
438 // the ActiveObjectOnClick option is active
439 _flags(obj
) &= ~(1<<7);
444 case MUIA_TextEditor_PopWindow_Open
:
447 data
->flags
|= FLG_PopWindow
;
449 data
->flags
&= ~FLG_PopWindow
;
453 case MUIA_TextEditor_Quiet
:
456 data
->flags
|= FLG_Quiet
;
460 data
->flags
&= ~FLG_Quiet
;
461 MUI_Redraw(obj
, MADF_DRAWOBJECT
);
462 if(data
->maxlines
> data
->totallines
)
463 set(data
->object
, MUIA_TextEditor_Prop_Entries
, data
->maxlines
*data
->height
);
465 set(data
->object
, MUIA_TextEditor_Prop_Entries
, data
->totallines
*data
->height
);
466 set(data
->object
, MUIA_TextEditor_Prop_First
, (data
->visual_y
-1)*data
->height
);
470 case MUIA_TextEditor_StyleBold
:
471 AddStyle(&data
->blockinfo
, BOLD
, ti_Data
, data
);
474 case MUIA_TextEditor_StyleItalic
:
475 AddStyle(&data
->blockinfo
, ITALIC
, ti_Data
, data
);
478 case MUIA_TextEditor_StyleUnderline
:
479 AddStyle(&data
->blockinfo
, UNDERLINE
, ti_Data
, data
);
482 case MUIA_TextEditor_Pen
:
486 AddColor(&data
->blockinfo
, (UWORD
)ti_Data
, data
);
487 data
->HasChanged
= TRUE
;
491 case MUIA_TextEditor_KeyUpFocus
:
492 data
->KeyUpFocus
= (Object
*)ti_Data
;
495 case MUIA_TextEditor_Slider
:
499 data
->slider
= (void *)ti_Data
;
501 // disable the slider right away if the texteditor
502 // gadget is disabled as well.
503 if(data
->flags
& FLG_Ghosted
)
504 set(data
->slider
, MUIA_Disabled
, TRUE
);
506 DoMethod(data
->slider
, MUIM_Notify
,
507 MUIA_Prop_Release
, MUIV_EveryTime
,
508 obj
, 3, MUIM_NoNotifySet
, MUIA_TextEditor_Prop_Release
, MUIV_TriggerValue
);
509 DoMethod(data
->slider
, MUIM_Notify
,
510 MUIA_Prop_First
, MUIV_EveryTime
,
511 obj
, 3, MUIM_NoNotifySet
, MUIA_TextEditor_Prop_First
, MUIV_TriggerValue
);
512 DoMethod(obj
, MUIM_Notify
,
513 MUIA_TextEditor_Prop_First
, MUIV_EveryTime
,
514 data
->slider
, 3, MUIM_NoNotifySet
, MUIA_Prop_First
, MUIV_TriggerValue
);
515 DoMethod(obj
, MUIM_Notify
,
516 MUIA_TextEditor_Prop_Entries
, MUIV_EveryTime
,
517 data
->slider
, 3, MUIM_NoNotifySet
, MUIA_Prop_Entries
, MUIV_TriggerValue
);
518 DoMethod(obj
, MUIM_Notify
,
519 MUIA_TextEditor_Prop_Visible
, MUIV_EveryTime
,
520 data
->slider
, 3, MUIM_NoNotifySet
, MUIA_Prop_Visible
, MUIV_TriggerValue
);
521 DoMethod(obj
, MUIM_Notify
,
522 MUIA_TextEditor_Prop_DeltaFactor
, MUIV_EveryTime
,
523 data
->slider
, 3, MUIM_NoNotifySet
, MUIA_Prop_DeltaFactor
, MUIV_TriggerValue
);
528 case MUIA_TextEditor_FixedFont
:
534 data
->font
= data
->fixedfont
;
535 data
->use_fixedfont
= TRUE
;
539 data
->font
= data
->normalfont
;
540 data
->use_fixedfont
= FALSE
;
543 // now we check whether we have a valid font or not
544 // and if not we take the default one of our muiAreaData
545 if(data
->font
== NULL
)
546 data
->font
= muiAreaData(obj
)->mad_Font
;
550 case MUIA_TextEditor_DoubleClickHook
:
551 data
->DoubleClickHook
= (struct Hook
*)ti_Data
;
554 case MUIA_TextEditor_HasChanged
:
555 data
->HasChanged
= ti_Data
;
557 data
->flags
&= ~FLG_UndoLost
;
560 case MUIA_TextEditor_HorizontalScroll
:
562 data
->flags
|= FLG_HScroll
;
564 data
->flags
&= ~FLG_HScroll
;
567 case MUIA_TextEditor_Contents
:
568 contents
= (char *)ti_Data
;
571 case MUIA_TextEditor_ImportHook
:
574 case MUIV_TextEditor_ImportHook_Plain
:
575 data
->ImportHook
= &ImPlainHook
;
577 case MUIV_TextEditor_ImportHook_EMail
:
578 data
->ImportHook
= &ImEMailHook
;
580 case MUIV_TextEditor_ImportHook_MIME
:
581 data
->ImportHook
= &ImMIMEHook
;
583 case MUIV_TextEditor_ImportHook_MIMEQuoted
:
584 data
->ImportHook
= &ImMIMEQuoteHook
;
587 data
->ImportHook
= (struct Hook
*)ti_Data
;
591 case MUIA_TextEditor_ImportWrap
:
592 data
->ImportWrap
= ti_Data
;
595 case MUIA_TextEditor_ExportHook
:
599 case MUIV_TextEditor_ExportHook_Plain
:
600 data
->ExportHook
= &ExportHookPlain
;
603 case MUIV_TextEditor_ExportHook_EMail
:
604 data
->ExportHook
= &ExportHookEMail
;
607 case MUIV_TextEditor_ExportHook_NoStyle
:
608 data
->ExportHook
= &ExportHookNoStyle
;
612 data
->ExportHook
= (struct Hook
*)ti_Data
;
617 case MUIA_TextEditor_ExportWrap
:
618 data
->ExportWrap
= ti_Data
;
621 case MUIA_TextEditor_Flow
:
624 LONG start
, lines
= 0;
626 data
->Flow
= ti_Data
;
629 struct marking newblock
;
630 struct line_node
*startline
;
632 NiceBlock(&data
->blockinfo
, &newblock
);
633 startline
= newblock
.startline
;
634 start
= LineToVisual(startline
, data
);
637 lines
+= startline
->visual
;
638 startline
->line
.Flow
= ti_Data
;
639 startline
= startline
->next
;
641 while(startline
!= newblock
.stopline
->next
);
645 start
= LineToVisual(data
->actualline
, data
);
646 lines
= data
->actualline
->visual
;
647 data
->actualline
->line
.Flow
= ti_Data
;
652 if(start
-1+lines
> data
->maxlines
)
653 lines
= data
->maxlines
-(start
-1);
654 DumpText(data
->visual_y
+start
-1, start
-1, start
-1+lines
, TRUE
, data
);
655 data
->HasChanged
= TRUE
;
659 case MUIA_TextEditor_WrapBorder
:
661 if(data
->WrapBorder
!= ti_Data
)
663 data
->WrapBorder
= ti_Data
;
669 case MUIA_TextEditor_WrapMode
:
671 if(data
->WrapMode
!= ti_Data
)
673 data
->WrapMode
= ti_Data
;
679 case MUIA_TextEditor_TypeAndSpell
:
680 data
->TypeAndSpell
= ti_Data
;
683 case MUIA_TextEditor_UndoLevels
:
684 ResizeUndoBuffer(data
, ti_Data
);
685 data
->userUndoSize
= TRUE
;
692 struct line_node
*newcontents
;
694 if((newcontents
= ImportText(contents
, data
, data
->ImportHook
, data
->ImportWrap
)))
696 FreeTextMem(data
->firstline
, data
);
697 data
->firstline
= newcontents
;
699 ResetUndoBuffer(data
);
704 if(crsr_x
!= 0xffff || crsr_y
!= 0xffff)
706 SetCursor(data
->CPos_X
, data
->actualline
, FALSE
, data
);
710 data
->actualline
= LineNode(crsr_y
+1, data
);
711 if(data
->actualline
->line
.Length
< data
->CPos_X
)
712 data
->CPos_X
= data
->actualline
->line
.Length
-1;
716 data
->CPos_X
= (data
->actualline
->line
.Length
> (ULONG
)crsr_x
) ? (UWORD
)crsr_x
: (UWORD
)data
->actualline
->line
.Length
-1;
719 ScrollIntoDisplay(data
);
720 SetCursor(data
->CPos_X
, data
->actualline
, TRUE
, data
);