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 #include <intuition/intuition.h>
24 #include <proto/exec.h>
25 #include <proto/graphics.h>
26 #include <proto/intuition.h>
31 #include "TextEditor_mcp.h"
34 IPTR
mBlockInfo(struct InstData
*data
, struct MUIP_TextEditor_BlockInfo
*msg
)
42 struct marking newblock
;
44 NiceBlock(&data
->blockinfo
, &newblock
);
45 *(msg
->startx
) = newblock
.startx
;
46 *(msg
->stopx
) = newblock
.stopx
;
47 *(msg
->starty
) = LineNr(data
, newblock
.startline
)-1;
48 *(msg
->stopy
) = LineNr(data
, newblock
.stopline
)-1;
59 IPTR
mQueryKeyAction(UNUSED
struct IClass
*cl
, Object
*obj
, struct MUIP_TextEditor_QueryKeyAction
*msg
)
61 struct te_key
*userkeys
;
62 struct te_key
*foundKey
= NULL
;
68 // now we try to retrieve the currently active
69 // key bindings, or we take the default ones
70 if(!DoMethod(obj
, MUIM_GetConfigItem
, MUICFG_TextEditor_Keybindings
, &setting
) || setting
== 0)
71 userkeys
= (struct te_key
*)default_keybindings
;
73 userkeys
= (struct te_key
*)setting
;
75 for(i
=0; (WORD
)userkeys
[i
].code
!= -1; i
++)
77 struct te_key
*curKey
= &userkeys
[i
];
79 if(curKey
->act
== msg
->keyAction
)
86 RETURN((IPTR
)foundKey
);
87 return (IPTR
)foundKey
;
92 IPTR
mMarkText(struct InstData
*data
, struct MUIP_TextEditor_MarkText
*msg
)
98 data
->blockinfo
.enabled
= FALSE
;
99 MarkText(data
, data
->blockinfo
.startx
, data
->blockinfo
.startline
, data
->blockinfo
.stopx
, data
->blockinfo
.stopline
);
103 SetCursor(data
, data
->CPos_X
, data
->actualline
, FALSE
);
106 // check if anything at all should be marked or not
107 if((LONG
)msg
->start_crsr_y
!= MUIV_TextEditor_MarkText_None
)
109 // check if only the specified area should be marked/selected
110 if((LONG
)msg
->stop_crsr_y
!= MUIV_TextEditor_MarkText_All
)
112 data
->blockinfo
.startline
= LineNode(data
, msg
->start_crsr_y
+1);
113 data
->blockinfo
.startx
= (data
->blockinfo
.startline
->line
.Length
> msg
->start_crsr_x
) ? msg
->start_crsr_x
: data
->blockinfo
.startline
->line
.Length
-1;
114 data
->blockinfo
.stopline
= LineNode(data
, msg
->stop_crsr_y
+1);
115 data
->blockinfo
.stopx
= (data
->blockinfo
.stopline
->line
.Length
> msg
->stop_crsr_x
) ? msg
->stop_crsr_x
: data
->blockinfo
.stopline
->line
.Length
-1;
116 data
->blockinfo
.enabled
= TRUE
;
118 data
->actualline
= data
->blockinfo
.stopline
;
119 data
->CPos_X
= data
->blockinfo
.stopx
;
120 ScrollIntoDisplay(data
);
124 // the user selected to mark all available text
125 MarkAllBlock(data
, &data
->blockinfo
);
128 MarkText(data
, data
->blockinfo
.startx
, data
->blockinfo
.startline
, data
->blockinfo
.stopx
, data
->blockinfo
.stopline
);
137 IPTR
mClearText(struct IClass
*cl
, Object
*obj
, UNUSED Msg msg
)
139 struct InstData
*data
= INST_DATA(cl
, obj
);
140 struct line_node
*newcontents
;
144 if((newcontents
= AllocVecPooled(data
->mypool
, sizeof(struct line_node
))) != NULL
)
146 if(Init_LineNode(data
, newcontents
, "\n") == TRUE
)
148 if(isFlagClear(data
->flags
, FLG_ReadOnly
) && data
->maxUndoSteps
!= 0)
150 struct marking newblock
;
152 MarkAllBlock(data
, &newblock
);
155 data
->actualline
= GetFirstLine(&data
->linelist
);
157 // add the text to the undo buffer only if we really have some text
158 // i.e. the block contains at least some characters or some lines
159 if(newblock
.startline
!= newblock
.stopline
|| newblock
.startx
< newblock
.stopx
)
160 AddToUndoBuffer(data
, ET_DELETEBLOCK_NOMOVE
, &newblock
);
162 FreeTextMem(data
, &data
->linelist
);
163 AddLine(&data
->linelist
, newcontents
);
168 FreeVecPooled(data
->mypool
, newcontents
);
178 IPTR
mToggleCursor(struct IClass
*cl
, Object
*obj
, UNUSED Msg msg
)
180 struct InstData
*data
= INST_DATA(cl
, obj
);
184 if(isFlagSet(data
->flags
, FLG_Active
))
186 if(data
->cursor_shown
== TRUE
)
188 SetCursor(data
, data
->CPos_X
, data
->actualline
, FALSE
);
189 data
->cursor_shown
= FALSE
;
193 SetCursor(data
, data
->CPos_X
, data
->actualline
, TRUE
);
194 data
->cursor_shown
= TRUE
;
204 IPTR
mInputTrigger(struct IClass
*cl
, Object
*obj
, UNUSED Msg msg
)
206 struct InstData
*data
= INST_DATA(cl
, obj
);
210 if(data
->smooth_wait
== 1 && data
->scrollaction
== TRUE
)
212 if(data
->ypos
!= _mtop(obj
))
216 if(data
->scr_direction
)
217 move
= data
->fontheight
-(_mtop(obj
)-data
->ypos
);
219 move
= -(_mtop(obj
)-data
->ypos
);
221 if(move
!= 1 && move
!= -1)
224 set(obj
, MUIA_TextEditor_Prop_First
, (data
->visual_y
-1)*data
->fontheight
+(_mtop(obj
)-data
->ypos
)+move
);
228 data
->scrollaction
= FALSE
;
231 if(isFlagSet(data
->flags
, FLG_Active
))
233 SetCursor(data
, data
->CPos_X
, data
->actualline
, TRUE
);
238 if(data
->mousemove
== TRUE
)
240 LONG MouseX
= _window(obj
)->MouseX
;
241 LONG MouseY
= _window(obj
)->MouseY
;
242 LONG oldCPos_X
= data
->CPos_X
;
243 struct line_node
*oldactualline
= data
->actualline
;
246 if(xget(_win(obj
), MUIA_Window_Activate
) == FALSE
)
248 data
->mousemove
= FALSE
;
255 if(MouseY
< data
->ypos
)
257 LONG diff
= data
->ypos
- MouseY
;
270 LONG limit
= data
->ypos
;
272 if(data
->maxlines
< (data
->totallines
-data
->visual_y
+1))
273 limit
+= (data
->maxlines
* data
->fontheight
);
275 limit
+= (data
->totallines
-data
->visual_y
+1)*data
->fontheight
;
279 LONG diff
= MouseY
- limit
;
292 PosFromCursor(data
, MouseX
, MouseY
);
297 if(data
->blockinfo
.enabled
== TRUE
&& scroll
== TRUE
&& data
->blockinfo
.stopline
== data
->actualline
&& data
->blockinfo
.stopx
== data
->CPos_X
)
299 PosFromCursor(data
, MouseX
, MouseY
);
302 if(data
->selectmode
!= 0)
304 struct marking tmpblock
;
306 NiceBlock(&data
->blockinfo
, &tmpblock
);
307 if(data
->blockinfo
.startx
== tmpblock
.startx
&& data
->blockinfo
.startline
== tmpblock
.startline
)
309 if(MouseX
> _mleft(obj
))
311 if(data
->selectmode
== 1)
313 while(data
->CPos_X
< data
->actualline
->line
.Length
-1 && CheckSep(data
, data
->actualline
->line
.Contents
[data
->CPos_X
]) == FALSE
)
314 // while((data->CPos_X < data->actualline->line.Length-1) && (data->actualline->line.Contents[data->CPos_X] != ' '))
328 OffsetToLines(data
, data
->CPos_X
, data
->actualline
, &pos
);
329 flow
= FlowSpace(data
, data
->actualline
->line
.Flow
, &data
->actualline
->line
.Contents
[pos
.bytes
]);
331 if(MouseX
<= _mleft(obj
)+flow
+TextLengthNew(&data
->tmprp
, &data
->actualline
->line
.Contents
[pos
.bytes
], pos
.extra
-pos
.bytes
-1, data
->TabSizePixels
))
333 if(data
->selectmode
== 1)
335 while(data
->CPos_X
> 0 && CheckSep(data
, data
->actualline
->line
.Contents
[data
->CPos_X
-1]) == FALSE
)
336 // while(data->CPos_X > 0 && data->actualline->line.Contents[data->CPos_X-1] != ' ')
347 if(data
->blockinfo
.enabled
== TRUE
|| data
->selectmode
== 0)
349 // if selectmode == 2, then the user has trippleclicked at the line
350 // and wants to get the whole line marked
351 if(data
->selectmode
== 2 || data
->selectmode
== 3)
353 data
->selectmode
= 2;
355 // if the line is a hard wrapped one we have to increase CPos_X by one
356 if(data
->actualline
->line
.Contents
[data
->CPos_X
] > ' ')
359 MarkText(data
, data
->blockinfo
.stopx
, data
->blockinfo
.stopline
, data
->CPos_X
, data
->actualline
);
362 MarkText(data
, data
->blockinfo
.stopx
, data
->blockinfo
.stopline
, data
->CPos_X
+1, data
->actualline
);
364 data
->selectmode
= 3;
366 else if(data
->blockinfo
.stopline
!= data
->actualline
|| data
->blockinfo
.stopx
!= data
->CPos_X
)
368 data
->blockinfo
.enabled
= TRUE
;
369 MarkText(data
, data
->blockinfo
.stopx
, data
->blockinfo
.stopline
, data
->CPos_X
, data
->actualline
);
372 data
->blockinfo
.stopline
= data
->actualline
;
373 data
->blockinfo
.stopx
= data
->CPos_X
;
377 data
->mousemove
= FALSE
;
381 if(oldCPos_X
!= data
->CPos_X
|| oldactualline
!= data
->actualline
)
383 ScrollIntoDisplay(data
);
384 PosFromCursor(data
, MouseX
, MouseY
);
386 // make sure to notify others that the cursor has changed and so on.
387 data
->NoNotify
= TRUE
;
389 if(data
->CPos_X
!= oldCPos_X
)
390 set(obj
, MUIA_TextEditor_CursorX
, data
->CPos_X
);
392 if(data
->actualline
!= oldactualline
)
393 set(obj
, MUIA_TextEditor_CursorY
, LineNr(data
, data
->actualline
)-1);
395 data
->NoNotify
= FALSE
;
405 ULONG
InsertText(struct InstData
*data
, STRPTR text
, BOOL moveCursor
)
407 struct MinList newlines
;
408 struct line_node
*actline
= data
->actualline
;
409 LONG x
= data
->CPos_X
;
414 if(ImportText(data
, text
, data
->ImportHook
, data
->ImportWrap
, &newlines
) == TRUE
)
416 BOOL oneline
= FALSE
;
417 BOOL newline
= FALSE
;
418 struct line_node
*line
;
421 data
->totallines
+= CountLines(data
, &newlines
);
423 line
= GetLastLine(&newlines
);
424 if(line
->line
.Contents
[line
->line
.Length
] == '\n')
427 data
->update
= FALSE
;
428 SplitLine(data
, x
, actline
, FALSE
, NULL
);
429 InsertLines(&newlines
, actline
);
430 data
->CPos_X
= line
->line
.Length
-1;
431 if(GetNextLine(actline
) == line
)
433 data
->CPos_X
+= actline
->line
.Length
-1;
437 MergeLines(data
, line
);
438 MergeLines(data
, actline
);
443 line
= GetNextLine(line
);
446 if(moveCursor
== TRUE
)
448 data
->actualline
= line
;
452 realx
= data
->CPos_X
;
457 ScrollIntoDisplay(data
);
459 tvisual_y
= LineToVisual(data
, actline
)-1;
463 if(isFlagClear(data
->flags
, FLG_Quiet
))
465 SetCursor(data
, data
->CPos_X
, line
, FALSE
);
466 if(data
->blockinfo
.enabled
== TRUE
)
468 data
->blockinfo
.enabled
= FALSE
;
469 MarkText(data
, data
->blockinfo
.startx
, data
->blockinfo
.startline
, data
->blockinfo
.stopx
, data
->blockinfo
.stopline
);
471 DumpText(data
, data
->visual_y
+tvisual_y
, tvisual_y
, data
->maxlines
, TRUE
);
475 data
->blockinfo
.enabled
= FALSE
;
478 if(moveCursor
== FALSE
)
480 data
->CPos_X
= realx
;
481 data
->actualline
= line
;