grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / classes / zune / texteditor / mcc / Navigation.c
blobdbb0340f9d59365fdbb3dd351cb92444c5022690
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 <clib/alib_protos.h>
24 #include <proto/graphics.h>
25 #include <proto/intuition.h>
26 #include <proto/locale.h>
28 #include "private.h"
29 #include "Debug.h"
31 struct pos_info pos;
33 /// FlowSpace()
34 LONG FlowSpace(struct InstData *data, UWORD flow, STRPTR text)
36 LONG flowspace = 0;
38 ENTER();
40 if(flow != MUIV_TextEditor_Flow_Left)
42 flowspace = (_mwidth(data->object)-TextLengthNew(&data->tmprp, text, LineCharsWidth(data, text)-1, data->TabSizePixels));
43 flowspace -= (data->CursorWidth == 6) ? TextLength(&data->tmprp, " ", 1) : data->CursorWidth;
44 if(flow == MUIV_TextEditor_Flow_Center)
46 flowspace /= 2;
50 RETURN(flowspace);
51 return flowspace;
54 ///
55 /// CursorOffset()
56 static LONG CursorOffset(struct InstData *data)
58 struct line_node *line = data->actualline;
59 STRPTR text = &line->line.Contents[data->CPos_X];
60 LONG res=0;
61 LONG lineCharsWidth;
63 ENTER();
65 // call TextFitNew() to find out how many chars would fit.
66 if((lineCharsWidth = LineCharsWidth(data, text)) > 0)
68 struct TextExtent tExtend;
69 LONG offset = data->pixel_x-FlowSpace(data, line->line.Flow, text);
71 if(offset < 1)
72 offset = 1;
74 res = TextFitNew(&data->tmprp, text, lineCharsWidth, &tExtend, NULL, 1, offset, data->font->tf_YSize, data->TabSizePixels);
76 // in case of a hard-wrapped line we have to deal with
77 // the possibility that the user tries to
78 // select the last char in a line which should normally by a white space
79 // due to soft-wrapping. So in this case we have to lower res by one so
80 // that it is not possible to select that last white space. However, for
81 // a hard wrapped line it still have to be possible to select that last char.
82 if(lineCharsWidth-res == 0 && text[lineCharsWidth-1] <= ' ')
83 res--;
86 RETURN(res);
87 return res;
90 ///
91 /// GetPosInPixels()
92 /*---------------------------------------*
93 * Return the number of pixels to cursor *
94 *---------------------------------------*/
95 static LONG GetPosInPixels(struct InstData *data, LONG bytes, LONG x)
97 LONG pos;
99 ENTER();
101 pos = TextLengthNew(&data->tmprp, &data->actualline->line.Contents[bytes], x, data->TabSizePixels);
103 if(data->actualline->line.Contents[data->CPos_X] == '\n')
104 pos += TextLength(&data->tmprp, " ", 1)/2;
105 else
106 pos += TextLengthNew(&data->tmprp, &data->actualline->line.Contents[data->CPos_X], 1, data->TabSizePixels)/2;
108 pos += FlowSpace(data, data->actualline->line.Flow, &data->actualline->line.Contents[bytes]);
110 RETURN(pos);
111 return(pos);
115 /// SetBookmark()
116 void SetBookmark(struct InstData *data, ULONG nr)
118 ENTER();
120 if(nr < ARRAY_SIZE(data->bookmarks))
122 data->bookmarks[nr].line = data->actualline;
123 data->bookmarks[nr].x = data->CPos_X;
126 LEAVE();
130 /// GotoBookmark()
131 void GotoBookmark(struct InstData *data, ULONG nr)
133 ENTER();
135 if(nr < ARRAY_SIZE(data->bookmarks))
137 if(data->bookmarks[nr].line)
139 struct line_node *actual = GetFirstLine(&data->linelist);
141 while(actual != NULL)
143 if(actual == data->bookmarks[nr].line)
145 data->actualline = actual;
146 data->CPos_X = data->bookmarks[nr].x;
147 if(data->CPos_X >= actual->line.Length)
148 data->CPos_X = actual->line.Length-1;
149 break;
151 actual = GetNextLine(actual);
153 if(actual == NULL)
155 DoMethod(data->object, MUIM_TextEditor_HandleError, Error_BookmarkHasBeenLost);
158 else
160 DoMethod(data->object, MUIM_TextEditor_HandleError, Error_NoBookmarkInstalled);
164 LEAVE();
168 /// GoTop()
169 /*---- CursorUp ---- */
170 void GoTop(struct InstData *data)
172 ENTER();
174 data->actualline = GetFirstLine(&data->linelist);
175 data->CPos_X = 0;
177 LEAVE();
181 /// GoPreviousLine()
182 void GoPreviousLine(struct InstData *data)
184 ENTER();
186 if(data->CPos_X == 0 && HasPrevLine(data->actualline) == TRUE)
187 data->actualline = GetPrevLine(data->actualline);
188 data->CPos_X = 0;
190 LEAVE();
194 /// GoPreviousPage()
195 void GoPreviousPage(struct InstData *data)
197 ENTER();
199 if(data->shown == TRUE)
201 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
202 if(data->pixel_x == 0)
203 data->pixel_x = GetPosInPixels(data, pos.bytes, pos.x);
204 if(!(HasPrevLine(data->actualline) == FALSE && pos.lines == 1))
206 LONG lineplacement;
207 LONG linemove = data->maxlines;
208 struct line_node *prev;
210 lineplacement = LineToVisual(data, data->actualline)+pos.lines-1;
211 if(lineplacement != 1)
212 linemove = lineplacement-1;
213 linemove -= pos.lines-1;
215 while(linemove != 0 && (prev = GetPrevLine(data->actualline)) != NULL && prev->visual <= linemove)
217 data->actualline = prev;
218 linemove -= data->actualline->visual;
220 data->CPos_X = 0;
221 if(linemove != 0 && HasPrevLine(data->actualline) == TRUE)
223 if(linemove > 0)
225 data->actualline = GetPrevLine(data->actualline);
226 linemove = data->actualline->visual-linemove;
228 else
230 linemove = -linemove;
232 while(linemove--)
234 data->CPos_X += LineCharsWidth(data, &data->actualline->line.Contents[data->CPos_X]);
237 data->CPos_X += CursorOffset(data);
239 else
241 GoTop(data);
245 LEAVE();
249 /// GoUp()
250 void GoUp(struct InstData *data)
252 ENTER();
254 if(data->shown == TRUE)
256 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
257 if(data->pixel_x == 0)
259 data->pixel_x = GetPosInPixels(data, pos.bytes, pos.x);
261 if(pos.lines == 1)
263 if(HasPrevLine(data->actualline) == TRUE)
265 data->actualline = GetPrevLine(data->actualline);
266 pos.lines = data->actualline->visual+1;
268 else
270 // data->CPos_X = 0;
271 LEAVE();
272 return;
275 data->CPos_X = 0;
276 if(--pos.lines)
278 while(--pos.lines)
280 data->CPos_X += LineCharsWidth(data, &data->actualline->line.Contents[data->CPos_X]);
282 data->CPos_X += CursorOffset(data);
284 else
285 DisplayBeep(NULL);
288 LEAVE();
292 /// GoBottom()
293 /*---- CursorDown ---- */
294 void GoBottom(struct InstData *data)
296 ENTER();
298 data->actualline = GetLastLine(&data->linelist);
299 data->CPos_X = data->actualline->line.Length-1;
301 LEAVE();
305 /// GoNextLine()
306 void GoNextLine(struct InstData *data)
308 ENTER();
310 data->CPos_X = 0;
311 if(HasNextLine(data->actualline) == TRUE)
312 data->actualline = GetNextLine(data->actualline);
313 else
314 data->CPos_X = data->actualline->line.Length-1;
316 LEAVE();
320 /// GoNextPage()
321 void GoNextPage(struct InstData *data)
323 ENTER();
325 if(data->shown == TRUE)
327 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
328 if(data->pixel_x == 0)
329 data->pixel_x = GetPosInPixels(data, pos.bytes, pos.x);
330 if(!(HasNextLine(data->actualline) == FALSE&& pos.lines == data->actualline->visual))
332 LONG lineplacement;
333 LONG linemove = data->maxlines;
335 lineplacement = LineToVisual(data, data->actualline)+pos.lines-1;
336 if(lineplacement != data->maxlines)
337 linemove = data->maxlines - lineplacement;
339 linemove += pos.lines-1;
340 while(linemove != 0 && HasNextLine(data->actualline) == TRUE && data->actualline->visual <= linemove)
342 linemove -= data->actualline->visual;
343 NextLine(data);
345 if(data->actualline->visual <= linemove)
346 linemove = data->actualline->visual-1;
347 data->CPos_X = 0;
348 while(linemove--)
350 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
351 data->CPos_X = pos.extra;
353 data->CPos_X += CursorOffset(data);
355 else
357 GoBottom(data);
361 LEAVE();
365 /// GoDown()
366 void GoDown (struct InstData *data)
368 ENTER();
370 if(data->shown == TRUE)
372 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
373 if(data->pixel_x == 0)
375 data->pixel_x = GetPosInPixels(data, pos.bytes, pos.x);
378 if(pos.lines == data->actualline->visual)
380 struct line_node *next = GetNextLine(data->actualline);
382 if(next != NULL)
384 pos.lines = 0;
385 data->actualline = next;
386 data->CPos_X = 0;
387 data->CPos_X += CursorOffset(data);
389 else
391 // data->CPos_X = data->actualline->line.Length-1;
394 else
396 data->CPos_X = pos.extra;
397 data->CPos_X += CursorOffset(data);
401 LEAVE();
405 /// GoEndOfLine()
406 /*---- CursorRight ---- */
407 void GoEndOfLine(struct InstData *data)
409 ENTER();
411 if(data->shown == TRUE)
413 LONG c;
415 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
417 if((c = LineCharsWidth(data, &data->actualline->line.Contents[pos.bytes])) > 0)
418 data->CPos_X = pos.bytes + c - 1;
419 else
420 data->CPos_X = pos.bytes;
423 LEAVE();
427 /// GoNextWord()
428 void GoNextWord(struct InstData *data)
430 ENTER();
432 while(data->CPos_X < data->actualline->line.Length && CheckSep(data, data->actualline->line.Contents[data->CPos_X]) == FALSE)
433 data->CPos_X++;
435 FindNextWord:
437 while(data->CPos_X < data->actualline->line.Length && CheckSep(data, data->actualline->line.Contents[data->CPos_X]) == TRUE)
438 data->CPos_X++;
440 if(data->CPos_X == data->actualline->line.Length)
442 struct line_node *next = GetNextLine(data->actualline);
444 if(next != NULL)
446 data->actualline = next;
447 data->CPos_X = 0;
448 goto FindNextWord;
450 else
451 data->CPos_X--;
454 LEAVE();
458 /// GoNextSentence()
459 void GoNextSentence(struct InstData *data)
461 ENTER();
463 while(data->CPos_X < data->actualline->line.Length && CheckSent(data, data->actualline->line.Contents[data->CPos_X]) == FALSE)
464 data->CPos_X++;
465 while(data->CPos_X < data->actualline->line.Length && CheckSent(data, data->actualline->line.Contents[data->CPos_X]) == TRUE)
466 data->CPos_X++;
467 if(data->CPos_X >= data->actualline->line.Length-1)
468 NextLine(data);
469 else
471 while(data->CPos_X < data->actualline->line.Length && data->actualline->line.Contents[data->CPos_X] == ' ')
472 data->CPos_X++;
473 if(data->CPos_X == data->actualline->line.Length-1)
474 NextLine(data);
477 LEAVE();
481 /// GoRight()
482 void GoRight(struct InstData *data)
484 ENTER();
486 if(data->CPos_X+1 < data->actualline->line.Length)
487 data->CPos_X++;
488 else
489 NextLine(data);
491 LEAVE();
495 /// GoStartOfLine()
496 void GoStartOfLine(struct InstData *data)
498 ENTER();
500 if(data->shown == TRUE)
502 OffsetToLines(data, data->CPos_X, data->actualline, &pos);
503 data->CPos_X = pos.bytes;
506 LEAVE();
510 /// GoPreviousWord()
511 void GoPreviousWord(struct InstData *data)
513 BOOL moved = FALSE;
514 struct line_node *prev;
516 ENTER();
518 FindWord:
520 if(data->CPos_X > 0 && CheckSep(data, data->actualline->line.Contents[data->CPos_X-1]) == TRUE)
522 data->CPos_X--;
523 moved = TRUE;
525 while(data->CPos_X > 0 && CheckSep(data, data->actualline->line.Contents[data->CPos_X]) == TRUE)
527 data->CPos_X--;
528 moved = TRUE;
530 prev = GetPrevLine(data->actualline);
531 if(data->CPos_X == 0 && prev != NULL && (moved == FALSE || CheckSep(data, data->actualline->line.Contents[0]) == TRUE))
533 data->actualline = prev;
534 data->CPos_X = data->actualline->line.Length-1;
535 goto FindWord;
538 while(data->CPos_X > 0 && CheckSep(data, data->actualline->line.Contents[data->CPos_X-1]) == FALSE)
539 data->CPos_X--;
541 LEAVE();
545 /// GoPreviousSentence()
546 void GoPreviousSentence(struct InstData *data)
548 struct line_node *prev;
550 ENTER();
552 prev = GetPrevLine(data->actualline);
553 while(data->CPos_X == 0 && prev != NULL)
555 data->actualline = prev;
556 data->CPos_X = data->actualline->line.Length-1;
557 prev = GetPrevLine(prev);
559 if(data->CPos_X != 0)
561 data->CPos_X--;
562 while(data->CPos_X > 0 && data->actualline->line.Contents[data->CPos_X] == ' ')
563 data->CPos_X--;
564 while(data->CPos_X > 0 && CheckSent(data, data->actualline->line.Contents[data->CPos_X]) == TRUE)
565 data->CPos_X--;
566 while(data->CPos_X > 0 && CheckSent(data, data->actualline->line.Contents[data->CPos_X]) == FALSE)
567 data->CPos_X--;
568 if(data->CPos_X > 0)
570 data->CPos_X++;
571 while(data->CPos_X < data->actualline->line.Length && data->actualline->line.Contents[data->CPos_X] == ' ')
572 data->CPos_X++;
576 LEAVE();
580 /// GoLeft()
581 void GoLeft(struct InstData *data)
583 ENTER();
585 if(data->CPos_X > 0)
586 data->CPos_X--;
587 else
589 struct line_node *prev = GetPrevLine(data->actualline);
591 if(prev != NULL)
593 data->actualline = prev;
594 data->CPos_X = data->actualline->line.Length-1;
598 LEAVE();
602 /// CheckSep()
603 /*-----------------------------------------*
604 * Check if given char is a word-seperator *
605 *-----------------------------------------*/
606 BOOL CheckSep(struct InstData *data, char character)
608 BOOL isSep = FALSE;
610 ENTER();
612 if(!IsAlNum(data->mylocale, (long)character))
613 isSep = TRUE;
615 RETURN(isSep);
616 return isSep;
620 /// CheckSent()
621 /*-----------------------------------------*
622 * Check if given char is a sentence ender *
623 *-----------------------------------------*/
624 BOOL CheckSent(UNUSED struct InstData *data, char character)
626 BOOL isSent = FALSE;
628 ENTER();
630 if(character == '.' || character == '!' || character == '?')
631 isSent = TRUE;
633 RETURN(isSent);
634 return isSent;
638 /// NextLine()
639 /*-----------------------------------*
640 * Move cursor to start of next line *
641 *-----------------------------------*/
642 void NextLine(struct InstData *data)
644 struct line_node *next;
646 ENTER();
648 next = GetNextLine(data->actualline);
649 if(next != NULL)
651 data->actualline = next;
652 data->CPos_X = 0;
654 else
656 data->CPos_X = data->actualline->line.Length-1;
659 LEAVE();
663 /// PosFromCursor()
664 /*-----------------------------------------*
665 * Place the cursor, based on an X Y coord *
666 *-----------------------------------------*/
667 void PosFromCursor(struct InstData *data, LONG MouseX, LONG MouseY)
669 struct pos_info pos;
670 LONG limit = data->ypos;
672 ENTER();
674 if(data->maxlines < data->totallines-data->visual_y+1)
675 limit += (data->maxlines * data->fontheight);
676 else
677 limit += (data->totallines-data->visual_y+1)*data->fontheight;
679 if(MouseY >= limit)
680 MouseY = limit-1;
682 GetLine(data, ((MouseY - data->ypos)/data->fontheight) + data->visual_y, &pos);
684 data->actualline = pos.line;
686 data->pixel_x = MouseX-_mleft(data->object)+1;
688 if(data->pixel_x < 1)
689 data->pixel_x = 1;
691 data->CPos_X = pos.x;
692 data->CPos_X += CursorOffset(data);
693 data->pixel_x = 0;
695 LEAVE();