fltk  1.3.5-source
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X.
  Fossies Dox: fltk-1.3.5-source.tar.bz2  ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Text_Display.cxx
Go to the documentation of this file.
1 //
2 // "$Id$"
3 //
4 // Copyright 2001-2016 by Bill Spitzak and others.
5 // Original code Copyright Mark Edel. Permission to distribute under
6 // the LGPL for the FLTK library granted by Mark Edel.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file. If this
10 // file is missing or damaged, see the license at:
11 //
12 // http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 // http://www.fltk.org/str.php
17 //
18 
19 // TODO: rendering of the "optional hyphen"
20 // TODO: font background color control via style buffer
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <FL/fl_utf8.h>
25 #include "flstring.h"
26 #include <limits.h>
27 #include <ctype.h>
28 #include <string.h> // strdup()
29 #include <FL/Fl.H>
30 #include <FL/Fl_Text_Buffer.H>
31 #include <FL/Fl_Text_Display.H>
32 #include <FL/Fl_Window.H>
33 
34 #undef min
35 #undef max
36 
37 // #define DEBUG
38 // #define DEBUG2
39 
40 #define LINENUM_LEFT_OF_VSCROLL // uncomment this line ...
41 // ... if you want the line numbers to be drawn left of the vertical
42 // scrollbar (only if the vertical scrollbar is aligned left).
43 // This is the default.
44 // If not defined and the vertical scrollbar is aligned left, then the
45 // scrollbar is positioned at the left border and the line numbers are
46 // drawn between the scrollbar (left) and the text area (right).
47 // If the vertical scrollbar is aligned right, then the line number
48 // position is not affected by this definition.
49 
50 // Text area margins. Left & right margins should be at least 3 so that
51 // there is some room for the overhanging parts of the cursor!
52 #define TOP_MARGIN 1
53 #define BOTTOM_MARGIN 1
54 #define LEFT_MARGIN 3
55 #define RIGHT_MARGIN 3
56 
57 #define NO_HINT -1
58 
59 /* Masks for text drawing methods. These are or'd together to form an
60  integer which describes what drawing calls to use to draw a string */
61 #define FILL_MASK 0x0100
62 #define SECONDARY_MASK 0x0200
63 #define PRIMARY_MASK 0x0400
64 #define HIGHLIGHT_MASK 0x0800
65 #define BG_ONLY_MASK 0x1000
66 #define TEXT_ONLY_MASK 0x2000
67 #define STYLE_LOOKUP_MASK 0xff
68 
69 /* Maximum displayable line length (how many characters will fit across the
70  widest window). This amount of memory is temporarily allocated from the
71  stack in the draw_vline() method for drawing strings */
72 #define MAX_DISP_LINE_LEN 1000
73 
74 static int max( int i1, int i2 );
75 static int min( int i1, int i2 );
76 static int countlines( const char *string );
77 
78 /* The variables below are used in a timer event to allow smooth
79  scrolling of the text area when the pointer has left the area. */
80 static int scroll_direction = 0;
81 static int scroll_amount = 0;
82 static int scroll_y = 0;
83 static int scroll_x = 0;
84 
85 // CET - FIXME
86 #define TMPFONTWIDTH 6
87 
88 
89 
96 Fl_Text_Display::Fl_Text_Display(int X, int Y, int W, int H, const char* l)
97 : Fl_Group(X, Y, W, H, l) {
98  int i;
99 
100  mMaxsize = 0;
103  dragPos = dragging = 0;
106  shortcut_ = 0;
107 
114 
115  text_area.x = 0;
116  text_area.y = 0;
117  text_area.w = 0;
118  text_area.h = 0;
119 
120  mVScrollBar = new Fl_Scrollbar(0,0,1,1);
122  mHScrollBar = new Fl_Scrollbar(0,0,1,1);
125 
126  end();
127 
130 
131  mCursorOn = 0;
132  mCursorPos = 0;
133  mCursorOldY = -100;
137  mBuffer = 0;
138  mFirstChar = 0;
139  mLastChar = 0;
140  mNBufferLines = 0;
142  mAbsTopLineNum = 1;
143  mNeedAbsTopLineNum = 0;
145 
147 
148  mStyleBuffer = 0;
149  mStyleTable = 0;
150  mNStyles = 0;
151  mNVisibleLines = 1;
152  mLineStarts = new int[mNVisibleLines];
153  mLineStarts[0] = 0;
154  for (i=1; i<mNVisibleLines; i++)
155  mLineStarts[i] = -1;
156  mSuppressResync = 0;
157  mNLinesDeleted = 0;
159 
160  mUnfinishedStyle = 0;
162  mHighlightCBArg = 0;
163 
165  mContinuousWrap = 0;
166  mWrapMarginPix = 0;
168 #if FLTK_ABI_VERSION >= 10303
169  linenumber_font_ = FL_HELVETICA;
170  linenumber_size_ = FL_NORMAL_SIZE;
171  linenumber_fgcolor_ = FL_INACTIVE_COLOR;
172  linenumber_bgcolor_ = 53; // ~90% gray
173  linenumber_align_ = FL_ALIGN_RIGHT;
174  linenumber_format_ = strdup("%d");
175 #endif
176 }
177 
178 
179 
187  if (scroll_direction) {
189  scroll_direction = 0;
190  }
191  if (mBuffer) {
194  }
195  if (mLineStarts) delete[] mLineStarts;
196 #if FLTK_ABI_VERSION >= 10303
197  if (linenumber_format_) {
198  free((void*)linenumber_format_);
199  linenumber_format_ = 0;
200  }
201 #endif
202 }
203 
204 
213  if (width < 0) return;
214  mLineNumWidth = width;
215  resize(x(), y(), w(), h()); // triggers code to recalculate line#s
216 }
217 
222  return mLineNumWidth;
223 }
224 
230 #if FLTK_ABI_VERSION >= 10303
231  linenumber_font_ = val;
232 #else
233  // do nothing
234 #endif
235 }
236 
241 #if FLTK_ABI_VERSION >= 10303
242  return linenumber_font_;
243 #else
244  return FL_HELVETICA;
245 #endif
246 }
247 
253 #if FLTK_ABI_VERSION >= 10303
254  linenumber_size_ = val;
255 #else
256  // do nothing
257 #endif
258 }
259 
264 #if FLTK_ABI_VERSION >= 10303
265  return linenumber_size_;
266 #else
267  return FL_NORMAL_SIZE;
268 #endif
269 }
270 
276 #if FLTK_ABI_VERSION >= 10303
277  linenumber_fgcolor_ = val;
278 #else
279  // do nothing
280 #endif
281 }
282 
287 #if FLTK_ABI_VERSION >= 10303
288  return linenumber_fgcolor_;
289 #else
290  return FL_INACTIVE_COLOR;
291 #endif
292 }
293 
299 #if FLTK_ABI_VERSION >= 10303
300  linenumber_bgcolor_ = val;
301 #else
302  // do nothing
303 #endif
304 }
305 
310 #if FLTK_ABI_VERSION >= 10303
311  return linenumber_bgcolor_;
312 #else
313  return 53; // hard coded ~90% gray
314 #endif
315 }
316 
323 #if FLTK_ABI_VERSION >= 10303
324  linenumber_align_ = val;
325 #else
326  // do nothing
327 #endif
328 }
329 
334 #if FLTK_ABI_VERSION >= 10303
335  return linenumber_align_;
336 #else
337  return FL_ALIGN_RIGHT;
338 #endif
339 }
340 
360 void Fl_Text_Display::linenumber_format(const char* val) {
361 #if FLTK_ABI_VERSION >= 10303
362  if ( linenumber_format_ ) free((void*)linenumber_format_);
363  linenumber_format_ = val ? strdup(val) : 0;
364 #else
365  // do nothing
366 #endif
367 }
368 
373 #if FLTK_ABI_VERSION >= 10303
374  return linenumber_format_;
375 #else
376  return "%d";
377 #endif
378 }
379 
385  /* If the text display is already displaying a buffer, clear it off
386  of the display and remove our callback from it */
387  if ( buf == mBuffer) return;
388  if ( mBuffer != 0 ) {
389  // we must provide a copy of the buffer that we are deleting!
390  char *deletedText = mBuffer->text();
391  buffer_modified_cb( 0, 0, mBuffer->length(), 0, deletedText, this );
392  free(deletedText);
393  mNBufferLines = 0;
396  }
397 
398  /* Add the buffer to the display, and attach a callback to the buffer for
399  receiving modification information when the buffer contents change */
400  mBuffer = buf;
401  if (mBuffer) {
404 
405  /* Update the display */
406  buffer_modified_cb( 0, buf->length(), 0, 0, 0, this );
407  }
408 
409  /* Resize the widget to update the screen... */
410  resize(x(), y(), w(), h());
411 }
412 
413 
414 
443  const Style_Table_Entry *styleTable,
444  int nStyles, char unfinishedStyle,
445  Unfinished_Style_Cb unfinishedHighlightCB,
446  void *cbArg ) {
447  mStyleBuffer = styleBuffer;
448  mStyleTable = styleTable;
449  mNStyles = nStyles;
450  mUnfinishedStyle = unfinishedStyle;
451  mUnfinishedHighlightCB = unfinishedHighlightCB;
452  mHighlightCBArg = cbArg;
453  mColumnScale = 0;
454 
455  mStyleBuffer->canUndo(0);
457 }
458 
459 
460 
466  int longest = 0;
467  for (int i = 0; i < mNVisibleLines; i++)
468  longest = max(longest, measure_vline(i));
469  return longest;
470 }
471 
472 
473 
480 void Fl_Text_Display::resize(int X, int Y, int W, int H) {
481 
482 #ifdef DEBUG2
483  printf("\n");
484  printf("Fl_Text_Display::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H);
485  printf(" current size(x=%d, y=%d, w=%d, h=%d)\n", x(), y(), w(), h());
486  printf(" box_d* size(x=%d, y=%d, w=%d, h=%d)\n",
488  printf(" text_area size(x=%d, y=%d, w=%d, h=%d)\n",
490  printf(" mContinuousWrap=%d, mWrapMarginPix=%d\n",
492  fflush(stdout);
493 #endif // DEBUG2
494 
495  Fl_Widget::resize(X,Y,W,H);
496  if (!buffer()) return;
497 
498  // did we have scrollbars initially?
499  unsigned int hscrollbarvisible = mHScrollBar->visible();
500  unsigned int vscrollbarvisible = mVScrollBar->visible();
501 
502  int oldTAWidth = text_area.w;
503 
504  X += Fl::box_dx(box());
505  Y += Fl::box_dy(box());
506  W -= Fl::box_dw(box());
507  H -= Fl::box_dh(box());
508 
510  text_area.y = Y + TOP_MARGIN;
513 
514  // Find the new maximum font height for this text display
515  int i;
516  for (i = 0, mMaxsize = fl_height(textfont(), textsize()); i < mNStyles; i++)
518 
519  // try without scrollbars first
522 
523 #if (1) // optimization (experimental - seems to work well)
524 
525  // Optimization: if the number of lines in the buffer does not fit in
526  // the display area, then we need a vertical scrollbar regardless of
527  // word wrapping. If we switch it on here, this saves one line counting
528  // run in wrap mode in the loop below ("... again ..."). This is important
529  // for large buffers that suffer from slow calculations of character width
530  // to determine line wrapping.
531 
533 
534  int nvlines = (text_area.h + mMaxsize - 1) / mMaxsize;
535  int nlines = buffer()->count_lines(0,buffer()->length());
536  if (nvlines < 1) nvlines = 1;
537  if (nlines >= nvlines-1) {
538  mVScrollBar->set_visible(); // we need a vertical scrollbar
539  text_area.w -= scrollbar_width();
540  }
541  }
542 
543 #endif // optimization
544 
545  for (int again = 1; again;) {
546  again = 0;
547  /* In continuous wrap mode, a change in width affects the total number of
548  lines in the buffer, and can leave the top line number incorrect, and
549  the top character no longer pointing at a valid line start */
550 
551 #ifdef DEBUG2
552  printf("*** again ... text_area.w = %d, oldTAWidth = %d, diff = %d\n",
553  text_area.w, oldTAWidth, text_area.w - oldTAWidth);
554 #endif // DEBUG2
555 
556  if (mContinuousWrap && !mWrapMarginPix && text_area.w != oldTAWidth) {
557 
558  int oldFirstChar = mFirstChar;
559  mNBufferLines = count_lines(0, buffer()->length(), true);
561  mTopLineNum = count_lines(0, mFirstChar, true)+1;
562  absolute_top_line_number(oldFirstChar);
563 #ifdef DEBUG2
564  printf(" mNBufferLines=%d\n", mNBufferLines);
565 #endif // DEBUG2
566 
567  }
568 
569  oldTAWidth = text_area.w;
570 
571  /* reallocate and update the line starts array, which may have changed
572  size and / or contents. */
573  int nvlines = (text_area.h + mMaxsize - 1) / mMaxsize;
574  if (nvlines < 1) nvlines = 1;
575  if (mNVisibleLines != nvlines) {
576  mNVisibleLines = nvlines;
577  if (mLineStarts) delete[] mLineStarts;
578  mLineStarts = new int [mNVisibleLines];
579  }
580 
582  calc_last_char();
583 
584  // figure the scrollbars
585  if (scrollbar_width()) {
586 
587  /* Decide if the vertical scrollbar needs to be visible */
588  if (!mVScrollBar->visible() &&
591  {
593  text_area.w -= scrollbar_width();
594  again = 1;
595  }
596 
597  /*
598  Decide if the horizontal scrollbar needs to be visible. If the text
599  wraps at the right edge, do not draw a horizontal scrollbar. Otherwise, if there
600  is a vertical scrollbar, a horizontal is always created too. This
601  is because the alternatives are unattractive:
602  * Dynamically creating a horizontal scrollbar based on the currently
603  visible lines is what the original nedit does, but it always wastes
604  space for the scrollbar even when it's not used. Since the FLTK
605  widget dynamically allocates the space for the scrollbar and
606  rearranges the widget to make room for it, this would create a very
607  visually displeasing "bounce" effect when the vertical scrollbar is
608  dragged. Trust me, I tried it and it looks really bad.
609  * The other alternative would be to keep track of what the longest
610  line in the entire buffer is and base the scrollbar on that. I
611  didn't do this because I didn't see any easy way to do that using
612  the nedit code and this could involve a lengthy calculation for
613  large buffers. If an efficient and non-costly way of doing this
614  can be found, this might be a way to go.
615  */
616  /* WAS: Suggestion: Try turning the horizontal scrollbar on when
617  you first see a line that is too wide in the window, but then
618  don't turn it off (ie mix both of your solutions). */
619 
620  if (!mHScrollBar->visible() &&
623  {
624  char wrap_at_bounds = mContinuousWrap && (mWrapMarginPix<text_area.w);
625  if (!wrap_at_bounds) {
627  text_area.h -= scrollbar_width();
628  again = 1; // loop again to see if we now need vert. & recalc sizes
629  }
630  }
631  }
632  } // (... again ...)
633 
634  // Calculate text area position, dependent on scrollbars and line numbers.
635  // Note: width and height have been calculated above.
638  text_area.x += scrollbar_width();
639 
640  text_area.y = Y + TOP_MARGIN;
641  if (mHScrollBar->visible() &&
643  text_area.y += scrollbar_width();
644 
645  // position and resize scrollbars
646  if (mVScrollBar->visible()) {
647  if (scrollbar_align() & FL_ALIGN_LEFT) {
648 #ifdef LINENUM_LEFT_OF_VSCROLL
650 #else
651  mVScrollBar->resize(X,
652 #endif
653  text_area.y - TOP_MARGIN,
654  scrollbar_width(),
656  } else {
658  text_area.y - TOP_MARGIN,
659  scrollbar_width(),
661  }
662  }
663 
664  if (mHScrollBar->visible()) {
665  if (scrollbar_align() & FL_ALIGN_TOP) {
667  Y,
669  scrollbar_width());
670  } else {
672  Y + H - scrollbar_width(),
674  scrollbar_width());
675  }
676  }
677 
678 
679  // user request to change viewport
682 
683  // everything will fit in the viewport
684  if (mNBufferLines < mNVisibleLines || mBuffer == NULL || mBuffer->length() == 0) {
685  scroll_(1, mHorizOffset);
686  /* if empty lines become visible, there may be an opportunity to
687  display more text by scrolling down */
688  } else {
689  while ( mNVisibleLines>=2
690  && (mLineStarts[mNVisibleLines-2]==-1)
692  { }
693  }
694 
695  // user request to display insert position
697  display_insert();
698 
699  // in case horizontal offset is now greater than longest line
700  int maxhoffset = max(0, longest_vline()-text_area.w);
701  if (mHorizOffset > maxhoffset)
702  scroll_(mTopLineNumHint, maxhoffset);
703 
707 
708  if (mContinuousWrap ||
709  hscrollbarvisible != mHScrollBar->visible() ||
710  vscrollbarvisible != mVScrollBar->visible())
711  redraw();
712 
715 }
716 
717 
718 
724 void Fl_Text_Display::draw_text( int left, int top, int width, int height ) {
725  int fontHeight, firstLine, lastLine, line;
726 
727  /* find the line number range of the display */
728  fontHeight = mMaxsize ? mMaxsize : textsize_;
729  firstLine = ( top - text_area.y - fontHeight + 1 ) / fontHeight;
730  lastLine = ( top + height - text_area.y ) / fontHeight + 1;
731 
732  fl_push_clip( left, top, width, height );
733 
734  /* draw the lines */
735  for ( line = firstLine; line <= lastLine; line++ )
736  draw_vline( line, left, left + width, 0, INT_MAX );
737 
738  fl_pop_clip();
739 }
740 
741 
742 
750 void Fl_Text_Display::redisplay_range(int startpos, int endpos) {
751  IS_UTF8_ALIGNED2(buffer(), startpos)
752  IS_UTF8_ALIGNED2(buffer(), endpos)
753 
754  if (damage_range1_start == -1 && damage_range1_end == -1) {
755  damage_range1_start = startpos;
756  damage_range1_end = endpos;
757  } else if ((startpos >= damage_range1_start && startpos <= damage_range1_end) ||
758  (endpos >= damage_range1_start && endpos <= damage_range1_end)) {
761  } else if (damage_range2_start == -1 && damage_range2_end == -1) {
762  damage_range2_start = startpos;
763  damage_range2_end = endpos;
764  } else {
767  }
769 }
770 
771 
772 
786 void Fl_Text_Display::draw_range(int startpos, int endpos) {
787  startpos = buffer()->utf8_align(startpos);
788  endpos = buffer()->utf8_align(endpos);
789 
790  int i, startLine, lastLine, startIndex, endIndex;
791 
792  /* If the range is outside of the displayed text, just return */
793  if ( endpos < mFirstChar || ( startpos > mLastChar && !empty_vlines() ) )
794  return;
795 
796  /* Clean up the starting and ending values */
797  if ( startpos < 0 ) startpos = 0;
798  if ( startpos > mBuffer->length() ) startpos = mBuffer->length();
799  if ( endpos < 0 ) endpos = 0;
800  if ( endpos > mBuffer->length() ) endpos = mBuffer->length();
801 
802  /* Get the starting and ending lines */
803  if ( startpos < mFirstChar )
804  startpos = mFirstChar;
805  if ( !position_to_line( startpos, &startLine ) )
806  startLine = mNVisibleLines - 1;
807  if ( endpos >= mLastChar ) {
808  lastLine = mNVisibleLines - 1;
809  } else {
810  if ( !position_to_line( endpos, &lastLine ) ) {
811  /* shouldn't happen */
812  lastLine = mNVisibleLines - 1;
813  }
814  }
815 
816  /* Get the starting and ending positions within the lines */
817  startIndex = mLineStarts[ startLine ] == -1 ? 0 : startpos - mLineStarts[ startLine ];
818  if ( endpos >= mLastChar )
819  endIndex = INT_MAX;
820  else if ( mLineStarts[ lastLine ] == -1 )
821  endIndex = 0;
822  else
823  endIndex = endpos - mLineStarts[ lastLine ];
824 
825  /* If the starting and ending lines are the same, redisplay the single
826  line between "start" and "end" */
827  if ( startLine == lastLine ) {
828  draw_vline( startLine, 0, INT_MAX, startIndex, endIndex );
829  return;
830  }
831 
832  /* Redisplay the first line from "start" */
833  draw_vline( startLine, 0, INT_MAX, startIndex, INT_MAX );
834 
835  /* Redisplay the lines in between at their full width */
836  for ( i = startLine + 1; i < lastLine; i++ )
837  draw_vline( i, 0, INT_MAX, 0, INT_MAX );
838 
839  /* Redisplay the last line to "end" */
840  draw_vline( lastLine, 0, INT_MAX, 0, endIndex );
841 }
842 
843 
844 
852  IS_UTF8_ALIGNED2(buffer(), newPos)
853 
854  /* make sure new position is ok, do nothing if it hasn't changed */
855  if ( newPos == mCursorPos ) return;
856  if ( newPos < 0 ) newPos = 0;
857  if ( newPos > mBuffer->length() ) newPos = mBuffer->length();
858 
859  /* cursor movement cancels vertical cursor motion column */
861 
862  /* erase the cursor at its previous position */
863  redisplay_range(buffer()->prev_char_clipped(mCursorPos), buffer()->next_char(mCursorPos));
864 
865  mCursorPos = newPos;
866 
867  /* draw cursor at its new position */
868  redisplay_range(buffer()->prev_char_clipped(mCursorPos), buffer()->next_char(mCursorPos));
869 }
870 
871 
872 
879  mCursorOn = b;
880  if (!buffer()) return;
881  redisplay_range(buffer()->prev_char_clipped(mCursorPos), buffer()->next_char(mCursorPos));
882 }
883 
884 
885 
902  mCursorStyle = style;
903  if (mCursorOn) show_cursor();
904 }
905 
906 
907 
928 void Fl_Text_Display::wrap_mode(int wrap, int wrapMargin) {
929  switch (wrap) {
930  case WRAP_NONE:
931  mWrapMarginPix = 0;
932  mContinuousWrap = 0;
933  break;
934  case WRAP_AT_COLUMN:
935  default:
936  mWrapMarginPix = int(col_to_x(wrapMargin));
937  mContinuousWrap = 1;
938  break;
939  case WRAP_AT_PIXEL:
940  mWrapMarginPix = wrapMargin;
941  mContinuousWrap = 1;
942  break;
943  case WRAP_AT_BOUNDS:
944  mWrapMarginPix = 0;
945  mContinuousWrap = 1;
946  break;
947  }
948 
949  if (buffer()) {
950  /* wrapping can change the total number of lines, re-count */
951  mNBufferLines = count_lines(0, buffer()->length(), true);
952 
953  /* changing wrap margins or changing from wrapped mode to non-wrapped
954  can leave the character at the top no longer at a line start, and/or
955  change the line number */
957  mTopLineNum = count_lines(0, mFirstChar, true) + 1;
958 
960 
961  /* update the line starts array */
963  calc_last_char();
964  } else {
965  // No buffer, so just clear the state info for later...
966  mNBufferLines = 0;
967  mFirstChar = 0;
968  mTopLineNum = 1;
969  mAbsTopLineNum = 1; // changed from 0 to 1 -- LZA / STR#2621
970  }
971 
972  resize(x(), y(), w(), h());
973 }
974 
975 
976 
986 void Fl_Text_Display::insert(const char* text) {
988  IS_UTF8_ALIGNED(text)
989 
990  int pos = mCursorPos;
991 
992  mCursorToHint = (int) (pos + strlen( text ));
993  mBuffer->insert( pos, text );
995 }
996 
997 
998 
1005 void Fl_Text_Display::overstrike(const char* text) {
1007  IS_UTF8_ALIGNED(text)
1008 
1009  int startPos = mCursorPos;
1011  int lineStart = buf->line_start( startPos );
1012  int textLen = (int) strlen( text );
1013  int i, p, endPos, indent, startIndent, endIndent;
1014  const char *c;
1015  unsigned int ch;
1016  char *paddedText = NULL;
1017 
1018  /* determine how many displayed character positions are covered */
1019  startIndent = mBuffer->count_displayed_characters( lineStart, startPos );
1020  indent = startIndent;
1021  for ( c = text; *c != '\0'; c += fl_utf8len1(*c) )
1022  indent++;
1023  endIndent = indent;
1024 
1025  /* find which characters to remove, and if necessary generate additional
1026  padding to make up for removed control characters at the end */
1027  indent = startIndent;
1028  for ( p = startPos; ; p = buf->next_char(p) ) {
1029  if ( p == buf->length() )
1030  break;
1031  ch = buf->char_at( p );
1032  if ( ch == '\n' )
1033  break;
1034  indent++;
1035  if ( indent == endIndent ) {
1036  p = buf->next_char(p);
1037  break;
1038  } else if ( indent > endIndent ) {
1039  if ( ch != '\t' ) {
1040  p = buf->next_char(p);
1041  paddedText = new char [ textLen + FL_TEXT_MAX_EXP_CHAR_LEN + 1 ];
1042  strcpy( paddedText, text );
1043  for ( i = 0; i < indent - endIndent; i++ )
1044  paddedText[ textLen + i ] = ' ';
1045  paddedText[ textLen + i ] = '\0';
1046  }
1047  break;
1048  }
1049  }
1050  endPos = p;
1051 
1052  mCursorToHint = startPos + textLen;
1053  buf->replace( startPos, endPos, paddedText == NULL ? text : paddedText );
1055  if ( paddedText != NULL )
1056  delete [] paddedText;
1057 }
1058 
1059 
1060 
1074 int Fl_Text_Display::position_to_xy( int pos, int* X, int* Y ) const {
1075  IS_UTF8_ALIGNED2(buffer(), pos)
1076 
1077  int lineStartPos, fontHeight;
1078  int visLineNum;
1079  /* If position is not displayed, return false */
1080  if ((pos < mFirstChar) ||
1081  (pos > mLastChar && !empty_vlines()) ||
1082  (pos > buffer()->length()) ) { // STR #3231
1083  return (*X=*Y=0); // make sure X & Y are set when it is out of view
1084  }
1085 
1086  /* Calculate Y coordinate */
1087  if (!position_to_line(pos, &visLineNum) || visLineNum < 0 || visLineNum > mNBufferLines) {
1088  return (*X=*Y=0); // make sure X & Y are set when it is out of view
1089  }
1090 
1091  fontHeight = mMaxsize;
1092  *Y = text_area.y + visLineNum * fontHeight;
1093 
1094  /* Get the text, length, and buffer position of the line. If the position
1095  is beyond the end of the buffer and should be at the first position on
1096  the first empty line, don't try to get or scan the text */
1097  lineStartPos = mLineStarts[visLineNum];
1098  if ( lineStartPos == -1 ) {
1099  *X = text_area.x - mHorizOffset;
1100  return 1;
1101  }
1102  *X = text_area.x + handle_vline(GET_WIDTH, lineStartPos, pos-lineStartPos, 0, 0, 0, 0, 0, 0) - mHorizOffset;
1103  return 1;
1104 }
1105 
1106 
1107 
1125 int Fl_Text_Display::position_to_linecol( int pos, int* lineNum, int* column ) const {
1126  IS_UTF8_ALIGNED2(buffer(), pos)
1127 
1128  int retVal;
1129 
1130  /* In continuous wrap mode, the absolute (non-wrapped) line count is
1131  maintained separately, as needed. Only return it if we're actually
1132  keeping track of it and pos is in the displayed text */
1133  if (mContinuousWrap) {
1134  if (!maintaining_absolute_top_line_number() || pos < mFirstChar || pos > mLastChar)
1135  return 0;
1136  *lineNum = mAbsTopLineNum + buffer()->count_lines(mFirstChar, pos);
1137  *column = buffer()->count_displayed_characters(buffer()->line_start(pos), pos);
1138  return 1;
1139  }
1140 
1141  retVal = position_to_line( pos, lineNum );
1142  if ( retVal ) {
1143  *column = mBuffer->count_displayed_characters( mLineStarts[ *lineNum ], pos );
1144  *lineNum += mTopLineNum;
1145  }
1146  return retVal;
1147 }
1148 
1149 
1150 
1156 int Fl_Text_Display::in_selection( int X, int Y ) const {
1157  int pos = xy_to_position( X, Y, CHARACTER_POS );
1158  IS_UTF8_ALIGNED2(buffer(), pos)
1160  return buf->primary_selection()->includes(pos);
1161 }
1162 
1163 
1164 
1185 int Fl_Text_Display::wrapped_column(int row, int column) const {
1186  int lineStart, dispLineStart;
1187 
1188  if (!mContinuousWrap || row < 0 || row > mNVisibleLines)
1189  return column;
1190  dispLineStart = mLineStarts[row];
1191  if (dispLineStart == -1)
1192  return column;
1193  lineStart = buffer()->line_start(dispLineStart);
1194  return column + buffer()->count_displayed_characters(lineStart, dispLineStart);
1195 }
1196 
1197 
1198 
1213 int Fl_Text_Display::wrapped_row(int row) const {
1214  if (!mContinuousWrap || row < 0 || row > mNVisibleLines)
1215  return row;
1216  return buffer()->count_lines(mFirstChar, mLineStarts[row]);
1217 }
1218 
1219 
1220 
1232  int hOffset, topLine, X, Y;
1233  hOffset = mHorizOffset;
1234  topLine = mTopLineNum;
1235 
1236  if (insert_position() < mFirstChar) {
1237  topLine -= count_lines(insert_position(), mFirstChar, false);
1238  } else if (mNVisibleLines>=2 && mLineStarts[mNVisibleLines-2] != -1) {
1239  int lastChar = line_end(mLineStarts[mNVisibleLines-2],true);
1240  if (insert_position() >= lastChar)
1241  topLine += count_lines(lastChar - (wrap_uses_character(mLastChar) ? 0 : 1),
1242  insert_position(), false);
1243  }
1244 
1245  /* Find the new setting for horizontal offset (this is a bit ungraceful).
1246  If the line is visible, just use PositionToXY to get the position
1247  to scroll to, otherwise, do the vertical scrolling first, then the
1248  horizontal */
1249  if (!position_to_xy( mCursorPos, &X, &Y )) {
1250  scroll_(topLine, hOffset);
1251  if (!position_to_xy( mCursorPos, &X, &Y )) {
1252 #ifdef DEBUG
1253  printf ("*** display_insert/position_to_xy # GIVE UP !\n"); fflush(stdout);
1254 #endif // DEBUG
1255  return; /* Give up, it's not worth it (but why does it fail?) */
1256  }
1257  }
1258  if (X > text_area.x + text_area.w)
1259  hOffset += X-(text_area.x + text_area.w);
1260  else if (X < text_area.x)
1261  hOffset += X-text_area.x;
1262 
1263  /* Do the scroll */
1264  if (topLine != mTopLineNum || hOffset != mHorizOffset)
1265  scroll_(topLine, hOffset);
1266 }
1267 
1268 
1276  resize(x(), y(), w(), h());
1277 }
1278 
1279 
1280 /*
1281  Cursor movement functions
1282  */
1283 
1289  if ( mCursorPos >= mBuffer->length() )
1290  return 0;
1291  int p = insert_position();
1292  int q = buffer()->next_char(p);
1293  insert_position(q);
1294  return 1;
1295 }
1296 
1297 
1298 
1304  if ( mCursorPos <= 0 )
1305  return 0;
1306  int p = insert_position();
1307  int q = buffer()->prev_char_clipped(p);
1308  insert_position(q);
1309  return 1;
1310 }
1311 
1312 
1313 
1319  int lineStartPos, xPos, prevLineStartPos, newPos, visLineNum;
1320 
1321  /* Find the position of the start of the line. Use the line starts array
1322  if possible */
1323  if ( position_to_line( mCursorPos, &visLineNum ) )
1324  lineStartPos = mLineStarts[ visLineNum ];
1325  else {
1326  lineStartPos = line_start( mCursorPos );
1327  visLineNum = -1;
1328  }
1329  if ( lineStartPos == 0 )
1330  return 0;
1331 
1332  /* Decide what column to move to, if there's a preferred column use that */
1333  if (mCursorPreferredXPos >= 0)
1334  xPos = mCursorPreferredXPos;
1335  else
1336  xPos = handle_vline(GET_WIDTH, lineStartPos, mCursorPos-lineStartPos,
1337  0, 0, 0, 0, 0, INT_MAX);
1338 
1339  /* count forward from the start of the previous line to reach the column */
1340  if ( visLineNum != -1 && visLineNum != 0 )
1341  prevLineStartPos = mLineStarts[ visLineNum - 1 ];
1342  else
1343  prevLineStartPos = rewind_lines( lineStartPos, 1 );
1344 
1345  int lineEnd = line_end(prevLineStartPos, true);
1346  newPos = handle_vline(FIND_INDEX_FROM_ZERO, prevLineStartPos, lineEnd-prevLineStartPos,
1347  0, 0, 0, 0, 0, xPos);
1348 
1349  /* move the cursor */
1350  insert_position( newPos );
1351 
1352  /* if a preferred column wasn't aleady established, establish it */
1353  mCursorPreferredXPos = xPos;
1354  return 1;
1355 }
1356 
1357 
1358 
1364  int lineStartPos, xPos, newPos, visLineNum;
1365 
1366  if ( mCursorPos == mBuffer->length() )
1367  return 0;
1368 
1369  if ( position_to_line( mCursorPos, &visLineNum ) )
1370  lineStartPos = mLineStarts[ visLineNum ];
1371  else {
1372  lineStartPos = line_start( mCursorPos );
1373  visLineNum = -1;
1374  }
1375  if (mCursorPreferredXPos >= 0) {
1376  xPos = mCursorPreferredXPos;
1377  } else {
1378  xPos = handle_vline(GET_WIDTH, lineStartPos, mCursorPos-lineStartPos,
1379  0, 0, 0, 0, 0, INT_MAX);
1380  }
1381 
1382  int nextLineStartPos = skip_lines( lineStartPos, 1, true );
1383  int lineEnd = line_end(nextLineStartPos, true);
1384  newPos = handle_vline(FIND_INDEX_FROM_ZERO, nextLineStartPos, lineEnd-nextLineStartPos,
1385  0, 0, 0, 0, 0, xPos);
1386 
1387  insert_position( newPos );
1388  mCursorPreferredXPos = xPos;
1389  return 1;
1390 }
1391 
1392 
1393 
1407 int Fl_Text_Display::count_lines(int startPos, int endPos,
1408  bool startPosIsLineStart) const {
1409  IS_UTF8_ALIGNED2(buffer(), startPos)
1410  IS_UTF8_ALIGNED2(buffer(), endPos)
1411 
1412  int retLines, retPos, retLineStart, retLineEnd;
1413 
1414 #ifdef DEBUG
1415  printf("Fl_Text_Display::count_lines(startPos=%d, endPos=%d, startPosIsLineStart=%d\n",
1416  startPos, endPos, startPosIsLineStart);
1417 #endif // DEBUG
1418 
1419  /* If we're not wrapping use simple (and more efficient) Fl_Text_Buffer::count_lines() */
1420  if (!mContinuousWrap)
1421  return buffer()->count_lines(startPos, endPos);
1422 
1423  wrapped_line_counter(buffer(), startPos, endPos, INT_MAX,
1424  startPosIsLineStart, 0, &retPos, &retLines, &retLineStart,
1425  &retLineEnd);
1426 
1427 #ifdef DEBUG
1428  printf(" # after WLC: retPos=%d, retLines=%d, retLineStart=%d, retLineEnd=%d\n",
1429  retPos, retLines, retLineStart, retLineEnd);
1430 #endif // DEBUG
1431 
1432  return retLines;
1433 }
1434 
1435 
1436 
1450 int Fl_Text_Display::skip_lines(int startPos, int nLines,
1451  bool startPosIsLineStart) {
1452  IS_UTF8_ALIGNED2(buffer(), startPos)
1453 
1454  int retLines, retPos, retLineStart, retLineEnd;
1455 
1456  /* if we're not wrapping use more efficient BufCountForwardNLines */
1457  if (!mContinuousWrap)
1458  return buffer()->skip_lines(startPos, nLines);
1459 
1460  /* wrappedLineCounter can't handle the 0 lines case */
1461  if (nLines == 0)
1462  return startPos;
1463 
1464  /* use the common line counting routine to count forward */
1465  wrapped_line_counter(buffer(), startPos, buffer()->length(),
1466  nLines, startPosIsLineStart, 0,
1467  &retPos, &retLines, &retLineStart, &retLineEnd);
1468  IS_UTF8_ALIGNED2(buffer(), retPos)
1469  return retPos;
1470 }
1471 
1472 
1473 
1496 int Fl_Text_Display::line_end(int startPos, bool startPosIsLineStart) const {
1497  IS_UTF8_ALIGNED2(buffer(), startPos)
1498 
1499  int retLines, retPos, retLineStart, retLineEnd;
1500 
1501  /* If we're not wrapping use more efficient BufEndOfLine */
1502  if (!mContinuousWrap)
1503  return buffer()->line_end(startPos);
1504 
1505  if (startPos == buffer()->length())
1506  return startPos;
1507 
1508  wrapped_line_counter(buffer(), startPos, buffer()->length(), 1,
1509  startPosIsLineStart, 0, &retPos, &retLines, &retLineStart,
1510  &retLineEnd);
1511 
1512  IS_UTF8_ALIGNED2(buffer(), retLineEnd)
1513  return retLineEnd;
1514 }
1515 
1516 
1517 
1527 int Fl_Text_Display::line_start(int pos) const {
1528  IS_UTF8_ALIGNED2(buffer(), pos)
1529 
1530  int retLines, retPos, retLineStart, retLineEnd;
1531 
1532  /* If we're not wrapping, use the more efficient BufStartOfLine */
1533  if (!mContinuousWrap)
1534  return buffer()->line_start(pos);
1535 
1536  wrapped_line_counter(buffer(), buffer()->line_start(pos), pos, INT_MAX, true, 0,
1537  &retPos, &retLines, &retLineStart, &retLineEnd);
1538 
1539  IS_UTF8_ALIGNED2(buffer(), retLineStart)
1540  return retLineStart;
1541 }
1542 
1543 
1544 
1555 int Fl_Text_Display::rewind_lines(int startPos, int nLines) {
1556  IS_UTF8_ALIGNED2(buffer(), startPos)
1557 
1558  Fl_Text_Buffer *buf = buffer();
1559  int pos, lineStart, retLines, retPos, retLineStart, retLineEnd;
1560 
1561  /* If we're not wrapping, use the more efficient BufCountBackwardNLines */
1562  if (!mContinuousWrap)
1563  return buf->rewind_lines(startPos, nLines);
1564 
1565  pos = startPos;
1566  for (;;) {
1567  lineStart = buf->line_start(pos);
1568  wrapped_line_counter(buf, lineStart, pos, INT_MAX, true, 0,
1569  &retPos, &retLines, &retLineStart, &retLineEnd, false);
1570  if (retLines > nLines)
1571  return skip_lines(lineStart, retLines-nLines, true);
1572  nLines -= retLines;
1573  pos = lineStart - 1;
1574  if (pos < 0)
1575  return 0;
1576  nLines -= 1;
1577  }
1578 }
1579 
1580 
1581 
1582 static inline int fl_isseparator(unsigned int c) {
1583  // FIXME: this does not take UCS-4 encoding into account
1584  return c != '$' && c != '_' && (isspace(c) || ispunct(c));
1585 }
1586 
1587 
1588 
1593  int pos = insert_position();
1594 
1595  while (pos < buffer()->length() && !fl_isseparator(buffer()->char_at(pos))) {
1596  pos = buffer()->next_char(pos);
1597  }
1598 
1599  while (pos < buffer()->length() && fl_isseparator(buffer()->char_at(pos))) {
1600  pos = buffer()->next_char(pos);
1601  }
1602 
1603  insert_position( pos );
1604 }
1605 
1606 
1607 
1612  int pos = insert_position();
1613  if (pos==0) return;
1614  pos = buffer()->prev_char(pos);
1615 
1616  while (pos && fl_isseparator(buffer()->char_at(pos))) {
1617  pos = buffer()->prev_char(pos);
1618  }
1619 
1620  while (pos && !fl_isseparator(buffer()->char_at(pos))) {
1621  pos = buffer()->prev_char(pos);
1622  }
1623 
1624  if (fl_isseparator(buffer()->char_at(pos))) {
1625  pos = buffer()->next_char(pos);
1626  }
1627 
1628  insert_position( pos );
1629 }
1630 
1631 
1632 
1647 void Fl_Text_Display::buffer_predelete_cb(int pos, int nDeleted, void *cbArg) {
1648  Fl_Text_Display *textD = (Fl_Text_Display *)cbArg;
1649  if (textD->mContinuousWrap) {
1650  /* Note: we must perform this measurement, even if there is not a
1651  single character deleted; the number of "deleted" lines is the
1652  number of visual lines spanned by the real line in which the
1653  modification takes place.
1654  Also, a modification of the tab distance requires the same
1655  kind of calculations in advance, even if the font width is "fixed",
1656  because when the width of the tab characters changes, the layout
1657  of the text may be completely different. */
1658  IS_UTF8_ALIGNED2(textD->buffer(), pos)
1659  textD->measure_deleted_lines(pos, nDeleted);
1660  } else {
1661  textD->mSuppressResync = 0; /* Probably not needed, but just in case */
1662  }
1663 }
1664 
1665 
1666 
1683 void Fl_Text_Display::buffer_modified_cb( int pos, int nInserted, int nDeleted,
1684  int nRestyled, const char *deletedText, void *cbArg ) {
1685  int linesInserted, linesDeleted, startDispPos, endDispPos;
1686  Fl_Text_Display *textD = ( Fl_Text_Display * ) cbArg;
1687  Fl_Text_Buffer *buf = textD->mBuffer;
1688  int oldFirstChar = textD->mFirstChar;
1689  int scrolled, origCursorPos = textD->mCursorPos;
1690  int wrapModStart = 0, wrapModEnd = 0;
1691 
1692  IS_UTF8_ALIGNED2(buf, pos)
1693  IS_UTF8_ALIGNED2(buf, oldFirstChar)
1694 
1695  /* buffer modification cancels vertical cursor motion column */
1696  if ( nInserted != 0 || nDeleted != 0 )
1697  textD->mCursorPreferredXPos = -1;
1698 
1699  /* Count the number of lines inserted and deleted, and in the case
1700  of continuous wrap mode, how much has changed */
1701  if (textD->mContinuousWrap) {
1702  textD->find_wrap_range(deletedText, pos, nInserted, nDeleted,
1703  &wrapModStart, &wrapModEnd, &linesInserted, &linesDeleted);
1704  } else {
1705  linesInserted = nInserted == 0 ? 0 : buf->count_lines( pos, pos + nInserted );
1706  linesDeleted = nDeleted == 0 ? 0 : countlines( deletedText );
1707  }
1708 
1709  /* Update the line starts and mTopLineNum */
1710  if ( nInserted != 0 || nDeleted != 0 ) {
1711  if (textD->mContinuousWrap) {
1712  textD->update_line_starts( wrapModStart, wrapModEnd-wrapModStart,
1713  nDeleted + pos-wrapModStart + (wrapModEnd-(pos+nInserted)),
1714  linesInserted, linesDeleted, &scrolled );
1715  } else {
1716  textD->update_line_starts( pos, nInserted, nDeleted, linesInserted,
1717  linesDeleted, &scrolled );
1718  }
1719  } else
1720  scrolled = 0;
1721 
1722  /* If we're counting non-wrapped lines as well, maintain the absolute
1723  (non-wrapped) line number of the text displayed */
1724  if (textD->maintaining_absolute_top_line_number() &&
1725  (nInserted != 0 || nDeleted != 0)) {
1726  if (deletedText && (pos + nDeleted < oldFirstChar))
1727  textD->mAbsTopLineNum += buf->count_lines(pos, pos + nInserted) -
1728  countlines(deletedText);
1729  else if (pos < oldFirstChar)
1731  }
1732 
1733  /* Update the line count for the whole buffer */
1734  textD->mNBufferLines += linesInserted - linesDeleted;
1735 
1736  /* Update the cursor position */
1737  if ( textD->mCursorToHint != NO_HINT ) {
1738  textD->mCursorPos = textD->mCursorToHint;
1739  textD->mCursorToHint = NO_HINT;
1740  } else if ( textD->mCursorPos > pos ) {
1741  if ( textD->mCursorPos < pos + nDeleted )
1742  textD->mCursorPos = pos;
1743  else
1744  textD->mCursorPos += nInserted - nDeleted;
1745  }
1746 
1747  // refigure scrollbars & stuff
1748  textD->resize(textD->x(), textD->y(), textD->w(), textD->h());
1749 
1750  // don't need to do anything else if not visible?
1751  if (!textD->visible_r()) return;
1752 
1753  /* If the changes caused scrolling, re-paint everything and we're done. */
1754  if ( scrolled ) {
1755  textD->damage(FL_DAMAGE_EXPOSE);
1756  if ( textD->mStyleBuffer ) /* See comments in extendRangeForStyleMods */
1757  textD->mStyleBuffer->primary_selection()->selected(0);
1758  return;
1759  }
1760 
1761  /* If the changes didn't cause scrolling, decide the range of characters
1762  that need to be re-painted. Also if the cursor position moved, be
1763  sure that the redisplay range covers the old cursor position so the
1764  old cursor gets erased, and erase the bits of the cursor which extend
1765  beyond the left and right edges of the text. */
1766  startDispPos = textD->mContinuousWrap ? wrapModStart : pos;
1767  IS_UTF8_ALIGNED2(buf, startDispPos)
1768 
1769  if ( origCursorPos == startDispPos && textD->mCursorPos != startDispPos )
1770  startDispPos = min( startDispPos, buf->prev_char_clipped(origCursorPos) );
1771  IS_UTF8_ALIGNED2(buf, startDispPos)
1772 
1773  if ( linesInserted == linesDeleted ) {
1774  if ( nInserted == 0 && nDeleted == 0 )
1775  endDispPos = pos + nRestyled;
1776  else {
1777  if (textD->mContinuousWrap)
1778  endDispPos = wrapModEnd;
1779  else
1780  endDispPos = buf->next_char(buf->line_end( pos + nInserted ));
1781 
1782  // CET - FIXME if ( origCursorPos >= startDispPos &&
1783  // ( origCursorPos <= endDispPos || endDispPos == buf->length() ) )
1784  }
1785  if (linesInserted > 1) {
1786  // textD->draw_line_numbers(false); // can't do this b/c not called from virtual draw();
1787  textD->damage(::FL_DAMAGE_EXPOSE);
1788  }
1789  } else {
1790  endDispPos = buf->next_char(textD->mLastChar);
1791  // CET - FIXME if ( origCursorPos >= pos )
1792  /* If more than one line is inserted/deleted, a line break may have
1793  been inserted or removed in between, and the line numbers may
1794  have changed. If only one line is altered, line numbers cannot
1795  be affected (the insertion or removal of a line break always
1796  results in at least two lines being redrawn). */
1797 
1798  // Call draw_line_numbers() here to ensure line# is drawn
1799  // when hitting enter for new line -- LZA / STR #2621
1800  //textD->draw_line_numbers(true); // no, can't call this here, not in draw() context -- ERCO / STR#2621
1801  //textD->damage(::FL_DAMAGE_EXPOSE);
1802  }
1803  IS_UTF8_ALIGNED2(buf, startDispPos)
1804  IS_UTF8_ALIGNED2(buf, endDispPos)
1805 
1806  /* If there is a style buffer, check if the modification caused additional
1807  changes that need to be redisplayed. (Redisplaying separately would
1808  cause double-redraw on almost every modification involving styled
1809  text). Extend the redraw range to incorporate style changes */
1810  if ( textD->mStyleBuffer )
1811  textD->extend_range_for_styles( &startDispPos, &endDispPos );
1812  IS_UTF8_ALIGNED2(buf, startDispPos)
1813  IS_UTF8_ALIGNED2(buf, endDispPos)
1814 
1815  /* Redisplay computed range */
1816  textD->redisplay_range( startDispPos, endDispPos );
1817 }
1818 
1819 
1820 /* Line Numbering Methods */
1821 
1837 }
1838 
1839 
1840 
1848  if (!mContinuousWrap)
1849  return mTopLineNum;
1851  return mAbsTopLineNum;
1852  return 0;
1853 }
1854 
1855 
1856 
1864  if (mFirstChar < oldFirstChar)
1865  mAbsTopLineNum -= buffer()->count_lines(mFirstChar, oldFirstChar);
1866  else
1867  mAbsTopLineNum += buffer()->count_lines(oldFirstChar, mFirstChar);
1868  }
1869 }
1870 
1871 
1872 
1880  return mContinuousWrap &&
1882 }
1883 
1884 
1885 
1894  mAbsTopLineNum = 1;
1896 }
1897 
1898 
1899 
1911 int Fl_Text_Display::position_to_line( int pos, int *lineNum ) const {
1912  IS_UTF8_ALIGNED2(buffer(), pos)
1913 
1914  int i;
1915 
1916  *lineNum = 0;
1917  if ( pos < mFirstChar ) return 0;
1918  if ( pos > mLastChar ) {
1919  if ( empty_vlines() ) {
1920  if ( mLastChar < mBuffer->length() ) {
1921  if ( !position_to_line( mLastChar, lineNum ) ) {
1922  Fl::error("Fl_Text_Display::position_to_line(): Consistency check ptvl failed");
1923  return 0;
1924  }
1925  return ++( *lineNum ) <= mNVisibleLines - 1;
1926  } else {
1927  position_to_line( buffer()->prev_char_clipped(mLastChar), lineNum );
1928  return 1;
1929  }
1930  }
1931  return 0;
1932  }
1933 
1934  for ( i = mNVisibleLines - 1; i >= 0; i-- ) {
1935  if ( mLineStarts[ i ] != -1 && pos >= mLineStarts[ i ] ) {
1936  *lineNum = i;
1937  return 1;
1938  }
1939  }
1940  return 0; /* probably never be reached */
1941 }
1942 
1943 
1968  int mode,
1969  int lineStartPos, int lineLen, int leftChar, int rightChar,
1970  int Y, int bottomClip,
1971  int leftClip, int rightClip) const
1972 {
1973  IS_UTF8_ALIGNED2(buffer(), lineStartPos)
1974 
1975  // FIXME: we need to allow two modes for FIND_INDEX: one on the edge of the
1976  // FIXME: character for selection, and one on the character center for cursors.
1977  int i, X, startX, startIndex, style, charStyle;
1978  char *lineStr;
1979 
1980  if ( lineStartPos == -1 ) {
1981  lineStr = NULL;
1982  } else {
1983  lineStr = mBuffer->text_range( lineStartPos, lineStartPos + lineLen );
1984  }
1985 
1986  if (mode==GET_WIDTH) {
1987  X = 0;
1988  } else if (mode==FIND_INDEX_FROM_ZERO) {
1989  X = 0;
1990  mode = FIND_INDEX;
1991  } else {
1992  X = text_area.x - mHorizOffset;
1993  }
1994 
1995  startX = X;
1996  startIndex = 0;
1997  if (!lineStr) {
1998  // just clear the background
1999  if (mode==DRAW_LINE) {
2000  style = position_style(lineStartPos, lineLen, -1);
2001  draw_string( style|BG_ONLY_MASK, text_area.x, Y, text_area.x+text_area.w, lineStr, lineLen );
2002  }
2003  if (mode==FIND_INDEX) {
2004  IS_UTF8_ALIGNED2(buffer(), lineStartPos)
2005  return lineStartPos;
2006  }
2007  return 0;
2008  }
2009 
2010  char currChar = 0, prevChar = 0;
2011  // draw the line
2012  style = position_style(lineStartPos, lineLen, 0);
2013  for (i=0; i<lineLen; ) {
2014  currChar = lineStr[i]; // one byte is enough to handele tabs and other cases
2015  int len = fl_utf8len1(currChar);
2016  if (len<=0) len = 1; // OUCH!
2017  charStyle = position_style(lineStartPos, lineLen, i);
2018  if (charStyle!=style || currChar=='\t' || prevChar=='\t') {
2019  // draw a segment whenever the style changes or a Tab is found
2020  int w = 0;
2021  if (prevChar=='\t') {
2022  // draw a single Tab space
2023  int tab = (int)col_to_x(mBuffer->tab_distance());
2024  int xAbs = (mode==GET_WIDTH) ? startX : startX+mHorizOffset-text_area.x;
2025  w = (((xAbs/tab)+1)*tab) - xAbs;
2026  if (mode==DRAW_LINE)
2027  draw_string( style|BG_ONLY_MASK, startX, Y, startX+w, 0, 0 );
2028  if (mode==FIND_INDEX && startX+w>rightClip) {
2029  // find x pos inside block
2030  free(lineStr);
2031  return lineStartPos + startIndex;
2032  }
2033  } else {
2034  // draw a text segment
2035  w = int( string_width( lineStr+startIndex, i-startIndex, style ) );
2036  if (mode==DRAW_LINE)
2037  draw_string( style, startX, Y, startX+w, lineStr+startIndex, i-startIndex );
2038  if (mode==FIND_INDEX && startX+w>rightClip) {
2039  // find x pos inside block
2040  int di = find_x(lineStr+startIndex, i-startIndex, style, rightClip-startX);
2041  free(lineStr);
2042  IS_UTF8_ALIGNED2(buffer(), (lineStartPos+startIndex+di))
2043  return lineStartPos + startIndex + di;
2044  }
2045  }
2046  style = charStyle;
2047  startX += w;
2048  startIndex = i;
2049  }
2050  i += len;
2051  prevChar = currChar;
2052  }
2053  int w = 0;
2054  if (currChar=='\t') {
2055  // draw a single Tab space
2056  int tab = (int)col_to_x(mBuffer->tab_distance());
2057  int xAbs = (mode==GET_WIDTH) ? startX : startX+mHorizOffset-text_area.x;
2058  w = (((xAbs/tab)+1)*tab) - xAbs;
2059  if (mode==DRAW_LINE)
2060  draw_string( style|BG_ONLY_MASK, startX, Y, startX+w, 0, 0 );
2061  if (mode==FIND_INDEX) {
2062  // find x pos inside block
2063  free(lineStr);
2064  return lineStartPos + startIndex + ( rightClip-startX>w ? 1 : 0 );
2065  }
2066  } else {
2067  w = int( string_width( lineStr+startIndex, i-startIndex, style ) );
2068  if (mode==DRAW_LINE)
2069  draw_string( style, startX, Y, startX+w, lineStr+startIndex, i-startIndex );
2070  if (mode==FIND_INDEX) {
2071  // find x pos inside block
2072  int di = find_x(lineStr+startIndex, i-startIndex, style, rightClip-startX);
2073  free(lineStr);
2074  IS_UTF8_ALIGNED2(buffer(), (lineStartPos+startIndex+di))
2075  return lineStartPos + startIndex + di;
2076  }
2077  }
2078  if (mode==GET_WIDTH) {
2079  free(lineStr);
2080  return startX+w;
2081  }
2082 
2083  // clear the rest of the line
2084  startX += w;
2085  style = position_style(lineStartPos, lineLen, i);
2086  if (mode==DRAW_LINE)
2087  draw_string( style|BG_ONLY_MASK, startX, Y, text_area.x+text_area.w, lineStr, lineLen );
2088 
2089  free(lineStr);
2090  IS_UTF8_ALIGNED2(buffer(), (lineStartPos+lineLen))
2091  return lineStartPos + lineLen;
2092 }
2093 
2094 
2103 int Fl_Text_Display::find_x(const char *s, int len, int style, int x) const {
2104  IS_UTF8_ALIGNED(s)
2105 
2106  // TODO: use binary search which may be quicker.
2107  int i = 0;
2108  while (i<len) {
2109  int cl = fl_utf8len1(s[i]);
2110  int w = int( string_width(s, i+cl, style) );
2111  if (w>x)
2112  return i;
2113  i += cl;
2114  }
2115  return len;
2116 }
2117 
2118 
2119 
2133 void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
2134  int leftCharIndex, int rightCharIndex) {
2135  int Y, lineStartPos, lineLen, fontHeight;
2136 
2137  // printf("draw_vline(visLineNum=%d, leftClip=%d, rightClip=%d, leftCharIndex=%d, rightCharIndex=%d)\n",
2138  // visLineNum, leftClip, rightClip, leftCharIndex, rightCharIndex);
2139  // printf("nNVisibleLines=%d\n", mNVisibleLines);
2140 
2141  /* If line is not displayed, skip it */
2142  if ( visLineNum < 0 || visLineNum >= mNVisibleLines )
2143  return;
2144 
2145  /* Calculate Y coordinate of the string to draw */
2146  fontHeight = mMaxsize;
2147  Y = text_area.y + visLineNum * fontHeight;
2148 
2149  /* Get the text, length, and buffer position of the line to display */
2150  lineStartPos = mLineStarts[ visLineNum ];
2151  if ( lineStartPos == -1 ) {
2152  lineLen = 0;
2153  } else {
2154  lineLen = vline_length( visLineNum );
2155  }
2156 
2157  /* Shrink the clipping range to the active display area */
2158  leftClip = max( text_area.x, leftClip );
2159  rightClip = min( rightClip, text_area.x + text_area.w );
2160 
2162  lineStartPos, lineLen, leftCharIndex, rightCharIndex,
2163  Y, Y+fontHeight, leftClip, rightClip);
2164  return;
2165 }
2166 
2167 
2168 
2186  int X, int Y, int toX,
2187  const char *string, int nChars) const {
2188  IS_UTF8_ALIGNED(string)
2189 
2190  const Style_Table_Entry * styleRec;
2191 
2192  /* Draw blank area rather than text, if that was the request */
2193  if ( style & FILL_MASK ) {
2194  if (style & TEXT_ONLY_MASK) return;
2195  clear_rect( style, X, Y, toX - X, mMaxsize );
2196  return;
2197  }
2198  /* Set font, color, and gc depending on style. For normal text, GCs
2199  for normal drawing, or drawing within a Fl_Text_Selection or highlight are
2200  pre-allocated and pre-configured. For syntax highlighting, GCs are
2201  configured here, on the fly. */
2202 
2203  Fl_Font font = textfont();
2204  int fsize = textsize();
2205  Fl_Color foreground;
2207 
2208  if ( style & STYLE_LOOKUP_MASK ) {
2209  int si = (style & STYLE_LOOKUP_MASK) - 'A';
2210  if (si < 0) si = 0;
2211  else if (si >= mNStyles) si = mNStyles - 1;
2212 
2213  styleRec = mStyleTable + si;
2214  font = styleRec->font;
2215  fsize = styleRec->size;
2216 
2217  if (style & PRIMARY_MASK) {
2218  if (Fl::focus() == (Fl_Widget*)this) {
2219 #ifdef __APPLE__
2220  if (Fl::compose_state) background = color();// Mac OS: underline marked text
2221  else
2222 #endif
2224  }
2226  } else if (style & HIGHLIGHT_MASK) {
2227  if (Fl::focus() == (Fl_Widget*)this) background = fl_color_average(color(), selection_color(), 0.5f);
2229  } else background = color();
2230  foreground = (style & PRIMARY_MASK) ? fl_contrast(styleRec->color, background) : styleRec->color;
2231  } else if (style & PRIMARY_MASK) {
2232  if (Fl::focus() == (Fl_Widget*)this) background = selection_color();
2234  foreground = fl_contrast(textcolor(), background);
2235  } else if (style & HIGHLIGHT_MASK) {
2236  if (Fl::focus() == (Fl_Widget*)this) background = fl_color_average(color(), selection_color(), 0.5f);
2238  foreground = fl_contrast(textcolor(), background);
2239  } else {
2240  foreground = textcolor();
2241  background = color();
2242  }
2243 
2244  if ( !active_r() ) {
2245  foreground = fl_inactive(foreground);
2247  }
2248 
2249  if (!(style & TEXT_ONLY_MASK)) {
2250  fl_color( background );
2251  fl_rectf( X, Y, toX - X, mMaxsize );
2252  }
2253  if (!(style & BG_ONLY_MASK)) {
2254  fl_color( foreground );
2255  fl_font( font, fsize );
2256 #if !(defined(__APPLE__) || defined(WIN32)) && USE_XFT
2257  // makes sure antialiased ÄÖÜ do not leak on line above
2258  fl_push_clip(X, Y, toX - X, mMaxsize);
2259 #endif
2260  fl_draw( string, nChars, X, Y + mMaxsize - fl_descent());
2261 #ifdef __APPLE__ // Mac OS: underline marked (= selected + Fl::compose_state != 0) text
2262  if (Fl::compose_state && (style & PRIMARY_MASK)) {
2263  fl_color( fl_color_average(foreground, background, 0.6) );
2264  fl_line(X, Y + mMaxsize - 1, X + fl_width(string, nChars), Y + mMaxsize - 1);
2265  }
2266 #endif
2267 #if !(defined(__APPLE__) || defined(WIN32)) && USE_XFT
2268  fl_pop_clip();
2269 #endif
2270  }
2271 
2272  // CET - FIXME
2273  /* If any space around the character remains unfilled (due to use of
2274  different sized fonts for highlighting), fill in above or below
2275  to erase previously drawn characters */
2276  /*
2277  if (fs->ascent < mAscent)
2278  clear_rect( style, X, Y, toX - X, mAscent - fs->ascent);
2279  if (fs->descent < mDescent)
2280  clear_rect( style, X, Y + mAscent + fs->descent, toX - x,
2281  mDescent - fs->descent);
2282  */
2283  /* Underline if style is secondary Fl_Text_Selection */
2284 
2285  /*
2286  if (style & SECONDARY_MASK)
2287  XDrawLine(XtDisplay(mW), XtWindow(mW), gc, x,
2288  y + mAscent, toX - 1, Y + fs->ascent);
2289  */
2290 }
2291 
2292 
2293 
2301  int X, int Y,
2302  int width, int height) const {
2303  /* A width of zero means "clear to end of window" to XClearArea */
2304  if ( width == 0 )
2305  return;
2306 
2307  Fl_Color c;
2308  if (style & PRIMARY_MASK) {
2309  if (Fl::focus()==(Fl_Widget*)this) {
2310  c = selection_color();
2311  } else {
2312  c = fl_color_average(color(), selection_color(), 0.4f);
2313  }
2314  } else if (style & HIGHLIGHT_MASK) {
2315  if (Fl::focus()==(Fl_Widget*)this) {
2316  c = fl_color_average(color(), selection_color(), 0.5f);
2317  } else {
2318  c = fl_color_average(color(), selection_color(), 0.6f);
2319  }
2320  } else {
2321  c = color();
2322  }
2323  fl_color(active_r() ? c : fl_inactive(c));
2324  fl_rectf( X, Y, width, height );
2325 }
2326 
2327 
2328 
2334 void Fl_Text_Display::draw_cursor( int X, int Y ) {
2335 
2336  typedef struct {
2337  int x1, y1, x2, y2;
2338  }
2339  Segment;
2340 
2341  Segment segs[ 5 ];
2342  int left, right, cursorWidth, midY;
2343  // int fontWidth = mFontStruct->min_bounds.width, nSegs = 0;
2344  int fontWidth = TMPFONTWIDTH; // CET - FIXME
2345  int nSegs = 0;
2346  int fontHeight = mMaxsize;
2347  int bot = Y + fontHeight - 1;
2348 
2349  if ( X < text_area.x - 1 || X > text_area.x + text_area.w )
2350  return;
2351 
2352 #ifdef __APPLE__
2353  Fl::insertion_point_location(X, bot, fontHeight);
2354 #endif
2355  /* For cursors other than the block, make them around 2/3 of a character
2356  width, rounded to an even number of pixels so that X will draw an
2357  odd number centered on the stem at x. */
2358  cursorWidth = 4; //(fontWidth/3) * 2;
2359  left = X - cursorWidth / 2;
2360  right = left + cursorWidth;
2361 
2362  /* Create segments and draw cursor */
2363  if ( mCursorStyle == CARET_CURSOR ) {
2364  midY = bot - fontHeight / 5;
2365  segs[ 0 ].x1 = left; segs[ 0 ].y1 = bot; segs[ 0 ].x2 = X; segs[ 0 ].y2 = midY;
2366  segs[ 1 ].x1 = X; segs[ 1 ].y1 = midY; segs[ 1 ].x2 = right; segs[ 1 ].y2 = bot;
2367  segs[ 2 ].x1 = left; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = midY - 1;
2368  segs[ 3 ].x1 = X; segs[ 3 ].y1 = midY - 1; segs[ 3 ].x2 = right; segs[ 3 ].y2 = bot;
2369  nSegs = 4;
2370  } else if ( mCursorStyle == NORMAL_CURSOR ) {
2371  segs[ 0 ].x1 = left; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = right; segs[ 0 ].y2 = Y;
2372  segs[ 1 ].x1 = X; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X; segs[ 1 ].y2 = bot;
2373  segs[ 2 ].x1 = left; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = right; segs[ 2 ].y2 = bot;
2374  nSegs = 3;
2375  } else if ( mCursorStyle == HEAVY_CURSOR ) {
2376  segs[ 0 ].x1 = X - 1; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X - 1; segs[ 0 ].y2 = bot;
2377  segs[ 1 ].x1 = X; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X; segs[ 1 ].y2 = bot;
2378  segs[ 2 ].x1 = X + 1; segs[ 2 ].y1 = Y; segs[ 2 ].x2 = X + 1; segs[ 2 ].y2 = bot;
2379  segs[ 3 ].x1 = left; segs[ 3 ].y1 = Y; segs[ 3 ].x2 = right; segs[ 3 ].y2 = Y;
2380  segs[ 4 ].x1 = left; segs[ 4 ].y1 = bot; segs[ 4 ].x2 = right; segs[ 4 ].y2 = bot;
2381  nSegs = 5;
2382  } else if ( mCursorStyle == DIM_CURSOR ) {
2383  midY = Y + fontHeight / 2;
2384  segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X; segs[ 0 ].y2 = Y;
2385  segs[ 1 ].x1 = X; segs[ 1 ].y1 = midY; segs[ 1 ].x2 = X; segs[ 1 ].y2 = midY;
2386  segs[ 2 ].x1 = X; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = bot;
2387  nSegs = 3;
2388  } else if ( mCursorStyle == BLOCK_CURSOR ) {
2389  right = X + fontWidth;
2390  segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = right; segs[ 0 ].y2 = Y;
2391  segs[ 1 ].x1 = right; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = right; segs[ 1 ].y2 = bot;
2392  segs[ 2 ].x1 = right; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = bot;
2393  segs[ 3 ].x1 = X; segs[ 3 ].y1 = bot; segs[ 3 ].x2 = X; segs[ 3 ].y2 = Y;
2394  nSegs = 4;
2395  } else if ( mCursorStyle == SIMPLE_CURSOR ){
2396  segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X; segs[ 0 ].y2 = bot;
2397  segs[ 1 ].x1 = X+1; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X+1; segs[ 1 ].y2 = bot;
2398  nSegs = 2;
2399  }
2401 
2402  for ( int k = 0; k < nSegs; k++ ) {
2403  fl_line( segs[ k ].x1, segs[ k ].y1, segs[ k ].x2, segs[ k ].y2 );
2404  }
2405 }
2406 
2407 
2408 
2432 int Fl_Text_Display::position_style( int lineStartPos, int lineLen, int lineIndex) const
2433 {
2434  IS_UTF8_ALIGNED2(buffer(), lineStartPos)
2435 
2437  Fl_Text_Buffer *styleBuf = mStyleBuffer;
2438  int pos, style = 0;
2439 
2440  if ( lineStartPos == -1 || buf == NULL )
2441  return FILL_MASK;
2442 
2443  pos = lineStartPos + min( lineIndex, lineLen );
2444 
2445  if ( lineIndex >= lineLen )
2446  style = FILL_MASK;
2447  else if ( styleBuf != NULL ) {
2448  style = ( unsigned char ) styleBuf->byte_at( pos );
2449  if (style == mUnfinishedStyle && mUnfinishedHighlightCB) {
2450  /* encountered "unfinished" style, trigger parsing */
2452  style = (unsigned char) styleBuf->byte_at( pos);
2453  }
2454  }
2455  if (buf->primary_selection()->includes(pos))
2456  style |= PRIMARY_MASK;
2457  if (buf->highlight_selection()->includes(pos))
2458  style |= HIGHLIGHT_MASK;
2459  if (buf->secondary_selection()->includes(pos))
2460  style |= SECONDARY_MASK;
2461  return style;
2462 }
2463 
2464 
2473 double Fl_Text_Display::string_width( const char *string, int length, int style ) const {
2474  IS_UTF8_ALIGNED(string)
2475 
2476  Fl_Font font;
2477  Fl_Fontsize fsize;
2478 
2479  if ( mNStyles && (style & STYLE_LOOKUP_MASK) ) {
2480  int si = (style & STYLE_LOOKUP_MASK) - 'A';
2481  if (si < 0) si = 0;
2482  else if (si >= mNStyles) si = mNStyles - 1;
2483 
2484  font = mStyleTable[si].font;
2485  fsize = mStyleTable[si].size;
2486  } else {
2487  font = textfont();
2488  fsize = textsize();
2489  }
2490  fl_font( font, fsize );
2491  return fl_width( string, length );
2492 }
2493 
2494 
2495 
2509 int Fl_Text_Display::xy_to_position( int X, int Y, int posType ) const {
2510  int lineStart, lineLen, fontHeight;
2511  int visLineNum;
2512 
2513  /* Find the visible line number corresponding to the Y coordinate */
2514  fontHeight = mMaxsize;
2515  visLineNum = ( Y - text_area.y ) / fontHeight;
2516  if ( visLineNum < 0 )
2517  return mFirstChar;
2518  if ( visLineNum >= mNVisibleLines )
2519  visLineNum = mNVisibleLines - 1;
2520 
2521  /* Find the position at the start of the line */
2522  lineStart = mLineStarts[ visLineNum ];
2523 
2524  /* If the line start was empty, return the last position in the buffer */
2525  if ( lineStart == -1 )
2526  return mBuffer->length();
2527 
2528  /* Get the line text and its length */
2529  lineLen = vline_length( visLineNum );
2530 
2531  return handle_vline(FIND_INDEX,
2532  lineStart, lineLen, 0, 0,
2533  0, 0,
2534  text_area.x, X);
2535 }
2536 
2537 
2538 
2553 void Fl_Text_Display::xy_to_rowcol( int X, int Y, int *row,
2554  int *column, int posType ) const {
2555  int fontHeight = mMaxsize;
2556  int fontWidth = TMPFONTWIDTH; //mFontStruct->max_bounds.width;
2557 
2558  /* Find the visible line number corresponding to the Y coordinate */
2559  *row = ( Y - text_area.y ) / fontHeight;
2560  if ( *row < 0 ) *row = 0;
2561  if ( *row >= mNVisibleLines ) *row = mNVisibleLines - 1;
2562 
2563  *column = ( ( X - text_area.x ) + mHorizOffset +
2564  ( posType == CURSOR_POS ? fontWidth / 2 : 0 ) ) / fontWidth;
2565  if ( *column < 0 ) * column = 0;
2566 }
2567 
2568 
2569 
2581 void Fl_Text_Display::offset_line_starts( int newTopLineNum ) {
2582  int oldTopLineNum = mTopLineNum;
2583  int oldFirstChar = mFirstChar;
2584  int lineDelta = newTopLineNum - oldTopLineNum;
2585  int nVisLines = mNVisibleLines;
2586  int *lineStarts = mLineStarts;
2587  int i, lastLineNum;
2589 
2590  /* If there was no offset, nothing needs to be changed */
2591  if ( lineDelta == 0 )
2592  return;
2593 
2594  /* Find the new value for mFirstChar by counting lines from the nearest
2595  known line start (start or end of buffer, or the closest value in the
2596  lineStarts array) */
2597  lastLineNum = oldTopLineNum + nVisLines - 1;
2598  if ( newTopLineNum < oldTopLineNum && newTopLineNum < -lineDelta ) {
2599  mFirstChar = skip_lines( 0, newTopLineNum - 1, true );
2600  } else if ( newTopLineNum < oldTopLineNum ) {
2601  mFirstChar = rewind_lines( mFirstChar, -lineDelta );
2602  } else if ( newTopLineNum < lastLineNum ) {
2603  mFirstChar = lineStarts[ newTopLineNum - oldTopLineNum ];
2604  } else if ( newTopLineNum - lastLineNum < mNBufferLines - newTopLineNum ) {
2605  mFirstChar = skip_lines( lineStarts[ nVisLines - 1 ],
2606  newTopLineNum - lastLineNum, true );
2607  } else {
2608  mFirstChar = rewind_lines( buf->length(), mNBufferLines - newTopLineNum + 1 );
2609  }
2610 
2611  /* Fill in the line starts array */
2612  if ( lineDelta < 0 && -lineDelta < nVisLines ) {
2613  for ( i = nVisLines - 1; i >= -lineDelta; i-- )
2614  lineStarts[ i ] = lineStarts[ i + lineDelta ];
2615  calc_line_starts( 0, -lineDelta );
2616  } else if ( lineDelta > 0 && lineDelta < nVisLines ) {
2617  for ( i = 0; i < nVisLines - lineDelta; i++ )
2618  lineStarts[ i ] = lineStarts[ i + lineDelta ];
2619  calc_line_starts( nVisLines - lineDelta, nVisLines - 1 );
2620  } else
2621  calc_line_starts( 0, nVisLines );
2622 
2623  /* Set lastChar and mTopLineNum */
2624  calc_last_char();
2625  mTopLineNum = newTopLineNum;
2626 
2627  /* If we're numbering lines or being asked to maintain an absolute line
2628  number, re-calculate the absolute line number */
2629  absolute_top_line_number(oldFirstChar);
2630 }
2631 
2632 
2633 
2649 void Fl_Text_Display::update_line_starts(int pos, int charsInserted,
2650  int charsDeleted, int linesInserted,
2651  int linesDeleted, int *scrolled ) {
2652  IS_UTF8_ALIGNED2(buffer(), pos)
2653 
2654  int *lineStarts = mLineStarts;
2655  int i, lineOfPos, lineOfEnd, nVisLines = mNVisibleLines;
2656  int charDelta = charsInserted - charsDeleted;
2657  int lineDelta = linesInserted - linesDeleted;
2658 
2659  /* If all of the changes were before the displayed text, the display
2660  doesn't change, just update the top line num and offset the line
2661  start entries and first and last characters */
2662  if ( pos + charsDeleted < mFirstChar ) {
2663  mTopLineNum += lineDelta;
2664  for ( i = 0; i < nVisLines && lineStarts[i] != -1; i++ )
2665  lineStarts[ i ] += charDelta;
2666  mFirstChar += charDelta;
2667  mLastChar += charDelta;
2668  *scrolled = 0;
2669  return;
2670  }
2671 
2672  /* The change began before the beginning of the displayed text, but
2673  part or all of the displayed text was deleted */
2674  if ( pos < mFirstChar ) {
2675  /* If some text remains in the window, anchor on that */
2676  if ( position_to_line( pos + charsDeleted, &lineOfEnd ) &&
2677  ++lineOfEnd < nVisLines && lineStarts[ lineOfEnd ] != -1 ) {
2678  mTopLineNum = max( 1, mTopLineNum + lineDelta );
2679  mFirstChar = rewind_lines(lineStarts[ lineOfEnd ] + charDelta, lineOfEnd );
2680  /* Otherwise anchor on original line number and recount everything */
2681  } else {
2682  if ( mTopLineNum > mNBufferLines + lineDelta ) {
2683  mTopLineNum = 1;
2684  mFirstChar = 0;
2685  } else
2686  mFirstChar = skip_lines( 0, mTopLineNum - 1, true );
2687  }
2688  calc_line_starts( 0, nVisLines - 1 );
2689  /* calculate lastChar by finding the end of the last displayed line */
2690  calc_last_char();
2691  *scrolled = 1;
2692  return;
2693  }
2694 
2695  /* If the change was in the middle of the displayed text (it usually is),
2696  salvage as much of the line starts array as possible by moving and
2697  offsetting the entries after the changed area, and re-counting the
2698  added lines or the lines beyond the salvaged part of the line starts
2699  array */
2700  if ( pos <= mLastChar ) {
2701  /* find line on which the change began */
2702  position_to_line( pos, &lineOfPos );
2703  /* salvage line starts after the changed area */
2704  if ( lineDelta == 0 ) {
2705  for ( i = lineOfPos + 1; i < nVisLines && lineStarts[ i ] != -1; i++ )
2706  lineStarts[ i ] += charDelta;
2707  } else if ( lineDelta > 0 ) {
2708  for ( i = nVisLines - 1; i >= lineOfPos + lineDelta + 1; i-- )
2709  lineStarts[ i ] = lineStarts[ i - lineDelta ] +
2710  ( lineStarts[ i - lineDelta ] == -1 ? 0 : charDelta );
2711  } else /* (lineDelta < 0) */ {
2712  for ( i = max( 0, lineOfPos + 1 ); i < nVisLines + lineDelta; i++ )
2713  lineStarts[ i ] = lineStarts[ i - lineDelta ] +
2714  ( lineStarts[ i - lineDelta ] == -1 ? 0 : charDelta );
2715  }
2716  /* fill in the missing line starts */
2717  if ( linesInserted >= 0 )
2718  calc_line_starts( lineOfPos + 1, lineOfPos + linesInserted );
2719  if ( lineDelta < 0 )
2720  calc_line_starts( nVisLines + lineDelta, nVisLines );
2721  /* calculate lastChar by finding the end of the last displayed line */
2722  calc_last_char();
2723  *scrolled = 0;
2724  return;
2725  }
2726 
2727  /* Change was past the end of the displayed text, but displayable by virtue
2728  of being an insert at the end of the buffer into visible blank lines */
2729  if ( empty_vlines() ) {
2730  position_to_line( pos, &lineOfPos );
2731  calc_line_starts( lineOfPos, lineOfPos + linesInserted );
2732  calc_last_char();
2733  *scrolled = 0;
2734  return;
2735  }
2736 
2737  /* Change was beyond the end of the buffer and not visible, do nothing */
2738  *scrolled = 0;
2739 }
2740 
2741 
2742 
2755 void Fl_Text_Display::calc_line_starts( int startLine, int endLine ) {
2756  int startPos, bufLen = mBuffer->length();
2757  int line, lineEnd, nextLineStart, nVis = mNVisibleLines;
2758  int *lineStarts = mLineStarts;
2759 
2760  /* Clean up (possibly) messy input parameters */
2761  if ( endLine < 0 ) endLine = 0;
2762  if ( endLine >= nVis ) endLine = nVis - 1;
2763  if ( startLine < 0 ) startLine = 0;
2764  if ( startLine >= nVis ) startLine = nVis - 1;
2765  if ( startLine > endLine )
2766  return;
2767 
2768  /* Find the last known good line number -> position mapping */
2769  if ( startLine == 0 ) {
2770  lineStarts[ 0 ] = mFirstChar;
2771  startLine = 1;
2772  }
2773  startPos = lineStarts[ startLine - 1 ];
2774 
2775  /* If the starting position is already past the end of the text,
2776  fill in -1's (means no text on line) and return */
2777  if ( startPos == -1 ) {
2778  for ( line = startLine; line <= endLine; line++ )
2779  lineStarts[ line ] = -1;
2780  return;
2781  }
2782 
2783  /* Loop searching for ends of lines and storing the positions of the
2784  start of the next line in lineStarts */
2785  for ( line = startLine; line <= endLine; line++ ) {
2786  find_line_end(startPos, true, &lineEnd, &nextLineStart);
2787  startPos = nextLineStart;
2788  if ( startPos >= bufLen ) {
2789  /* If the buffer ends with a newline or line break, put
2790  buf->length() in the next line start position (instead of
2791  a -1 which is the normal marker for an empty line) to
2792  indicate that the cursor may safely be displayed there */
2793  if ( line == 0 || ( lineStarts[ line - 1 ] != bufLen &&
2794  lineEnd != nextLineStart ) ) {
2795  lineStarts[ line ] = bufLen;
2796  line++;
2797  }
2798  break;
2799  }
2800  lineStarts[ line ] = startPos;
2801  }
2802 
2803  /* Set any entries beyond the end of the text to -1 */
2804  for ( ; line <= endLine; line++ )
2805  lineStarts[ line ] = -1;
2806 }
2807 
2808 
2809 
2817  int i;
2818  for (i = mNVisibleLines - 1; i >= 0 && mLineStarts[i] == -1; i--) ;
2819  mLastChar = i < 0 ? 0 : line_end(mLineStarts[i], true);
2820 }
2821 
2822 
2823 
2830 void Fl_Text_Display::scroll(int topLineNum, int horizOffset) {
2831  mTopLineNumHint = topLineNum;
2832  mHorizOffsetHint = horizOffset;
2833  resize(x(), y(), w(), h());
2834 }
2835 
2836 
2837 
2844 int Fl_Text_Display::scroll_(int topLineNum, int horizOffset) {
2845  /* Limit the requested scroll position to allowable values */
2846  if (topLineNum > mNBufferLines + 3 - mNVisibleLines)
2847  topLineNum = mNBufferLines + 3 - mNVisibleLines;
2848  if (topLineNum < 1) topLineNum = 1;
2849 
2850  if (horizOffset > longest_vline() - text_area.w)
2851  horizOffset = longest_vline() - text_area.w;
2852  if (horizOffset < 0) horizOffset = 0;
2853 
2854  /* Do nothing if scroll position hasn't actually changed or there's no
2855  window to draw in yet */
2856  if (mHorizOffset == horizOffset && mTopLineNum == topLineNum)
2857  return 0;
2858 
2859  /* If the vertical scroll position has changed, update the line
2860  starts array and related counters in the text display */
2861  offset_line_starts(topLineNum);
2862 
2863  /* Just setting mHorizOffset is enough information for redisplay */
2864  mHorizOffset = horizOffset;
2865 
2866  // redraw all text
2868  return 1;
2869 }
2870 
2871 
2872 
2880  /* The vertical scrollbar value and slider size directly represent the top
2881  line number, and the number of visible lines respectively. The scroll
2882  bar maximum value is chosen to generally represent the size of the whole
2883  buffer, with minor adjustments to keep the scrollbar widget happy */
2884 #ifdef DEBUG
2885  printf("Fl_Text_Display::update_v_scrollbar():\n"
2886  " mTopLineNum=%d, mNVisibleLines=%d, mNBufferLines=%d\n",
2888 #endif // DEBUG
2889 
2891  mVScrollBar->linesize(3);
2892 }
2893 
2894 
2902  int sliderMax = max(longest_vline(), text_area.w + mHorizOffset);
2903  mHScrollBar->value( mHorizOffset, text_area.w, 0, sliderMax );
2904 }
2905 
2906 
2907 
2912  if (b->value() == textD->mTopLineNum) return;
2913  textD->scroll(b->value(), textD->mHorizOffset);
2914 }
2915 
2916 
2917 
2922  if (b->value() == textD->mHorizOffset) return;
2923  textD->scroll(textD->mTopLineNum, b->value());
2924 }
2925 
2926 
2927 
2936 // This draw_line_numbers() method based on patch from
2937 // http://www.mail-archive.com/fltk-dev@easysw.com/msg06376.html
2938 // altered to support line numbers right alignment. -LZA / STR #2621
2939 //
2940 void Fl_Text_Display::draw_line_numbers(bool /*clearAll*/) {
2941  int Y, line, visLine, lineStart;
2942  char lineNumString[16];
2943  int lineHeight = mMaxsize;
2944  int isactive = active_r() ? 1 : 0;
2945 
2946  // Don't draw if lineNumWidth == 0 (line numbers are hidden),
2947  // or widget is not yet realized
2948  if (mLineNumWidth <= 0 || !visible_r())
2949  return;
2950 
2951  // Make sure we set the correct clipping range for line numbers.
2952  // Take scrollbars and positions into account.
2953  int hscroll_h = mHScrollBar->visible() ? mHScrollBar->h() : 0;
2954  int xoff = Fl::box_dx(box());
2955  int yoff = Fl::box_dy(box()) + ((scrollbar_align()&FL_ALIGN_TOP)?hscroll_h:0);
2956 
2957 #ifndef LINENUM_LEFT_OF_VSCROLL
2958  int vscroll_w = mVScrollBar->visible() ? mVScrollBar->w() : 0;
2960  xoff += vscroll_w;
2961 #endif
2962 
2963  Fl_Color fgcolor = isactive ? linenumber_fgcolor() : fl_inactive(linenumber_fgcolor());
2964  Fl_Color bgcolor = isactive ? linenumber_bgcolor() : fl_inactive(linenumber_bgcolor());
2965  fl_push_clip(x() + xoff,
2966  y() + yoff,
2967  mLineNumWidth,
2968  h() - Fl::box_dw(box()) - hscroll_h);
2969  {
2970  // Set background color for line number area -- LZA / STR# 2621
2971  // Erase background
2972  fl_color(bgcolor);
2973  fl_rectf(x()+xoff, y(), mLineNumWidth, h());
2974 
2975  // Draw separator line
2976  //fl_color(180,180,180);
2977  //fl_line(x()+mLineNumWidth-1, y(), x()+mLineNumWidth-1, y()+h());
2978 
2979  // Draw line number text
2981 
2982  Y = y() + yoff;
2984 
2985  // set font color for line numbers
2986  fl_color(fgcolor);
2987  for (visLine=0; visLine < mNVisibleLines; visLine++) {
2988  lineStart = mLineStarts[visLine];
2989  if (lineStart != -1 && (lineStart==0 || buffer()->char_at(lineStart-1)=='\n')) {
2990  sprintf(lineNumString, linenumber_format(), line);
2991  int xx = x() + xoff + 3,
2992  yy = Y + 3,
2993  ww = mLineNumWidth - (3*2),
2994  hh = lineHeight;
2995  fl_draw(lineNumString, xx, yy, ww, hh, linenumber_align(), 0, 0);
2996  //DEBUG fl_rect(xx, yy, ww, hh);
2997  line++;
2998  } else {
2999  if (visLine == 0) line++;
3000  }
3001  Y += lineHeight;
3002  }
3003  }
3004  fl_pop_clip();
3005 }
3006 
3007 static int max( int i1, int i2 ) {
3008  return i1 >= i2 ? i1 : i2;
3009 }
3010 
3011 static int min( int i1, int i2 ) {
3012  return i1 <= i2 ? i1 : i2;
3013 }
3014 
3015 
3016 
3020 static int countlines( const char *string ) {
3021  IS_UTF8_ALIGNED(string)
3022 
3023  const char * c;
3024  int lineCount = 0;
3025 
3026  if (!string) return 0;
3027 
3028  for ( c = string; *c != '\0'; c++ )
3029  if ( *c == '\n' ) lineCount++;
3030  return lineCount;
3031 }
3032 
3033 
3034 
3035 
3041 int Fl_Text_Display::measure_vline( int visLineNum ) const {
3042  int lineLen = vline_length( visLineNum );
3043  int lineStartPos = mLineStarts[ visLineNum ];
3044  if (lineStartPos < 0 || lineLen == 0) return 0;
3045  return handle_vline(GET_WIDTH, lineStartPos, lineLen, 0, 0, 0, 0, 0, 0);
3046 }
3047 
3048 
3049 
3055  return (mNVisibleLines > 0) && (mLineStarts[ mNVisibleLines - 1 ] == -1);
3056 }
3057 
3058 
3059 
3069 int Fl_Text_Display::vline_length( int visLineNum ) const {
3070  int nextLineStart, lineStartPos;
3071 
3072  if (visLineNum < 0 || visLineNum >= mNVisibleLines)
3073  return (0);
3074 
3075  lineStartPos = mLineStarts[ visLineNum ];
3076 
3077  if ( lineStartPos == -1 )
3078  return 0;
3079 
3080  if ( visLineNum + 1 >= mNVisibleLines )
3081  return mLastChar - lineStartPos;
3082 
3083  nextLineStart = mLineStarts[ visLineNum + 1 ];
3084  if ( nextLineStart == -1 )
3085  return mLastChar - lineStartPos;
3086 
3087  int nextLineStartMinus1 = buffer()->prev_char(nextLineStart);
3088  if (wrap_uses_character(nextLineStartMinus1))
3089  return nextLineStartMinus1 - lineStartPos;
3090 
3091  return nextLineStart - lineStartPos;
3092 }
3093 
3094 
3095 
3116 void Fl_Text_Display::find_wrap_range(const char *deletedText, int pos,
3117  int nInserted, int nDeleted,
3118  int *modRangeStart, int *modRangeEnd,
3119  int *linesInserted, int *linesDeleted) {
3120  IS_UTF8_ALIGNED(deletedText)
3121  IS_UTF8_ALIGNED2(buffer(), pos)
3122 
3123  int length, retPos, retLines, retLineStart, retLineEnd;
3124  Fl_Text_Buffer *deletedTextBuf, *buf = buffer();
3125  int nVisLines = mNVisibleLines;
3126  int *lineStarts = mLineStarts;
3127  int countFrom, countTo, lineStart, adjLineStart, i;
3128  int visLineNum = 0, nLines = 0;
3129 
3130  /*
3131  ** Determine where to begin searching: either the previous newline, or
3132  ** if possible, limit to the start of the (original) previous displayed
3133  ** line, using information from the existing line starts array
3134  */
3135  if (pos >= mFirstChar && pos <= mLastChar) {
3136  for (i=nVisLines-1; i>0; i--) {
3137  if (lineStarts[i] != -1 && pos >= lineStarts[i]) {
3138  break;
3139  }
3140  }
3141  if (i > 0) {
3142  countFrom = lineStarts[i-1];
3143  visLineNum = i-1;
3144  } else {
3145  countFrom = buf->line_start(pos);
3146  }
3147  } else {
3148  countFrom = buf->line_start(pos);
3149  }
3150 
3151  IS_UTF8_ALIGNED2(buf, countFrom)
3152 
3153  /*
3154  ** Move forward through the (new) text one line at a time, counting
3155  ** displayed lines, and looking for either a real newline, or for the
3156  ** line starts to re-sync with the original line starts array
3157  */
3158  lineStart = countFrom;
3159  *modRangeStart = countFrom;
3160  for (;;) {
3161 
3162  /* advance to the next line. If the line ended in a real newline
3163  or the end of the buffer, that's far enough */
3164  wrapped_line_counter(buf, lineStart, buf->length(), 1, true, 0,
3165  &retPos, &retLines, &retLineStart, &retLineEnd);
3166  if (retPos >= buf->length()) {
3167  countTo = buf->length();
3168  *modRangeEnd = countTo;
3169  if (retPos != retLineEnd)
3170  nLines++;
3171  break;
3172  } else {
3173  lineStart = retPos;
3174  }
3175  nLines++;
3176  if (lineStart > pos + nInserted && buf->char_at(buf->prev_char(lineStart)) == '\n') {
3177  countTo = lineStart;
3178  *modRangeEnd = lineStart;
3179  break;
3180  }
3181 
3182  /* Don't try to resync in continuous wrap mode with non-fixed font
3183  sizes; it would result in a chicken-and-egg dependency between
3184  the calculations for the inserted and the deleted lines.
3185  If we're in that mode, the number of deleted lines is calculated in
3186  advance, without resynchronization, so we shouldn't resynchronize
3187  for the inserted lines either. */
3188  if (mSuppressResync)
3189  continue;
3190 
3191  /* check for synchronization with the original line starts array
3192  before pos, if so, the modified range can begin later */
3193  if (lineStart <= pos) {
3194  while (visLineNum<nVisLines && lineStarts[visLineNum] < lineStart)
3195  visLineNum++;
3196  if (visLineNum < nVisLines && lineStarts[visLineNum] == lineStart) {
3197  countFrom = lineStart;
3198  nLines = 0;
3199  if (visLineNum+1 < nVisLines && lineStarts[visLineNum+1] != -1)
3200  *modRangeStart = min(pos, buf->prev_char(lineStarts[visLineNum+1]));
3201  else
3202  *modRangeStart = countFrom;
3203  } else
3204  *modRangeStart = min(*modRangeStart, buf->prev_char(lineStart));
3205  }
3206 
3207  /* check for synchronization with the original line starts array
3208  after pos, if so, the modified range can end early */
3209  else if (lineStart > pos + nInserted) {
3210  adjLineStart = lineStart - nInserted + nDeleted;
3211  while (visLineNum<nVisLines && lineStarts[visLineNum]<adjLineStart)
3212  visLineNum++;
3213  if (visLineNum < nVisLines && lineStarts[visLineNum] != -1 &&
3214  lineStarts[visLineNum] == adjLineStart) {
3215  countTo = line_end(lineStart, true);
3216  *modRangeEnd = lineStart;
3217  break;
3218  }
3219  }
3220  }
3221  *linesInserted = nLines;
3222 
3223 
3224  /* Count deleted lines between countFrom and countTo as the text existed
3225  before the modification (that is, as if the text between pos and
3226  pos+nInserted were replaced by "deletedText"). This extra context is
3227  necessary because wrapping can occur outside of the modified region
3228  as a result of adding or deleting text in the region. This is done by
3229  creating a textBuffer containing the deleted text and the necessary
3230  additional context, and calling the wrappedLineCounter on it.
3231 
3232  NOTE: This must not be done in continuous wrap mode when the font
3233  width is not fixed. In that case, the calculation would try
3234  to access style information that is no longer available (deleted
3235  text), or out of date (updated highlighting), possibly leading
3236  to completely wrong calculations and/or even crashes eventually.
3237  (This is not theoretical; it really happened.)
3238 
3239  In that case, the calculation of the number of deleted lines
3240  has happened before the buffer was modified (only in that case,
3241  because resynchronization of the line starts is impossible
3242  in that case, which makes the whole calculation less efficient).
3243  */
3244  if (mSuppressResync) {
3245  *linesDeleted = mNLinesDeleted;
3246  mSuppressResync = 0;
3247  return;
3248  }
3249 
3250  length = (pos-countFrom) + nDeleted +(countTo-(pos+nInserted));
3251  deletedTextBuf = new Fl_Text_Buffer(length);
3252  deletedTextBuf->copy(buffer(), countFrom, pos, 0);
3253  if (nDeleted != 0)
3254  deletedTextBuf->insert(pos-countFrom, deletedText);
3255  deletedTextBuf->copy(buffer(), pos+nInserted, countTo, pos-countFrom+nDeleted);
3256  /* Note that we need to take into account an offset for the style buffer:
3257  the deletedTextBuf can be out of sync with the style buffer. */
3258  wrapped_line_counter(deletedTextBuf, 0, length, INT_MAX, true, countFrom,
3259  &retPos, &retLines, &retLineStart, &retLineEnd, false);
3260  delete deletedTextBuf;
3261  *linesDeleted = retLines;
3262  mSuppressResync = 0;
3263 }
3264 
3265 
3266 
3284 void Fl_Text_Display::measure_deleted_lines(int pos, int nDeleted) {
3285  IS_UTF8_ALIGNED2(buffer(), pos)
3286 
3287  int retPos, retLines, retLineStart, retLineEnd;
3288  Fl_Text_Buffer *buf = buffer();
3289  int nVisLines = mNVisibleLines;
3290  int *lineStarts = mLineStarts;
3291  int countFrom, lineStart;
3292  int nLines = 0, i;
3293  /*
3294  ** Determine where to begin searching: either the previous newline, or
3295  ** if possible, limit to the start of the (original) previous displayed
3296  ** line, using information from the existing line starts array
3297  */
3298  if (pos >= mFirstChar && pos <= mLastChar) {
3299  for (i=nVisLines-1; i>0; i--)
3300  if (lineStarts[i] != -1 && pos >= lineStarts[i])
3301  break;
3302  if (i > 0) {
3303  countFrom = lineStarts[i-1];
3304  } else
3305  countFrom = buf->line_start(pos);
3306  } else
3307  countFrom = buf->line_start(pos);
3308 
3309  /*
3310  ** Move forward through the (new) text one line at a time, counting
3311  ** displayed lines, and looking for either a real newline, or for the
3312  ** line starts to re-sync with the original line starts array
3313  */
3314  lineStart = countFrom;
3315  for (;;) {
3316  /* advance to the next line. If the line ended in a real newline
3317  or the end of the buffer, that's far enough */
3318  wrapped_line_counter(buf, lineStart, buf->length(), 1, true, 0,
3319  &retPos, &retLines, &retLineStart, &retLineEnd);
3320  if (retPos >= buf->length()) {
3321  if (retPos != retLineEnd)
3322  nLines++;
3323  break;
3324  } else
3325  lineStart = retPos;
3326  nLines++;
3327  if (lineStart > pos + nDeleted && buf->char_at(lineStart-1) == '\n') {
3328  break;
3329  }
3330 
3331  /* Unlike in the findWrapRange() function above, we don't try to
3332  resync with the line starts, because we don't know the length
3333  of the inserted text yet, nor the updated style information.
3334 
3335  Because of that, we also shouldn't resync with the line starts
3336  after the modification either, because we must perform the
3337  calculations for the deleted and inserted lines in the same way.
3338 
3339  This can result in some unnecessary recalculation and redrawing
3340  overhead, and therefore we should only use this two-phase mode
3341  of calculation when it's really needed (continuous wrap + variable
3342  font width). */
3343  }
3344  mNLinesDeleted = nLines;
3345  mSuppressResync = 1;
3346 }
3347 
3348 
3349 
3377  int maxPos, int maxLines, bool startPosIsLineStart, int styleBufOffset,
3378  int *retPos, int *retLines, int *retLineStart, int *retLineEnd,
3379  bool countLastLineMissingNewLine) const {
3380  IS_UTF8_ALIGNED2(buf, startPos)
3381  IS_UTF8_ALIGNED2(buf, maxPos)
3382 
3383  int lineStart, newLineStart = 0, b, p, colNum, wrapMarginPix;
3384  int i, foundBreak;
3385  double width;
3386  int nLines = 0;
3387  unsigned int c;
3388 
3389  /* Set the wrap margin to the wrap column or the view width */
3390  if (mWrapMarginPix != 0) {
3391  wrapMarginPix = mWrapMarginPix;
3392  } else {
3393  wrapMarginPix = text_area.w;
3394  }
3395 
3396  /* Find the start of the line if the start pos is not marked as a
3397  line start. */
3398  if (startPosIsLineStart)
3399  lineStart = startPos;
3400  else
3401  lineStart = line_start(startPos);
3402 
3403  /*
3404  ** Loop until position exceeds maxPos or line count exceeds maxLines.
3405  ** (actually, continues beyond maxPos to end of line containing maxPos,
3406  ** in case later characters cause a word wrap back before maxPos)
3407  */
3408  colNum = 0;
3409  width = 0;
3410  for (p=lineStart; p<buf->length(); p=buf->next_char(p)) {
3411  c = buf->char_at(p); // UCS-4
3412 
3413  /* If the character was a newline, count the line and start over,
3414  otherwise, add it to the width and column counts */
3415  if (c == '\n') {
3416  if (p >= maxPos) {
3417  *retPos = maxPos;
3418  *retLines = nLines;
3419  *retLineStart = lineStart;
3420  *retLineEnd = maxPos;
3421  return;
3422  }
3423  nLines++;
3424  int p1 = buf->next_char(p);
3425  if (nLines >= maxLines) {
3426  *retPos = p1;
3427  *retLines = nLines;
3428  *retLineStart = p1;
3429  *retLineEnd = p;
3430  return;
3431  }
3432  lineStart = p1;
3433  colNum = 0;
3434  width = 0;
3435  } else {
3436  const char *s = buf->address(p);
3437  colNum++;
3438  // FIXME: it is not a good idea to simply add character widths because on
3439  // some platforms, the width is a floating point value and depends on the
3440  // previous character as well.
3441  width += measure_proportional_character(s, (int)width, p+styleBufOffset);
3442  }
3443 
3444  /* If character exceeded wrap margin, find the break point and wrap there */
3445  if (width > wrapMarginPix) {
3446  foundBreak = false;
3447  for (b=p; b>=lineStart; b=buf->prev_char(b)) {
3448  c = buf->char_at(b);
3449  if (c == '\t' || c == ' ') {
3450  newLineStart = buf->next_char(b);
3451  colNum = 0;
3452  width = 0;
3453  int iMax = buf->next_char(p);
3454  for (i=buf->next_char(b); i<iMax; i = buf->next_char(i)) {
3455  width += measure_proportional_character(buf->address(i), (int)width,
3456  i+styleBufOffset);
3457  colNum++;
3458  }
3459  foundBreak = true;
3460  break;
3461  }
3462  }
3463  if (b<lineStart) b = lineStart;
3464  if (!foundBreak) { /* no whitespace, just break at margin */
3465  newLineStart = max(p, buf->next_char(lineStart));
3466  colNum++;
3467  if (b >= buf->length()) { // STR #2730
3468  width = 0;
3469  } else {
3470  const char *s = buf->address(b);
3471  width = measure_proportional_character(s, 0, p+styleBufOffset);
3472  }
3473  }
3474  if (p >= maxPos) {
3475  *retPos = maxPos;
3476  *retLines = maxPos < newLineStart ? nLines : nLines + 1;
3477  *retLineStart = maxPos < newLineStart ? lineStart : newLineStart;
3478  *retLineEnd = maxPos;
3479  return;
3480  }
3481  nLines++;
3482  if (nLines >= maxLines) {
3483  *retPos = foundBreak ? buf->next_char(b) : max(p, buf->next_char(lineStart));
3484  *retLines = nLines;
3485  *retLineStart = lineStart;
3486  *retLineEnd = foundBreak ? b : p;
3487  return;
3488  }
3489  lineStart = newLineStart;
3490  }
3491  }
3492 
3493  /* reached end of buffer before reaching pos or line target */
3494  *retPos = buf->length();
3495  *retLines = nLines;
3496  if (countLastLineMissingNewLine && colNum > 0)
3497  *retLines = buf->next_char(*retLines);
3498  *retLineStart = lineStart;
3499  *retLineEnd = buf->length();
3500 }
3501 
3502 
3503 
3525 double Fl_Text_Display::measure_proportional_character(const char *s, int xPix, int pos) const {
3526  IS_UTF8_ALIGNED(s)
3527 
3528  if (*s=='\t') {
3529  int tab = (int)col_to_x(mBuffer->tab_distance());
3530  return (((xPix/tab)+1)*tab) - xPix;
3531  }
3532 
3533  int charLen = fl_utf8len1(*s), style = 0;
3534  if (mStyleBuffer) {
3535  style = mStyleBuffer->byte_at(pos);
3536  }
3537  return string_width(s, charLen, style);
3538 }
3539 
3540 
3541 
3559 void Fl_Text_Display::find_line_end(int startPos, bool startPosIsLineStart,
3560  int *lineEnd, int *nextLineStart) const {
3561  IS_UTF8_ALIGNED2(buffer(), startPos)
3562 
3563  int retLines, retLineStart;
3564 
3565  /* if we're not wrapping use more efficient BufEndOfLine */
3566  if (!mContinuousWrap) {
3567  int le = buffer()->line_end(startPos);
3568  int ls = buffer()->next_char(le);
3569  *lineEnd = le;
3570  *nextLineStart = min(buffer()->length(), ls);
3571  return;
3572  }
3573 
3574  /* use the wrapped line counter routine to count forward one line */
3575  wrapped_line_counter(buffer(), startPos, buffer()->length(),
3576  1, startPosIsLineStart, 0, nextLineStart, &retLines,
3577  &retLineStart, lineEnd);
3578 }
3579 
3580 
3581 
3603 int Fl_Text_Display::wrap_uses_character(int lineEndPos) const {
3604  IS_UTF8_ALIGNED2(buffer(), lineEndPos)
3605 
3606  unsigned int c;
3607 
3608  if (!mContinuousWrap || lineEndPos == buffer()->length())
3609  return 1;
3610 
3611  c = buffer()->char_at(lineEndPos);
3612  return c == '\n' || ((c == '\t' || c == ' ') &&
3613  lineEndPos + 1 < buffer()->length());
3614 }
3615 
3616 
3617 
3630 void Fl_Text_Display::extend_range_for_styles( int *startpos, int *endpos ) {
3631  IS_UTF8_ALIGNED2(buffer(), (*startpos))
3632  IS_UTF8_ALIGNED2(buffer(), (*endpos))
3633 
3635  int extended = 0;
3636 
3637  /* The peculiar protocol used here is that modifications to the style
3638  buffer are marked by selecting them with the buffer's primary Fl_Text_Selection.
3639  The style buffer is usually modified in response to a modify callback on
3640  the text buffer BEFORE Fl_Text_Display.c's modify callback, so that it can keep
3641  the style buffer in step with the text buffer. The style-update
3642  callback can't just call for a redraw, because Fl_Text_Display hasn't processed
3643  the original text changes yet. Anyhow, to minimize redrawing and to
3644  avoid the complexity of scheduling redraws later, this simple protocol
3645  tells the text display's buffer modify callback to extend its redraw
3646  range to show the text color/and font changes as well. */
3647  if ( sel->selected() ) {
3648  if ( sel->start() < *startpos ) {
3649  *startpos = sel->start();
3650  // somewhere while deleting, alignment is lost. We do this just to be sure.
3651  *startpos = buffer()->utf8_align(*startpos);
3652  IS_UTF8_ALIGNED2(buffer(), (*startpos))
3653  extended = 1;
3654  }
3655  if ( sel->end() > *endpos ) {
3656  *endpos = sel->end();
3657  *endpos = buffer()->utf8_align(*endpos);
3658  IS_UTF8_ALIGNED2(buffer(), (*endpos))
3659  extended = 1;
3660  }
3661  }
3662 
3663  /* If the Fl_Text_Selection was extended due to a style change, and some of the
3664  fonts don't match in spacing, extend redraw area to end of line to
3665  redraw characters exposed by possible font size changes */
3666  if ( extended )
3667  *endpos = mBuffer->line_end( *endpos ) + 1;
3668 
3669  IS_UTF8_ALIGNED2(buffer(), (*endpos))
3670 }
3671 
3672 
3673 
3680  // don't even try if there is no associated text buffer!
3681  if (!buffer()) { draw_box(); return; }
3682 
3683  fl_push_clip(x(),y(),w(),h()); // prevent drawing outside widget area
3684 
3685  // background color -- change if inactive
3686  Fl_Color bgcolor = active_r() ? color() : fl_inactive(color());
3687 
3688  // draw the non-text, non-scrollbar areas.
3689  if (damage() & FL_DAMAGE_ALL) {
3690  // printf("drawing all (box = %d)\n", box());
3692  // if to printer, draw the background
3693  fl_rectf(text_area.x, text_area.y, text_area.w, text_area.h, bgcolor);
3694  }
3695  // draw the box()
3696  int W = w(), H = h();
3697  draw_box(box(), x(), y(), W, H, bgcolor);
3698 
3699  if (mHScrollBar->visible())
3700  W -= scrollbar_width();
3701  if (mVScrollBar->visible())
3702  H -= scrollbar_width();
3703 
3704  // left margin
3707  bgcolor);
3708 
3709  // right margin
3712  bgcolor);
3713 
3714  // top margin
3716  text_area.w, TOP_MARGIN, bgcolor);
3717 
3718  // bottom margin
3720  text_area.w, BOTTOM_MARGIN, bgcolor);
3721 
3722  // draw that little box in the corner of the scrollbars
3723  if (mVScrollBar->visible() && mHScrollBar->visible())
3725  mVScrollBar->w(), mHScrollBar->h(),
3726  FL_GRAY);
3727  //draw_line_numbers(true); // commented out STR# 2621 / LZA
3728  }
3729  else if (damage() & (FL_DAMAGE_SCROLL | FL_DAMAGE_EXPOSE)) {
3730  // printf("blanking previous cursor extrusions at Y: %d\n", mCursorOldY);
3731  // CET - FIXME - save old cursor position instead and just draw side needed?
3733  text_area.y,
3735  text_area.h);
3737  LEFT_MARGIN, mMaxsize, bgcolor);
3739  RIGHT_MARGIN, mMaxsize, bgcolor);
3740  fl_pop_clip();
3741  }
3742 
3743  // draw the scrollbars
3744  if (damage() & (FL_DAMAGE_ALL | FL_DAMAGE_CHILD)) {
3747  }
3750 
3751  // draw all of the text
3752  if (damage() & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE)) {
3753  //printf("drawing all text\n");
3754  int X, Y, W, H;
3756  X, Y, W, H)) {
3757  // Draw text using the intersected clipping box...
3758  // (this sets the clipping internally)
3759  draw_text(X, Y, W, H);
3760  } else {
3761  // Draw the whole area...
3763  }
3764  }
3765  else if (damage() & FL_DAMAGE_SCROLL) {
3766  // draw some lines of text
3768  text_area.w, text_area.h);
3769  //printf("drawing text from %d to %d\n", damage_range1_start, damage_range1_end);
3771  if (damage_range2_end != -1) {
3772  //printf("drawing text from %d to %d\n", damage_range2_start, damage_range2_end);
3774  }
3777  fl_pop_clip();
3778  }
3779 
3780  // draw the text cursor
3781  int start, end;
3782  int has_selection = buffer()->selection_position(&start, &end);
3784  && (
3785 #ifdef __APPLE__
3787 #endif
3788  !has_selection || mCursorPos < start || mCursorPos > end) &&
3789  mCursorOn && Fl::focus() == (Fl_Widget*)this ) {
3791  text_area.y,
3793  text_area.h);
3794 
3795  int X = 0, Y = 0;
3796  if (position_to_xy(mCursorPos, &X, &Y)) {
3797  draw_cursor(X, Y);
3798  mCursorOldY = Y;
3799  }
3800  // else puts("position_to_xy() failed - unable to draw cursor!");
3801  //printf("drew cursor at pos: %d (%d,%d)\n", mCursorPos, X, Y);
3802  fl_pop_clip();
3803  }
3804 
3805  // Important to do this at end of this method, otherwise line numbers
3806  // will not scroll with the text edit area
3807  draw_line_numbers(true);
3808 
3809  fl_pop_clip();
3810 }
3811 
3812 
3813 
3814 // this processes drag events due to mouse for Fl_Text_Display and
3815 // also drags due to cursor movement with shift held down for
3816 // Fl_Text_Editor
3819  if (pos >= d->dragPos) {
3820  d->buffer()->select(d->dragPos, pos);
3821  } else {
3822  d->buffer()->select(pos, d->dragPos);
3823  }
3824  d->insert_position(pos);
3825  } else if (d->dragType == Fl_Text_Display::DRAG_WORD) {
3826  if (pos >= d->dragPos) {
3827  d->insert_position(d->word_end(pos));
3828  d->buffer()->select(d->word_start(d->dragPos), d->word_end(pos));
3829  } else {
3830  d->insert_position(d->word_start(pos));
3831  d->buffer()->select(d->word_start(pos), d->word_end(d->dragPos));
3832  }
3833  } else if (d->dragType == Fl_Text_Display::DRAG_LINE) {
3834  if (pos >= d->dragPos) {
3835  d->insert_position(d->buffer()->line_end(pos)+1);
3836  d->buffer()->select(d->buffer()->line_start(d->dragPos),
3837  d->buffer()->line_end(pos)+1);
3838  } else {
3839  d->insert_position(d->buffer()->line_start(pos));
3840  d->buffer()->select(d->buffer()->line_start(pos),
3841  d->buffer()->line_end(d->dragPos)+1);
3842  }
3843  }
3844 }
3845 
3846 
3847 
3855 void Fl_Text_Display::scroll_timer_cb(void *user_data) {
3857  int pos;
3858  switch (scroll_direction) {
3859  case 1: // mouse is to the right, scroll left
3860  w->scroll(w->mTopLineNum, w->mHorizOffset + scroll_amount);
3861  pos = w->xy_to_position(w->text_area.x + w->text_area.w, scroll_y, CURSOR_POS);
3862  break;
3863  case 2: // mouse is to the left, scroll right
3864  w->scroll(w->mTopLineNum, w->mHorizOffset + scroll_amount);
3865  pos = w->xy_to_position(w->text_area.x, scroll_y, CURSOR_POS);
3866  break;
3867  case 3: // mouse is above, scroll down
3868  w->scroll(w->mTopLineNum + scroll_amount, w->mHorizOffset);
3869  pos = w->xy_to_position(scroll_x, w->text_area.y, CURSOR_POS);
3870  break;
3871  case 4: // mouse is below, scroll up
3872  w->scroll(w->mTopLineNum + scroll_amount, w->mHorizOffset);
3873  pos = w->xy_to_position(scroll_x, w->text_area.y + w->text_area.h, CURSOR_POS);
3874  break;
3875  default:
3876  return;
3877  }
3878  fl_text_drag_me(pos, w);
3880 }
3881 
3882 
3883 
3887 int Fl_Text_Display::handle(int event) {
3888  if (!buffer()) return 0;
3889  // This isn't very elegant!
3891  !dragging && event != FL_LEAVE && event != FL_ENTER &&
3892  event != FL_MOVE && event != FL_FOCUS && event != FL_UNFOCUS &&
3893  event != FL_KEYBOARD && event != FL_KEYUP) {
3894  return Fl_Group::handle(event);
3895  }
3896 
3897  switch (event) {
3898  case FL_ENTER:
3899  case FL_MOVE:
3900  if (active_r()) {
3903  else window()->cursor(FL_CURSOR_DEFAULT);
3904  return 1;
3905  } else {
3906  return 0;
3907  }
3908 
3909  case FL_LEAVE:
3910  case FL_HIDE:
3911  if (active_r() && window()) {
3913 
3914  return 1;
3915  } else {
3916  return 0;
3917  }
3918 
3919  case FL_PUSH: {
3920  if (active_r() && window()) {
3923  else window()->cursor(FL_CURSOR_DEFAULT);
3924  }
3925 
3926  if (Fl::focus() != this) {
3927  Fl::focus(this);
3928  handle(FL_FOCUS);
3929  }
3930  if (Fl_Group::handle(event)) return 1;
3931  if (Fl::event_state()&FL_SHIFT) return handle(FL_DRAG);
3932  dragging = 1;
3934  dragPos = pos;
3935  if (buffer()->primary_selection()->includes(pos)) {
3937  return 1;
3938  }
3940  if (dragType == DRAG_CHAR) {
3941  buffer()->unselect();
3942 // Fl::copy("", 0, 0); /* removed for STR 2668 */
3943  }
3944  else if (dragType == DRAG_WORD) {
3945  buffer()->select(word_start(pos), word_end(pos));
3946  dragPos = word_start(pos);
3947  }
3948 
3949  if (buffer()->primary_selection()->selected())
3950  insert_position(buffer()->primary_selection()->end());
3951  else
3952  insert_position(pos);
3954  return 1;
3955  }
3956 
3957  case FL_DRAG: {
3958  if (dragType==DRAG_NONE)
3959  return 1;
3960  if (dragType==DRAG_START_DND) {
3961  if (!Fl::event_is_click() && Fl::dnd_text_ops()) {
3962  const char* copy = buffer()->selection_text();
3963 #ifdef __APPLE__
3964  Fl_X::dnd(1);
3965 #else
3966  Fl::dnd();
3967 #endif
3968  free((void*)copy);
3969  }
3970  return 1;
3971  }
3972  int X = Fl::event_x(), Y = Fl::event_y(), pos = insert_position();
3973  // if we leave the text_area, we start a timer event
3974  // that will take care of scrolling and selecting
3975  if (Y < text_area.y) {
3976  scroll_x = X;
3977  scroll_amount = (Y - text_area.y) / 5 - 1;
3978  if (!scroll_direction) {
3979  Fl::add_timeout(.01, scroll_timer_cb, this);
3980  }
3981  scroll_direction = 3;
3982  } else if (Y >= text_area.y+text_area.h) {
3983  scroll_x = X;
3984  scroll_amount = (Y - text_area.y - text_area.h) / 5 + 1;
3985  if (!scroll_direction) {
3986  Fl::add_timeout(.01, scroll_timer_cb, this);
3987  }
3988  scroll_direction = 4;
3989  } else if (X < text_area.x) {
3990  scroll_y = Y;
3991  scroll_amount = (X - text_area.x) / 2 - 1;
3992  if (!scroll_direction) {
3993  Fl::add_timeout(.01, scroll_timer_cb, this);
3994  }
3995  scroll_direction = 2;
3996  } else if (X >= text_area.x+text_area.w) {
3997  scroll_y = Y;
3998  scroll_amount = (X - text_area.x - text_area.w) / 2 + 1;
3999  if (!scroll_direction) {
4000  Fl::add_timeout(.01, scroll_timer_cb, this);
4001  }
4002  scroll_direction = 1;
4003  } else {
4004  if (scroll_direction) {
4006  scroll_direction = 0;
4007  }
4008  pos = xy_to_position(X, Y, CURSOR_POS);
4009  pos = buffer()->next_char(pos);
4010  }
4011  fl_text_drag_me(pos, this);
4012  return 1;
4013  }
4014 
4015  case FL_RELEASE: {
4016  if (Fl::event_is_click() && (! Fl::event_clicks()) &&
4017  buffer()->primary_selection()->includes(dragPos) && !(Fl::event_state()&FL_SHIFT) ) {
4018  buffer()->unselect(); // clicking in the selection: unselect and move cursor
4020  return 1;
4021  } else if (Fl::event_clicks() == DRAG_LINE && Fl::event_button() == FL_LEFT_MOUSE) {
4022  buffer()->select(buffer()->line_start(dragPos), buffer()->next_char(buffer()->line_end(dragPos)));
4024  dragType = DRAG_CHAR;
4025  } else {
4026  dragging = 0;
4027  if (scroll_direction) {
4029  scroll_direction = 0;
4030  }
4031 
4032  // convert from WORD or LINE selection to CHAR
4033  /*if (insert_position() >= dragPos)
4034  dragPos = buffer()->primary_selection()->start();
4035  else
4036  dragPos = buffer()->primary_selection()->end();*/
4037  dragType = DRAG_CHAR;
4038  }
4039 
4040  const char* copy = buffer()->selection_text();
4041  if (*copy) Fl::copy(copy, (int) strlen(copy), 0);
4042  free((void*)copy);
4043  return 1;
4044  }
4045 
4046  case FL_MOUSEWHEEL:
4047  if (Fl::event_dy()) return mVScrollBar->handle(event);
4048  else return mHScrollBar->handle(event);
4049 
4050  case FL_UNFOCUS:
4051  if (active_r() && window()) window()->cursor(FL_CURSOR_DEFAULT);
4052  case FL_FOCUS:
4053  if (buffer()->selected()) {
4054  int start, end;
4055  if (buffer()->selection_position(&start, &end))
4057  }
4058  if (buffer()->secondary_selected()) {
4059  int start, end;
4060  if (buffer()->secondary_selection_position(&start, &end))
4062  }
4063  if (buffer()->highlight()) {
4064  int start, end;
4065  if (buffer()->highlight_position(&start, &end))
4067  }
4068  return 1;
4069 
4070  case FL_KEYBOARD:
4071  // Copy?
4072  if ((Fl::event_state()&(FL_CTRL|FL_COMMAND)) && Fl::event_key()=='c') {
4073  if (!buffer()->selected()) return 1;
4074  const char *copy = buffer()->selection_text();
4075  if (*copy) Fl::copy(copy, (int) strlen(copy), 1);
4076  free((void*)copy);
4077  return 1;
4078  }
4079 
4080  // Select all ?
4081  if ((Fl::event_state()&(FL_CTRL|FL_COMMAND)) && Fl::event_key()=='a') {
4082  buffer()->select(0,buffer()->length());
4083  const char *copy = buffer()->selection_text();
4084  if (*copy) Fl::copy(copy, (int) strlen(copy), 0);
4085  free((void*)copy);
4086  return 1;
4087  }
4088 
4089  if (mVScrollBar->handle(event)) return 1;
4090  if (mHScrollBar->handle(event)) return 1;
4091 
4092  break;
4093 
4094  case FL_SHORTCUT:
4096  return 0;
4097  if (Fl::visible_focus() && handle(FL_FOCUS)) {
4098  Fl::focus(this);
4099  return 1;
4100  }
4101  break;
4102 
4103  }
4104 
4105  return 0;
4106 }
4107 
4108 
4109 /*
4110  Convert an x pixel position into a column number.
4111  */
4112 double Fl_Text_Display::x_to_col(double y) const
4113 {
4114  if (!mColumnScale) {
4115  mColumnScale = string_width("Mitg", 4, 'A') / 4.0;
4116  }
4117  return (y/mColumnScale)+0.5;
4118 }
4119 
4120 
4124 double Fl_Text_Display::col_to_x(double col) const
4125 {
4126  if (!mColumnScale) {
4127  // recalculate column scale value
4128  x_to_col(0);
4129  }
4130  return col*mColumnScale;
4131 }
4132 
4133 
4134 //
4135 // End of "$Id$".
4136 //
Fl_Text_Display::draw_cursor
void draw_cursor(int, int)
Draw a cursor with top center at X, Y.
Definition: Fl_Text_Display.cxx:2334
scroll_direction
static int scroll_direction
Definition: Fl_Text_Display.cxx:80
FL_TEXT_MAX_EXP_CHAR_LEN
#define FL_TEXT_MAX_EXP_CHAR_LEN
Definition: Fl_Text_Buffer.H:58
Fl_Text_Display::buffer
void buffer(Fl_Text_Buffer *buf)
Definition: Fl_Text_Display.cxx:384
Fl_Text_Display::xy_to_position
int xy_to_position(int x, int y, int PosType=CHARACTER_POS) const
Translate a pixel position into a character index.
Definition: Fl_Text_Display.cxx:2509
fl_font
void fl_font(Fl_Font face, Fl_Fontsize fsize)
Definition: fl_draw.H:509
Fl_Text_Display::damage_range2_end
int damage_range2_end
Definition: Fl_Text_Display.H:450
fl_width
FL_EXPORT double fl_width(const char *txt)
Definition: fl_font.cxx:65
FL_ALIGN_LEFT
const Fl_Align FL_ALIGN_LEFT
Definition: Enumerations.H:839
Fl_Text_Display::dragPos
int dragPos
Definition: Fl_Text_Display.H:515
Fl_Text_Display::find_line_end
void find_line_end(int pos, bool start_pos_is_line_start, int *lineEnd, int *nextLineStart) const
Finds both the end of the current line and the start of the next line.
Definition: Fl_Text_Display.cxx:3559
Fl_Widget::y
int y() const
Definition: Fl_Widget.H:289
Fl_Text_Selection::start
int start() const
Return the byte offset to the first selected character.
Definition: Fl_Text_Buffer.H:95
FL_DAMAGE_ALL
Definition: Enumerations.H:1112
Fl_Text_Display::mStyleBuffer
Fl_Text_Buffer * mStyleBuffer
Definition: Fl_Text_Display.H:462
IS_UTF8_ALIGNED2
#define IS_UTF8_ALIGNED2(a, b)
Definition: Fl_Text_Buffer.H:34
Fl_Text_Display::scroll_timer_cb
static void scroll_timer_cb(void *)
Timer callback for scroll events.
Definition: Fl_Text_Display.cxx:3855
Fl_Text_Selection
This is an internal class for Fl_Text_Buffer to manage text selections. This class works correctly wi...
Definition: Fl_Text_Buffer.H:69
Fl.H
Fl_Text_Display::mWrapMarginPix
int mWrapMarginPix
Definition: Fl_Text_Display.H:469
Fl_Text_Display::mLineNumLeft
int mLineNumLeft
Definition: Fl_Text_Display.H:526
Fl_Text_Display::mNBufferLines
int mNBufferLines
Definition: Fl_Text_Display.H:460
buf
static char * buf
Definition: fl_encoding_mac_roman.cxx:76
Fl_Text_Buffer::line_end
int line_end(int pos) const
Definition: Fl_Text_Buffer.cxx:821
countlines
static int countlines(const char *string)
Definition: Fl_Text_Display.cxx:3020
fl_line
void fl_line(int x, int y, int x1, int y1)
Definition: fl_draw.H:223
Fl_Scrollbar
Definition: Fl_Scrollbar.H:43
fl_rectf
void fl_rectf(int x, int y, int w, int h)
Definition: fl_draw.H:206
Fl_Text_Display::mLastChar
int mLastChar
Definition: Fl_Text_Display.H:464
FL_HIDE
Definition: Enumerations.H:369
Fl_Text_Display::update_h_scrollbar
void update_h_scrollbar()
Update horizontal scrollbar.
Definition: Fl_Text_Display.cxx:2901
Fl_Widget::draw_box
void draw_box() const
Definition: fl_boxtype.cxx:442
FL_KEYUP
Definition: Enumerations.H:320
Fl_Text_Display::mCursorToHint
int mCursorToHint
Definition: Fl_Text_Display.H:454
Fl_Color
unsigned int Fl_Color
Definition: Enumerations.H:934
Fl_Text_Display::resize
virtual void resize(int X, int Y, int W, int H)
Change the size of the displayed text area. Calling this function will trigger a recalculation of all...
Definition: Fl_Text_Display.cxx:480
Fl_Group::end
void end()
Definition: Fl_Group.cxx:75
Fl_Text_Display::display_insert
void display_insert()
Scroll the display to bring insertion cursor into view.
Definition: Fl_Text_Display.cxx:1231
Fl_Text_Display::maintain_absolute_top_line_number
void maintain_absolute_top_line_number(int state)
Line numbering stuff, currently unused.
Definition: Fl_Text_Display.cxx:1834
FL_UNFOCUS
Definition: Enumerations.H:288
Fl_Text_Buffer::skip_lines
int skip_lines(int startPos, int nLines)
Definition: Fl_Text_Buffer.cxx:933
Fl_Text_Display::buffer_modified_cb
static void buffer_modified_cb(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg)
This is called whenever the buffer is modified.
Definition: Fl_Text_Display.cxx:1683
Fl_Text_Display::mHScrollBar
Fl_Scrollbar * mHScrollBar
Definition: Fl_Text_Display.H:511
Fl_Text_Display::vline_length
int vline_length(int visLineNum) const
Count number of bytes in a visible line.
Definition: Fl_Text_Display.cxx:3069
Fl_Text_Display::mStyleTable
const Style_Table_Entry * mStyleTable
Definition: Fl_Text_Display.H:486
Fl_Text_Display::update_v_scrollbar
void update_v_scrollbar()
Update vertical scrollbar.
Definition: Fl_Text_Display.cxx:2879
Fl_Text_Display::next_word
void next_word(void)
Moves the current insert position right one word.
Definition: Fl_Text_Display.cxx:1592
Fl_Text_Display::longest_vline
int longest_vline() const
Find the longest line of all visible lines.
Definition: Fl_Text_Display.cxx:465
Fl_Text_Buffer::text_range
char * text_range(int start, int end) const
Get a copy of a part of the text buffer. Return a copy of the text between start and end character po...
Definition: Fl_Text_Buffer.cxx:200
Fl::box_dx
static int box_dx(Fl_Boxtype)
Definition: fl_boxtype.cxx:360
FL_INACTIVE_COLOR
const Fl_Color FL_INACTIVE_COLOR
the inactive foreground color
Definition: Enumerations.H:939
Fl_Text_Display::DRAG_LINE
Definition: Fl_Text_Display.H:118
Fl_Text_Display::word_start
int word_start(int pos) const
Definition: Fl_Text_Display.H:254
Fl_Text_Display::linenumber_font
Fl_Font linenumber_font() const
Definition: Fl_Text_Display.cxx:240
Fl_Text_Display::draw_text
void draw_text(int X, int Y, int W, int H)
Refresh a rectangle of the text display.
Definition: Fl_Text_Display.cxx:724
Fl_Text_Buffer::canUndo
void canUndo(char flag=1)
Definition: Fl_Text_Buffer.cxx:448
Fl_Text_Display::x
int x
Definition: Fl_Text_Display.H:517
Fl_Text_Display::HEAVY_CURSOR
Definition: Fl_Text_Display.H:94
fl_descent
int fl_descent()
Definition: fl_draw.H:533
FL_DAMAGE_SCROLL
Definition: Enumerations.H:1108
Fl_Text_Display::textfont
Fl_Font textfont() const
Definition: Fl_Text_Display.H:290
Fl::event_state
static int event_state()
Definition: Fl.H:704
STYLE_LOOKUP_MASK
#define STYLE_LOOKUP_MASK
Definition: Fl_Text_Display.cxx:67
Fl_Text_Display::CURSOR_POS
Definition: Fl_Text_Display.H:104
Fl_Text_Display::CHARACTER_POS
Definition: Fl_Text_Display.H:105
FL_CURSOR_DEFAULT
Definition: Enumerations.H:1049
Fl_Text_Display::mNLinesDeleted
int mNLinesDeleted
Definition: Fl_Text_Display.H:498
Fl_Text_Buffer::insert
void insert(int pos, const char *text)
Definition: Fl_Text_Buffer.cxx:269
fl_color
void fl_color(Fl_Color c)
Definition: fl_draw.H:52
Fl_Text_Display::mHighlightCBArg
void * mHighlightCBArg
Definition: Fl_Text_Display.H:492
Fl_Text_Display::mNVisibleLines
int mNVisibleLines
Definition: Fl_Text_Display.H:459
state
int state
Definition: Fl_Text_Editor.cxx:92
Fl::event_button
static int event_button()
Definition: Fl.H:678
Fl_Text_Display::DRAG_START_DND
Definition: Fl_Text_Display.H:115
Fl_Widget::window
Fl_Window * window() const
Definition: Fl_Window.cxx:118
Fl_Text_Display::mHorizOffset
int mHorizOffset
Definition: Fl_Text_Display.H:481
Fl_Text_Display::measure_deleted_lines
void measure_deleted_lines(int pos, int nDeleted)
Wrapping calculations.
Definition: Fl_Text_Display.cxx:3284
FL_DRAG
Definition: Enumerations.H:268
FL_SHIFT
#define FL_SHIFT
One of the shift keys is down.
Definition: Enumerations.H:557
Fl_Text_Display::draw_string
void draw_string(int style, int x, int y, int toX, const char *string, int nChars) const
Draw a text segment in a single style.
Definition: Fl_Text_Display.cxx:2185
Fl::event_is_click
static int event_is_click()
Definition: Fl.H:661
Fl_Text_Display::CARET_CURSOR
Definition: Fl_Text_Display.H:91
min
static int min(int i1, int i2)
Definition: Fl_Text_Display.cxx:3011
Fl_Text_Display::move_down
int move_down()
Moves the current insert position down one line.
Definition: Fl_Text_Display.cxx:1363
Fl_Text_Display::overstrike
void overstrike(const char *text)
Replaces text at the current insert position.
Definition: Fl_Text_Display.cxx:1005
fl_text_drag_me
void fl_text_drag_me(int pos, Fl_Text_Display *d)
Definition: Fl_Text_Display.cxx:3817
free
void free()
H
static int H
Definition: Fl_Tooltip.cxx:76
Fl_Text_Display::position_style
int position_style(int lineStartPos, int lineLen, int lineIndex) const
Find the correct style for a character.
Definition: Fl_Text_Display.cxx:2432
Fl_Text_Display::line_start
int line_start(int pos) const
Return the beginning of a line.
Definition: Fl_Text_Display.cxx:1527
Fl_Text_Display::DRAG_NONE
Definition: Fl_Text_Display.H:114
Fl_Text_Display::previous_word
void previous_word(void)
Moves the current insert position left one word.
Definition: Fl_Text_Display.cxx:1611
fl_height
int fl_height()
Definition: fl_draw.H:527
NO_HINT
#define NO_HINT
Definition: Fl_Text_Display.cxx:57
Fl_Text_Display::mSuppressResync
int mSuppressResync
Definition: Fl_Text_Display.H:496
Fl_Widget::set_flag
void set_flag(unsigned int c)
Definition: Fl_Widget.H:149
Fl_Widget::x
int x() const
Definition: Fl_Widget.H:284
NULL
#define NULL
Definition: forms.H:34
Fl_Widget::set_visible
void set_visible()
Definition: Fl_Widget.H:696
Fl_Text_Display::absolute_top_line_number
void absolute_top_line_number(int oldFirstChar)
Line numbering stuff, currently unused.
Definition: Fl_Text_Display.cxx:1862
fl_draw
FL_EXPORT void fl_draw(const char *str, int x, int y)
Definition: fl_font.cxx:70
Fl_Text_Display::show_cursor
void show_cursor(int b=1)
Shows the text cursor. This function may trigger a redraw.
Definition: Fl_Text_Display.cxx:878
Fl_Text_Display::mMaxsize
int mMaxsize
Definition: Fl_Text_Display.H:494
Fl_Text_Display::wrapped_row
int wrapped_row(int row) const
Nobody knows what this function does.
Definition: Fl_Text_Display.cxx:1213
Fl_Text_Buffer::prev_char
int prev_char(int ix) const
Definition: Fl_Text_Buffer.cxx:1759
Fl_Text_Buffer::add_modify_callback
void add_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void *cbArg)
Definition: Fl_Text_Buffer.cxx:652
Fl_Text_Display::handle
virtual int handle(int e)
Event handling.
Definition: Fl_Text_Display.cxx:3887
Fl_Text_Buffer.H
Fl_Scrollbar::linesize
int linesize() const
Definition: Fl_Scrollbar.H:96
Fl_Text_Display::v_scrollbar_cb
static void v_scrollbar_cb(Fl_Scrollbar *w, Fl_Text_Display *d)
Callbacks for drag or valueChanged on vertical scrollbar.
Definition: Fl_Text_Display.cxx:2911
Fl_Text_Display::SIMPLE_CURSOR
Definition: Fl_Text_Display.H:95
fl_contrast
Fl_Color fl_contrast(Fl_Color fg, Fl_Color bg)
Definition: fl_color.cxx:435
FL_LEAVE
Definition: Enumerations.H:259
Fl_Text_Display::wrapped_line_counter
void wrapped_line_counter(Fl_Text_Buffer *buf, int startPos, int maxPos, int maxLines, bool startPosIsLineStart, int styleBufOffset, int *retPos, int *retLines, int *retLineStart, int *retLineEnd, bool countLastLineMissingNewLine=true) const
Wrapping calculations.
Definition: Fl_Text_Display.cxx:3376
Fl_Text_Display::wrap_mode
void wrap_mode(int wrap, int wrap_margin)
Set the new text wrap mode.
Definition: Fl_Text_Display.cxx:928
Fl::event_key
static int event_key()
Definition: Fl.H:723
Fl_Text_Display::wrapped_column
int wrapped_column(int row, int column) const
Nobody knows what this function does.
Definition: Fl_Text_Display.cxx:1185
Fl_Text_Buffer::length
int length() const
Returns the number of bytes in the buffer.
Definition: Fl_Text_Buffer.H:180
Fl_Text_Display::insert_position
void insert_position(int newPos)
Sets the position of the text insertion cursor for text display. Move the insertion cursor in front o...
Definition: Fl_Text_Display.cxx:851
Fl_Widget::user_data
void * user_data() const
Definition: Fl_Widget.H:593
Fl_Callback
void() Fl_Callback(Fl_Widget *, void *)
Definition: Fl_Widget.H:49
b
long b
Definition: jpegint.h:397
Fl_Text_Display::mContinuousWrap
int mContinuousWrap
Definition: Fl_Text_Display.H:468
Fl_Text_Display::mCursorOn
int mCursorOn
Definition: Fl_Text_Display.H:452
Fl_Text_Display::scrollbar_align
Fl_Align scrollbar_align() const
Definition: Fl_Text_Display.H:241
Fl_Text_Display::offset_line_starts
void offset_line_starts(int newTopLineNum)
Offset line start counters for a new vertical scroll position.
Definition: Fl_Text_Display.cxx:2581
Fl::dnd
static int dnd()
Definition: fl_dnd_win32.cxx:535
Fl_Text_Display::linenumber_width
int linenumber_width() const
Definition: Fl_Text_Display.cxx:221
background
void background(uchar r, uchar g, uchar b)
Definition: cmap.cxx:113
Fl_Display_Device::display_device
static Fl_Display_Device * display_device()
Definition: Fl_Device.cxx:83
Fl::event_x
static int event_x()
Definition: Fl.H:598
Fl_Text_Display::DIM_CURSOR
Definition: Fl_Text_Display.H:92
Fl_Text_Buffer::char_at
unsigned int char_at(int pos) const
Definition: Fl_Text_Buffer.cxx:242
Fl_Text_Display::mCursorStyle
int mCursorStyle
Definition: Fl_Text_Display.H:457
Fl::box_dh
static int box_dh(Fl_Boxtype)
Definition: fl_boxtype.cxx:397
FL_HORIZONTAL
#define FL_HORIZONTAL
The valuator can work horizontally.
Definition: Fl_Valuator.H:31
Fl_Text_Buffer::remove_modify_callback
void remove_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void *cbArg)
Definition: Fl_Text_Buffer.cxx:677
Fl_Text_Display::GET_WIDTH
Definition: Fl_Text_Display.H:381
Fl_Text_Display::scroll
void scroll(int topLineNum, int horizOffset)
Scrolls the current buffer to start at the specified line and column.
Definition: Fl_Text_Display.cxx:2830
Fl_Text_Display::linenumber_bgcolor
Fl_Color linenumber_bgcolor() const
Definition: Fl_Text_Display.cxx:309
Fl_Widget::w
int w() const
Definition: Fl_Widget.H:294
FL_FOREGROUND_COLOR
const Fl_Color FL_FOREGROUND_COLOR
the default foreground color (0) used for labels and text
Definition: Enumerations.H:937
Fl_Text_Display::maintaining_absolute_top_line_number
int maintaining_absolute_top_line_number() const
Line numbering stuff, currently unused.
Definition: Fl_Text_Display.cxx:1879
Fl_Text_Display::cursor_style
void cursor_style(int style)
Sets the text cursor style. Sets the text cursor style to one of the following:
Definition: Fl_Text_Display.cxx:901
Fl::box_dw
static int box_dw(Fl_Boxtype)
Definition: fl_boxtype.cxx:391
Fl::dnd_text_ops
static int dnd_text_ops()
Definition: Fl.H:1213
Fl_Text_Display::shortcut_
int shortcut_
Definition: Fl_Text_Display.H:519
Fl_Text_Buffer::primary_selection
const Fl_Text_Selection * primary_selection() const
Definition: Fl_Text_Buffer.H:646
Fl_Window.H
Fl_Text_Display::mVScrollBar
Fl_Scrollbar * mVScrollBar
Definition: Fl_Text_Display.H:512
Fl_Widget::clear_visible
void clear_visible()
Definition: Fl_Widget.H:702
FL_CURSOR_INSERT
Definition: Enumerations.H:1053
Fl_Widget::color
Fl_Color color() const
Definition: Fl_Widget.H:378
Fl::test_shortcut
static int test_shortcut(Fl_Shortcut)
Definition: fl_shortcut.cxx:54
Fl_Text_Display::mUnfinishedStyle
char mUnfinishedStyle
Definition: Fl_Text_Display.H:488
Fl_Text_Display::h_scrollbar_cb
static void h_scrollbar_cb(Fl_Scrollbar *w, Fl_Text_Display *d)
Callbacks for drag or valueChanged on horizontal scrollbar.
Definition: Fl_Text_Display.cxx:2921
Fl_Text_Buffer::utf8_align
int utf8_align(int) const
Definition: Fl_Text_Buffer.cxx:1794
Fl_Text_Display::count_lines
int count_lines(int start, int end, bool start_pos_is_line_start) const
Count the number of lines between two positions.
Definition: Fl_Text_Display.cxx:1407
Fl_Text_Display::highlight_data
void highlight_data(Fl_Text_Buffer *styleBuffer, const Style_Table_Entry *styleTable, int nStyles, char unfinishedStyle, Unfinished_Style_Cb unfinishedHighlightCB, void *cbArg)
Attach (or remove) highlight information in text display and redisplay.
Definition: Fl_Text_Display.cxx:442
Fl_Text_Display::mTopLineNumHint
int mTopLineNumHint
Definition: Fl_Text_Display.H:482
Fl_Text_Display::buffer
Fl_Text_Buffer * buffer() const
Definition: Fl_Text_Display.H:174
p
static menustate * p
Definition: Fl_Menu.cxx:606
Fl_Widget::w
void w(int v)
Definition: Fl_Widget.H:143
Fl_Text_Display::DRAG_CHAR
Definition: Fl_Text_Display.H:116
Fl_Text_Display::textcolor
Fl_Color textcolor() const
Definition: Fl_Text_Display.H:314
Fl_Text_Buffer::count_displayed_characters
int count_displayed_characters(int lineStartPos, int targetPos) const
Definition: Fl_Text_Buffer.cxx:861
Fl::box_dy
static int box_dy(Fl_Boxtype)
Definition: fl_boxtype.cxx:385
Fl_Text_Display::y
int y
Definition: Fl_Text_Display.H:517
Fl_Widget::selection_color
Fl_Color selection_color() const
Definition: Fl_Widget.H:396
Fl_Widget::x
void x(int v)
Definition: Fl_Widget.H:139
Fl_Text_Display::mCursor_color
Fl_Color mCursor_color
Definition: Fl_Text_Display.H:509
fl_utf8.h
header for Unicode and UTF-8 character handling
FL_MOVE
Definition: Enumerations.H:335
Fl_Text_Display::NORMAL_CURSOR
Definition: Fl_Text_Display.H:90
FL_MOUSEWHEEL
Definition: Enumerations.H:395
fl_utf8len1
int fl_utf8len1(char c)
Definition: fl_utf8.cxx:141
Fl_Text_Display::damage_range1_end
int damage_range1_end
Definition: Fl_Text_Display.H:449
scroll_amount
static int scroll_amount
Definition: Fl_Text_Display.cxx:81
Fl_Text_Display::h
int h
Definition: Fl_Text_Display.H:517
max
static int max(int i1, int i2)
Definition: Fl_Text_Display.cxx:3007
Fl_Text_Display::damage_range2_start
int damage_range2_start
Definition: Fl_Text_Display.H:450
Fl_Text_Display::position_to_line
int position_to_line(int pos, int *lineNum) const
Convert a position index into a line number offset.
Definition: Fl_Text_Display.cxx:1911
PRIMARY_MASK
#define PRIMARY_MASK
Definition: Fl_Text_Display.cxx:63
FL_HELVETICA
const Fl_Font FL_HELVETICA
Helvetica (or Arial) normal (0)
Definition: Enumerations.H:879
Fl_Text_Display.H
Fl_Text_Display::scroll_
int scroll_(int topLineNum, int horizOffset)
Scrolls the current buffer to start at the specified line and column.
Definition: Fl_Text_Display.cxx:2844
Fl_Text_Display::calc_last_char
void calc_last_char()
Update last display character index.
Definition: Fl_Text_Display.cxx:2816
fl_clip_box
int fl_clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H)
Definition: fl_draw.H:126
Fl_Text_Display::mCursorOldY
int mCursorOldY
Definition: Fl_Text_Display.H:453
fl_inactive
Fl_Color fl_inactive(Fl_Color c)
Definition: fl_color.cxx:423
Fl_Widget::active_r
int active_r() const
Definition: Fl_Widget.cxx:265
Fl_Text_Display::empty_vlines
int empty_vlines() const
Return true if there are lines visible with no corresponding buffer text.
Definition: Fl_Text_Display.cxx:3054
Fl_Text_Display::mHorizOffsetHint
int mHorizOffsetHint
Definition: Fl_Text_Display.H:484
Fl_Text_Display::linenumber_align
Fl_Align linenumber_align() const
Definition: Fl_Text_Display.cxx:333
FL_COMMAND
#define FL_COMMAND
An alias for FL_CTRL on WIN32 and X11, or FL_META on MacOS X.
Definition: Enumerations.H:580
Fl_Text_Display::handle_vline
int handle_vline(int mode, int lineStart, int lineLen, int leftChar, int rightChar, int topClip, int bottomClip, int leftClip, int rightClip) const
Definition: Fl_Text_Display.cxx:1967
Fl_Text_Display::WRAP_AT_COLUMN
Definition: Fl_Text_Display.H:126
FL_FOCUS
Definition: Enumerations.H:283
TMPFONTWIDTH
#define TMPFONTWIDTH
Definition: Fl_Text_Display.cxx:86
Fl_Text_Display::insert_position
int insert_position() const
Definition: Fl_Text_Display.H:186
Fl_Surface_Device::surface
static Fl_Surface_Device * surface()
Definition: Fl_Device.H:574
Fl_Text_Buffer::next_char
int next_char(int ix) const
Definition: Fl_Text_Buffer.cxx:1770
Fl_Widget::visible
unsigned int visible() const
Definition: Fl_Widget.H:660
Fl_Text_Display::measure_vline
int measure_vline(int visLineNum) const
Returns the width in pixels of the displayed line pointed to by "visLineNum".
Definition: Fl_Text_Display.cxx:3041
Fl_Text_Display::dragging
int dragging
Definition: Fl_Text_Display.H:515
Fl_Text_Selection::selected
bool selected() const
Returns true if any text is selected.
Definition: Fl_Text_Buffer.H:108
Fl_Text_Display::text_area
struct Fl_Text_Display::@22 text_area
Fl_Text_Buffer::selection_position
int selection_position(int *start, int *end)
Definition: Fl_Text_Buffer.cxx:512
Fl_Fontsize
int Fl_Fontsize
Definition: Enumerations.H:906
indent
const char * indent()
Definition: code.cxx:99
Fl_Scrollbar::value
int value() const
Definition: Fl_Scrollbar.H:65
Fl_Text_Display::display_insert_position_hint
int display_insert_position_hint
Definition: Fl_Text_Display.H:516
FL_PUSH
Definition: Enumerations.H:236
Fl_Text_Display::in_selection
int in_selection(int x, int y) const
Check if a pixel position is within the primary selection.
Definition: Fl_Text_Display.cxx:1156
Fl_Widget::damage
uchar damage() const
Definition: Fl_Widget.H:917
Fl_Text_Display::move_left
int move_left()
Moves the current insert position left one character.
Definition: Fl_Text_Display.cxx:1303
Fl_Widget::test_shortcut
int test_shortcut()
Definition: fl_shortcut.cxx:494
Fl_Text_Buffer::tab_distance
int tab_distance() const
Definition: Fl_Text_Buffer.H:349
Fl::remove_timeout
static void remove_timeout(Fl_Timeout_Handler, void *=0)
Definition: Fl.cxx:368
Fl_Text_Display::shortcut
int shortcut() const
Definition: Fl_Text_Display.H:277
fl_push_clip
void fl_push_clip(int x, int y, int w, int h)
Definition: fl_draw.H:82
Fl_Text_Display::x_to_col
double x_to_col(double x) const
Definition: Fl_Text_Display.cxx:4112
Fl::repeat_timeout
static void repeat_timeout(double t, Fl_Timeout_Handler, void *=0)
Definition: Fl.cxx:334
Fl_Widget::redraw
void redraw()
Definition: Fl.cxx:1782
FL_NORMAL_SIZE
Fl_Fontsize FL_NORMAL_SIZE
normal font size
Definition: Fl_Widget.cxx:117
Fl_Widget
Definition: Fl_Widget.H:101
Fl_Text_Buffer::byte_at
char byte_at(int pos) const
Definition: Fl_Text_Buffer.cxx:257
Fl_Group
Definition: Fl_Group.H:41
TOP_MARGIN
#define TOP_MARGIN
Definition: Fl_Text_Display.cxx:52
Fl::focus
static Fl_Widget * focus()
Definition: Fl.H:840
FL_ALIGN_BOTTOM
const Fl_Align FL_ALIGN_BOTTOM
Definition: Enumerations.H:835
BG_ONLY_MASK
#define BG_ONLY_MASK
Definition: Fl_Text_Display.cxx:65
Fl_Widget::box
Fl_Boxtype box() const
Definition: Fl_Widget.H:363
Fl_Text_Display::show_insert_position
void show_insert_position()
Scrolls the text buffer to show the current insert position. This function triggers a complete recalc...
Definition: Fl_Text_Display.cxx:1274
Fl_Text_Display::mUnfinishedHighlightCB
Unfinished_Style_Cb mUnfinishedHighlightCB
Definition: Fl_Text_Display.H:490
Fl_Widget::h
int h() const
Definition: Fl_Widget.H:299
Fl_Text_Display::draw_line_numbers
void draw_line_numbers(bool clearAll)
Refresh the line number area.
Definition: Fl_Text_Display.cxx:2940
Fl_Text_Display::move_up
int move_up()
Moves the current insert position up one line.
Definition: Fl_Text_Display.cxx:1318
Fl::event_y
static int event_y()
Definition: Fl.H:603
Fl_Text_Buffer::select
void select(int start, int end)
Definition: Fl_Text_Buffer.cxx:485
Fl_Text_Display::mNeedAbsTopLineNum
int mNeedAbsTopLineNum
Definition: Fl_Text_Display.H:478
FL_KEYBOARD
Definition: Enumerations.H:315
Fl::copy
static void copy(const char *stuff, int len, int destination, const char *type)
Definition: Fl_win32.cxx:680
Fl_Widget::h
void h(int v)
Definition: Fl_Widget.H:145
Fl_Text_Display::draw_range
void draw_range(int start, int end)
Draw a range of text.
Definition: Fl_Text_Display.cxx:786
Fl_Text_Display::Style_Table_Entry::color
Fl_Color color
text color
Definition: Fl_Text_Display.H:149
Fl::event_dy
static int event_dy()
Definition: Fl.H:627
Fl_Text_Display::col_to_x
double col_to_x(double col) const
Definition: Fl_Text_Display.cxx:4124
Fl_Text_Display::skip_lines
int skip_lines(int startPos, int nLines, bool startPosIsLineStart)
Skip a number of lines forward.
Definition: Fl_Text_Display.cxx:1450
FL_SELECTION_COLOR
const Fl_Color FL_SELECTION_COLOR
the default selection/highlight color
Definition: Enumerations.H:940
scroll_y
static int scroll_y
Definition: Fl_Text_Display.cxx:82
Fl_Text_Display::~Fl_Text_Display
~Fl_Text_Display()
Definition: Fl_Text_Display.cxx:186
Fl_Text_Display::update_line_starts
void update_line_starts(int pos, int charsInserted, int charsDeleted, int linesInserted, int linesDeleted, int *scrolled)
Update line start arrays and variables.
Definition: Fl_Text_Display.cxx:2649
Fl_Text_Display::extend_range_for_styles
void extend_range_for_styles(int *start, int *end)
I don't know what this does!
Definition: Fl_Text_Display.cxx:3630
Fl_Widget::y
void y(int v)
Definition: Fl_Widget.H:141
Fl_Text_Display::string_width
double string_width(const char *string, int length, int style) const
Find the width of a string in the font of a particular style.
Definition: Fl_Text_Display.cxx:2473
Fl_Text_Display::rewind_lines
int rewind_lines(int startPos, int nLines)
Skip a number of lines back.
Definition: Fl_Text_Display.cxx:1555
Fl::event_clicks
static int event_clicks()
Definition: Fl.H:645
Fl_Text_Display::insert
void insert(const char *text)
Inserts "text" at the current cursor location.
Definition: Fl_Text_Display.cxx:986
Fl_Text_Buffer::text
char * text() const
Get a copy of the entire contents of the text buffer. Memory is allocated to contain the returned str...
Definition: Fl_Text_Buffer.cxx:153
Fl::scrollbar_size
static int scrollbar_size()
Definition: Fl.cxx:196
Fl_Text_Buffer::add_predelete_callback
void add_predelete_callback(Fl_Text_Predelete_Cb bufPredelCB, void *cbArg)
Definition: Fl_Text_Buffer.cxx:728
Fl_Text_Display::position_to_xy
int position_to_xy(int pos, int *x, int *y) const
Convert a character index into a pixel position.
Definition: Fl_Text_Display.cxx:1074
Fl_Text_Display::draw_vline
void draw_vline(int visLineNum, int leftClip, int rightClip, int leftCharIndex, int rightCharIndex)
Draw a single line of text.
Definition: Fl_Text_Display.cxx:2133
Fl_Text_Display::mModifyingTabDistance
int mModifyingTabDistance
Definition: Fl_Text_Display.H:501
Fl_Scrollbar::handle
int handle(int)
Definition: Fl_Scrollbar.cxx:66
Fl_Text_Display::scrollbar_width
int scrollbar_width() const
Definition: Fl_Text_Display.H:229
fl_pop_clip
void fl_pop_clip()
Definition: fl_draw.H:103
Fl_Group::handle
int handle(int)
Definition: Fl_Group.cxx:147
Fl_Widget::size
void size(int W, int H)
Definition: Fl_Widget.H:341
Fl_Text_Display::calc_line_starts
void calc_line_starts(int startLine, int endLine)
Update the line start arrays.
Definition: Fl_Text_Display.cxx:2755
Fl_Window::cursor
void cursor(Fl_Cursor)
Definition: fl_cursor.cxx:111
Fl_Text_Display::FIND_INDEX_FROM_ZERO
Definition: Fl_Text_Display.H:380
x
int x
Definition: test.c:73
Fl_Text_Display::move_right
int move_right()
Moves the current insert position right one character.
Definition: Fl_Text_Display.cxx:1288
Fl_Text_Buffer::count_lines
int count_lines(int startPos, int endPos) const
Definition: Fl_Text_Buffer.cxx:903
Fl_Widget::callback
Fl_Callback_p callback() const
Definition: Fl_Widget.H:561
Fl_Widget::visible_r
int visible_r() const
Definition: Fl_Widget.cxx:295
Fl_Text_Display
Rich text display widget.
Definition: Fl_Text_Display.H:82
Fl_Font
int Fl_Font
Definition: Enumerations.H:877
RIGHT_MARGIN
#define RIGHT_MARGIN
Definition: Fl_Text_Display.cxx:55
Fl_Text_Display::BLOCK_CURSOR
Definition: Fl_Text_Display.H:93
FL_DAMAGE_EXPOSE
Definition: Enumerations.H:1107
Fl_Text_Display::Style_Table_Entry
Definition: Fl_Text_Display.H:148
Fl_Text_Display::buffer_predelete_cb
static void buffer_predelete_cb(int pos, int nDeleted, void *cbArg)
This is called before any characters are deleted.
Definition: Fl_Text_Display.cxx:1647
Fl_Text_Display::WRAP_NONE
Definition: Fl_Text_Display.H:125
FL_BACKGROUND2_COLOR
const Fl_Color FL_BACKGROUND2_COLOR
the default background color for text, list, and valuator widgets
Definition: Enumerations.H:938
FL_ALIGN_TOP
const Fl_Align FL_ALIGN_TOP
Definition: Enumerations.H:833
LEFT_MARGIN
#define LEFT_MARGIN
Definition: Fl_Text_Display.cxx:54
Fl::add_timeout
static void add_timeout(double t, Fl_Timeout_Handler, void *=0)
Definition: Fl.cxx:329
FL_SHORTCUT
Definition: Enumerations.H:349
Fl_Text_Display::DRAG_WORD
Definition: Fl_Text_Display.H:117
Fl_Text_Display::line_end
int line_end(int startPos, bool startPosIsLineStart) const
Returns the end of a line.
Definition: Fl_Text_Display.cxx:1496
Fl::visible_focus
static int visible_focus()
Definition: Fl.H:1197
Fl_Group::update_child
void update_child(Fl_Widget &widget) const
Definition: Fl_Group.cxx:754
Fl_Text_Display::clear_rect
void clear_rect(int style, int x, int y, int width, int height) const
Clear a rectangle with the appropriate background color for style.
Definition: Fl_Text_Display.cxx:2300
HIGHLIGHT_MASK
#define HIGHLIGHT_MASK
Definition: Fl_Text_Display.cxx:64
y
int y
Definition: test.c:74
Fl_Text_Display::reset_absolute_top_line_number
void reset_absolute_top_line_number()
Line numbering stuff, probably unused.
Definition: Fl_Text_Display.cxx:1893
Fl_Text_Display::dragType
int dragType
Definition: Fl_Text_Display.H:515
BOTTOM_MARGIN
#define BOTTOM_MARGIN
Definition: Fl_Text_Display.cxx:53
Fl_Text_Selection::end
int end() const
Return the byte offset to the character after the last selected character.
Definition: Fl_Text_Buffer.H:101
SECONDARY_MASK
#define SECONDARY_MASK
Definition: Fl_Text_Display.cxx:62
Fl_Text_Buffer::unselect
void unselect()
Definition: Fl_Text_Buffer.cxx:500
FL_GRAY
#define FL_GRAY
Definition: Enumerations.H:978
Fl_Text_Display::linenumber_format
const char * linenumber_format() const
Definition: Fl_Text_Display.cxx:372
Fl_Widget::type
uchar type() const
Definition: Fl_Widget.H:274
fl_isseparator
static int fl_isseparator(unsigned int c)
Definition: Fl_Text_Display.cxx:1582
Fl_Text_Display::mColumnScale
double mColumnScale
Definition: Fl_Text_Display.H:504
f
Fl_Box_Draw_F * f
Definition: fl_boxtype.cxx:285
Fl_Text_Display::DRAW_LINE
Definition: Fl_Text_Display.H:378
Fl_Text_Buffer::prev_char_clipped
int prev_char_clipped(int ix) const
Definition: Fl_Text_Buffer.cxx:1735
Fl_Text_Buffer::selection_text
char * selection_text()
Definition: Fl_Text_Buffer.cxx:521
Fl_Text_Display::linenumber_size
Fl_Fontsize linenumber_size() const
Definition: Fl_Text_Display.cxx:263
Fl_Text_Display::mBuffer
Fl_Text_Buffer * mBuffer
Definition: Fl_Text_Display.H:461
Fl_Text_Display::fl_text_drag_me
friend void fl_text_drag_me(int pos, Fl_Text_Display *d)
Definition: Fl_Text_Display.cxx:3817
Y
static int Y
Definition: Fl_Tooltip.cxx:76
flstring.h
Fl_Text_Display::Fl_Text_Display
Fl_Text_Display(int X, int Y, int W, int H, const char *l=0)
Creates a new text display widget.
Definition: Fl_Text_Display.cxx:96
Fl_Text_Display::mCursorPreferredXPos
int mCursorPreferredXPos
Definition: Fl_Text_Display.H:458
TEXT_ONLY_MASK
#define TEXT_ONLY_MASK
Definition: Fl_Text_Display.cxx:66
Fl::compose_state
static int compose_state
Definition: Fl.H:166
Fl_Text_Display::mAbsTopLineNum
int mAbsTopLineNum
Definition: Fl_Text_Display.H:474
Fl_Text_Buffer::remove_predelete_callback
void remove_predelete_callback(Fl_Text_Predelete_Cb predelCB, void *cbArg)
Definition: Fl_Text_Buffer.cxx:753
Fl_Widget::SHORTCUT_LABEL
the label contains a shortcut we need to draw
Definition: Fl_Widget.H:162
Fl_Text_Display::textsize
Fl_Fontsize textsize() const
Definition: Fl_Text_Display.H:302
Fl_Text_Display::measure_proportional_character
double measure_proportional_character(const char *s, int colNum, int pos) const
Wrapping calculations.
Definition: Fl_Text_Display.cxx:3525
FILL_MASK
#define FILL_MASK
Definition: Fl_Text_Display.cxx:61
Fl_Text_Display::linenumber_fgcolor
Fl_Color linenumber_fgcolor() const
Definition: Fl_Text_Display.cxx:286
Fl_Widget::resize
virtual void resize(int x, int y, int w, int h)
Definition: Fl_Widget.cxx:150
FL_ALIGN_RIGHT
const Fl_Align FL_ALIGN_RIGHT
Definition: Enumerations.H:841
FL_LEFT_MOUSE
#define FL_LEFT_MOUSE
The left mouse button.
Definition: Enumerations.H:540
Fl_Text_Display::mTopLineNum
int mTopLineNum
Definition: Fl_Text_Display.H:472
Fl::error
static void(* error)(const char *,...)
Definition: Fl.H:513
Fl_Text_Display::damage_range1_start
int damage_range1_start
Definition: Fl_Text_Display.H:449
scroll_x
static int scroll_x
Definition: Fl_Text_Display.cxx:83
length
png_uint_32 length
Definition: png.c:2173
Fl_Text_Buffer::line_start
int line_start(int pos) const
Definition: Fl_Text_Buffer.cxx:810
IS_UTF8_ALIGNED
#define IS_UTF8_ALIGNED(a)
Definition: Fl_Text_Buffer.H:33
FL_RELEASE
Definition: Enumerations.H:244
Fl_Text_Buffer
This class manages Unicode text displayed in one or more Fl_Text_Display widgets.
Definition: Fl_Text_Buffer.H:158
fl_color_average
Fl_Color fl_color_average(Fl_Color c1, Fl_Color c2, float weight)
Definition: fl_color.cxx:402
extended
unsigned short extended
Definition: Fl_win32.cxx:998
Fl_Text_Display::position_to_linecol
int position_to_linecol(int pos, int *lineNum, int *column) const
Find the line and column number of position pos.
Definition: Fl_Text_Display.cxx:1125
Fl_Align
unsigned Fl_Align
Definition: Enumerations.H:828
start
static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, int &X, int &Y, int &W, int &H)
Definition: Fl_Image.cxx:655
Fl_Text_Display::draw
virtual void draw()
Draw the widget.
Definition: Fl_Text_Display.cxx:3679
Fl_Text_Display::word_end
int word_end(int pos) const
Definition: Fl_Text_Display.H:261
Fl_Text_Buffer::copy
void copy(Fl_Text_Buffer *fromBuf, int fromStart, int fromEnd, int toPos)
Definition: Fl_Text_Buffer.cxx:364
FL_CTRL
#define FL_CTRL
One of the ctrl keys is down.
Definition: Enumerations.H:559
Fl_Text_Display::wrap_uses_character
int wrap_uses_character(int lineEndPos) const
Check if the line break is caused by a \n or by line wrapping.
Definition: Fl_Text_Display.cxx:3603
Fl_Text_Display::mCursorPos
int mCursorPos
Definition: Fl_Text_Display.H:451
Fl_Text_Display::mNStyles
int mNStyles
Definition: Fl_Text_Display.H:485
Fl_Text_Display::mFirstChar
int mFirstChar
Definition: Fl_Text_Display.H:464
Fl_Text_Display::find_wrap_range
void find_wrap_range(const char *deletedText, int pos, int nInserted, int nDeleted, int *modRangeStart, int *modRangeEnd, int *linesInserted, int *linesDeleted)
Wrapping calculations.
Definition: Fl_Text_Display.cxx:3116
Fl_Text_Display::WRAP_AT_BOUNDS
Definition: Fl_Text_Display.H:128
FL_DAMAGE_CHILD
Definition: Enumerations.H:1106
Fl_Text_Display::mLineStarts
int * mLineStarts
Definition: Fl_Text_Display.H:471
FL_ENTER
Definition: Enumerations.H:253
Fl_Text_Display::Style_Table_Entry::font
Fl_Font font
text font
Definition: Fl_Text_Display.H:150
Fl_Text_Display::w
int w
Definition: Fl_Text_Display.H:517
Fl_Text_Display::WRAP_AT_PIXEL
Definition: Fl_Text_Display.H:127
Fl_Text_Display::redisplay_range
void redisplay_range(int start, int end)
Marks text from start to end as needing a redraw. This function will trigger a damage event and later...
Definition: Fl_Text_Display.cxx:750
Fl_Text_Display::FIND_INDEX
Definition: Fl_Text_Display.H:379
Fl_Text_Display::xy_to_rowcol
void xy_to_rowcol(int x, int y, int *row, int *column, int PosType=CHARACTER_POS) const
Translate pixel coordinates into row and column.
Definition: Fl_Text_Display.cxx:2553
Fl::event_inside
static int event_inside(int, int, int, int)
Definition: Fl.cxx:227
Fl_Text_Display::Style_Table_Entry::size
Fl_Fontsize size
text font size
Definition: Fl_Text_Display.H:151
Fl_Text_Display::get_absolute_top_line_number
int get_absolute_top_line_number() const
Line numbering stuff, currently unused.
Definition: Fl_Text_Display.cxx:1847
FL_DOWN_FRAME
see figure 1
Definition: Enumerations.H:610
Fl_Text_Display::mLineNumWidth
int mLineNumWidth
Definition: Fl_Text_Display.H:526
Fl_Text_Display::find_x
int find_x(const char *s, int len, int style, int x) const
Find the index of the character that lies at the given x position.
Definition: Fl_Text_Display.cxx:2103
FL_ALIGN_BOTTOM_RIGHT
const Fl_Align FL_ALIGN_BOTTOM_RIGHT
Definition: Enumerations.H:861
Fl_Text_Display::textsize_
Fl_Fontsize textsize_
Definition: Fl_Text_Display.H:522