1 //
2 // "$Id$"
3 //
4 // Header file for Fl_Text_Display class.
5 //
6 // Copyright 2001-2016 by Bill Spitzak and others.
7 // Original code Copyright Mark Edel.  Permission to distribute under
8 // the LGPL for the FLTK library granted by Mark Edel.
9 //
10 // This library is free software. Distribution and use rights are outlined in
11 // the file "COPYING" which should have been included with this file.  If this
12 // file is missing or damaged, see the license at:
13 //
14 //     http://www.fltk.org/COPYING.php
15 //
16 // Please report all bugs and problems on the following page:
17 //
18 //     http://www.fltk.org/str.php
19 //
20 
21 /* \file
22  Fl_Text_Display widget . */
23 
24 #ifndef FL_TEXT_DISPLAY_H
25 #define FL_TEXT_DISPLAY_H
26 
27 #include "fl_draw.H"
28 #include "Fl_Group.H"
29 #include "Fl_Widget.H"
30 #include "Fl_Scrollbar.H"
31 #include "Fl_Text_Buffer.H"
32 
33 /**
34  \brief Rich text display widget.
35 
36  This is the FLTK text display widget. It allows the user to view
37  multiple lines of text and supports highlighting, word wrap, mixes
38  of font faces and colors, line numbers and scrolling.  The buffer
39  that is displayed in the widget is managed by the Fl_Text_Buffer
40  class. A single Text Buffer can be displayed by multiple Text
41  Displays.
42 
43  \image html editor.png "Fl_Text_Display widget"
44  \image latex editor.png "Fl_Text_Display widget" width=6cm
45  <BR><BR>
46  \image html editor-linenumbers.png "Fl_Text_Display widget with line numbers enabled"
47  \image latex editor-linenumbers.png "Fl_Text_Display widget with line numbers enabled" width=6cm
48 
49  \b Example \b Use
50  \code
51      #include <FL/FL_Text_Display.H>
52      ..
53      int main() {
54          ..
55          Fl_Text_Buffer *buff = new Fl_Text_Buffer();
56          Fl_Text_Display *disp = new Fl_Text_Display(10, 10, 640, 480);
57          disp->buffer(buff);                 // attach text buffer to display widget
58          buff->text("line one\nline two");   // add some text to buffer
59 	 ..
60      }
61  \endcode
62 
63  \b Features
64 
65  - Word wrap: wrap_mode(), wrapped_column(), wrapped_row()
66  - Font control: textfont(), textsize(), textcolor()
67  - Font styling: highlight_data()
68  - Cursor: cursor_style(), show_cursor(), hide_cursor(), cursor_color()
69  - Line numbers: linenumber_width(), linenumber_font(),
70    linenumber_size(), linenumber_fgcolor(), linenumber_bgcolor(),
71    linenumber_align(), linenumber_format()
72 
73  Note that other features may be available via Fl_Text_Editor
74  and Fl_Text_Buffer classes.
75 
76  \note Line numbers were added in 1.3.3. To avoid breaking ABI,
77        many of its options are read only. To adjust these features
78        in 1.3.x, you must build FLTK with FLTK_ABI_VERSION set to 10303
79        or higher.
80 
81  */
82 class FL_EXPORT Fl_Text_Display: public Fl_Group {
83 
84 public:
85 
86   /**
87    text display cursor shapes enumeration
88    */
89   enum {
90     NORMAL_CURSOR,    /**< I-beam */
91     CARET_CURSOR,     /**< caret under the text */
92     DIM_CURSOR,       /**< dim I-beam */
93     BLOCK_CURSOR,     /**< unfille box under the current character */
94     HEAVY_CURSOR,     /**< thick I-beam */
95     SIMPLE_CURSOR    /**< as cursor as Fl_Input cursor */
96   };
97 
98   /**
99    the character position is the left edge of a character, whereas
100    the cursor is thought to be between the centers of two consecutive
101    characters.
102    */
103   enum {
104     CURSOR_POS,
105     CHARACTER_POS
106   };
107 
108   /**
109    drag types - they match Fl::event_clicks() so that single clicking to
110    start a collection selects by character, double clicking selects by
111    word and triple clicking selects by line.
112    */
113   enum {
114     DRAG_NONE = -2,
115     DRAG_START_DND = -1,
116     DRAG_CHAR = 0,
117     DRAG_WORD = 1,
118     DRAG_LINE = 2
119   };
120 
121   /**
122    wrap types - used in wrap_mode()
123    */
124   enum {
125     WRAP_NONE,      /**< don't wrap text at all */
126     WRAP_AT_COLUMN, /**< wrap text at the given text column */
127     WRAP_AT_PIXEL,  /**< wrap text at a pixel position */
128     WRAP_AT_BOUNDS  /**< wrap text so that it fits into the widget width */
129   };
130 
131   friend void fl_text_drag_me(int pos, Fl_Text_Display* d);
132 
133   typedef void (*Unfinished_Style_Cb)(int, void *);
134 
135   /**
136    This structure associates the color, font, and font size of a string to draw
137    with an attribute mask matching attr.
138 
139    There must be one entry for each style that can be used in an
140    Fl_Text_Display for displaying text. The style table is an array of
141    struct Style_Table_Entry.
142 
143    The style table is associated with an Fl_Text_Display by using
144    Fl_Text_Display::highlight_data().
145 
146    \see Fl_Text_Display::highlight_data()
147    */
148   struct Style_Table_Entry {
149     Fl_Color    color;	///< text color
150     Fl_Font     font;	///< text font
151     Fl_Fontsize size;	///< text font size
152     unsigned    attr;	///< currently unused (this may be change in the future)
153   };
154 
155   Fl_Text_Display(int X, int Y, int W, int H, const char *l = 0);
156   ~Fl_Text_Display();
157 
158   virtual int handle(int e);
159 
160   void buffer(Fl_Text_Buffer* buf);
161 
162   /**
163    Sets the current text buffer associated with the text widget.
164    Multiple text widgets can be associated with the same text buffer.
165    \param buf new text buffer
166    */
buffer(Fl_Text_Buffer & buf)167   void buffer(Fl_Text_Buffer& buf) { buffer(&buf); }
168 
169   /**
170    Gets the current text buffer associated with the text widget.
171    Multiple text widgets can be associated with the same text buffer.
172    \return current text buffer
173    */
buffer()174   Fl_Text_Buffer* buffer() const { return mBuffer; }
175 
176   void redisplay_range(int start, int end);
177   void scroll(int topLineNum, int horizOffset);
178   void insert(const char* text);
179   void overstrike(const char* text);
180   void insert_position(int newPos);
181 
182   /**
183    Gets the position of the text insertion cursor for text display.
184    \return insert position index into text buffer
185    */
insert_position()186   int insert_position() const { return mCursorPos; }
187   int position_to_xy(int pos, int* x, int* y) const;
188 
189   int in_selection(int x, int y) const;
190   void show_insert_position();
191 
192   int move_right();
193   int move_left();
194   int move_up();
195   int move_down();
196   int count_lines(int start, int end, bool start_pos_is_line_start) const;
197   int line_start(int pos) const;
198   int line_end(int startPos, bool startPosIsLineStart) const;
199   int skip_lines(int startPos, int nLines, bool startPosIsLineStart);
200   int rewind_lines(int startPos, int nLines);
201   void next_word(void);
202   void previous_word(void);
203 
204   void show_cursor(int b = 1);
205 
206   /**
207    Hides the text cursor.
208    */
hide_cursor()209   void hide_cursor() { show_cursor(0); }
210 
211   void cursor_style(int style);
212 
213   /**
214    Gets the text cursor color.
215    \return cursor color
216    */
cursor_color()217   Fl_Color cursor_color() const {return mCursor_color;}
218 
219   /**
220    Sets the text cursor color.
221    \param n new cursor color
222    */
cursor_color(Fl_Color n)223   void cursor_color(Fl_Color n) {mCursor_color = n;}
224 
225   /**
226    Gets the width/height of the scrollbars.
227    \return width of scrollbars
228    */
scrollbar_width()229   int scrollbar_width() const { return scrollbar_width_; }
230 
231   /**
232    Sets the width/height of the scrollbars.
233    \param W width of scrollbars
234    */
scrollbar_width(int W)235   void scrollbar_width(int W) { scrollbar_width_ = W; }
236 
237   /**
238    Gets the scrollbar alignment type.
239    \return scrollbar alignment
240    */
scrollbar_align()241   Fl_Align scrollbar_align() const { return scrollbar_align_; }
242 
243   /**
244    Sets the scrollbar alignment type.
245    \param a new scrollbar alignment
246    */
scrollbar_align(Fl_Align a)247   void scrollbar_align(Fl_Align a) { scrollbar_align_ = a; }
248 
249   /**
250    Moves the insert position to the beginning of the current word.
251    \param pos start calculation at this index
252    \return beginning of the words
253    */
word_start(int pos)254   int word_start(int pos) const { return buffer()->word_start(pos); }
255 
256   /**
257    Moves the insert position to the end of the current word.
258    \param pos start calculation at this index
259    \return index of first character after the end of the word
260    */
word_end(int pos)261   int word_end(int pos) const { return buffer()->word_end(pos); }
262 
263 
264   void highlight_data(Fl_Text_Buffer *styleBuffer,
265                       const Style_Table_Entry *styleTable,
266                       int nStyles, char unfinishedStyle,
267                       Unfinished_Style_Cb unfinishedHighlightCB,
268                       void *cbArg);
269 
270   int position_style(int lineStartPos, int lineLen, int lineIndex) const;
271 
272   /**
273    \todo FIXME : get set methods pointing on shortcut_
274    have no effects as shortcut_ is unused in this class and derived!
275    \return the current shortcut key
276    */
shortcut()277   int shortcut() const {return shortcut_;}
278 
279   /**
280    \todo FIXME : get set methods pointing on shortcut_
281    have no effects as shortcut_ is unused in this class and derived!
282    \param s the new shortcut key
283    */
shortcut(int s)284   void shortcut(int s) {shortcut_ = s;}
285 
286   /**
287    Gets the default font used when drawing text in the widget.
288    \return current text font face unless overridden by a style
289    */
textfont()290   Fl_Font textfont() const {return textfont_;}
291 
292   /**
293    Sets the default font used when drawing text in the widget.
294    \param s default text font face
295    */
textfont(Fl_Font s)296   void textfont(Fl_Font s) {textfont_ = s; mColumnScale = 0;}
297 
298   /**
299    Gets the default size of text in the widget.
300    \return current text height unless overridden by a style
301    */
textsize()302   Fl_Fontsize textsize() const {return textsize_;}
303 
304   /**
305    Sets the default size of text in the widget.
306    \param s new text size
307    */
textsize(Fl_Fontsize s)308   void textsize(Fl_Fontsize s) {textsize_ = s; mColumnScale = 0;}
309 
310   /**
311    Gets the default color of text in the widget.
312    \return text color unless overridden by a style
313    */
textcolor()314   Fl_Color textcolor() const {return textcolor_;}
315 
316   /**
317    Sets the default color of text in the widget.
318    \param n new text color
319    */
textcolor(Fl_Color n)320   void textcolor(Fl_Color n) {textcolor_ = n;}
321 
322   int wrapped_column(int row, int column) const;
323   int wrapped_row(int row) const;
324   void wrap_mode(int wrap, int wrap_margin);
325 
326   virtual void resize(int X, int Y, int W, int H);
327 
328   /**
329    Convert an x pixel position into a column number.
330    \param x number of pixels from the left margin
331    \return an approximate column number based on the main font
332    */
333   double x_to_col(double x) const;
334 
335   /**
336    Convert a column number into an x pixel position.
337    \param col an approximate column number based on the main font
338    \return number of pixels from the left margin to the left of an
339 	   average sized character
340    */
341   double col_to_x(double col) const;
342 
343   void linenumber_width(int width);
344   int linenumber_width() const;
345   void linenumber_font(Fl_Font val);
346   Fl_Font linenumber_font() const;
347   void linenumber_size(Fl_Fontsize val);
348   Fl_Fontsize linenumber_size() const;
349   void linenumber_fgcolor(Fl_Color val);
350   Fl_Color linenumber_fgcolor() const;
351   void linenumber_bgcolor(Fl_Color val);
352   Fl_Color linenumber_bgcolor() const;
353   void linenumber_align(Fl_Align val);
354   Fl_Align linenumber_align() const;
355   void linenumber_format(const char* val);
356   const char* linenumber_format() const;
357 
358 protected:
359   // Most (all?) of this stuff should only be called from resize() or
360   // draw().
361   // Anything with "vline" indicates thats it deals with currently
362   // visible lines.
363 
364   virtual void draw();
365   void draw_text(int X, int Y, int W, int H);
366   void draw_range(int start, int end);
367   void draw_cursor(int, int);
368 
369   void draw_string(int style, int x, int y, int toX, const char *string,
370                    int nChars) const;
371 
372   void draw_vline(int visLineNum, int leftClip, int rightClip,
373                   int leftCharIndex, int rightCharIndex);
374 
375   int find_x(const char *s, int len, int style, int x) const;
376 
377   enum {
378     DRAW_LINE,
379     FIND_INDEX,
380     FIND_INDEX_FROM_ZERO,
381     GET_WIDTH
382   };
383 
384   int handle_vline(int mode,
385                    int lineStart, int lineLen, int leftChar, int rightChar,
386                    int topClip, int bottomClip,
387                    int leftClip, int rightClip) const;
388 
389   void draw_line_numbers(bool clearAll);
390 
391   void clear_rect(int style, int x, int y, int width, int height) const;
392   void display_insert();
393 
394   void offset_line_starts(int newTopLineNum);
395 
396   void calc_line_starts(int startLine, int endLine);
397 
398   void update_line_starts(int pos, int charsInserted, int charsDeleted,
399                           int linesInserted, int linesDeleted, int *scrolled);
400 
401   void calc_last_char();
402 
403   int position_to_line( int pos, int* lineNum ) const;
404   double string_width(const char* string, int length, int style) const;
405 
406   static void scroll_timer_cb(void*);
407 
408   static void buffer_predelete_cb(int pos, int nDeleted, void* cbArg);
409   static void buffer_modified_cb(int pos, int nInserted, int nDeleted,
410                                  int nRestyled, const char* deletedText,
411                                  void* cbArg);
412 
413   static void h_scrollbar_cb(Fl_Scrollbar* w, Fl_Text_Display* d);
414   static void v_scrollbar_cb( Fl_Scrollbar* w, Fl_Text_Display* d);
415   void update_v_scrollbar();
416   void update_h_scrollbar();
417   int measure_vline(int visLineNum) const;
418   int longest_vline() const;
419   int empty_vlines() const;
420   int vline_length(int visLineNum) const;
421   int xy_to_position(int x, int y, int PosType = CHARACTER_POS) const;
422 
423   void xy_to_rowcol(int x, int y, int* row, int* column,
424                     int PosType = CHARACTER_POS) const;
425   void maintain_absolute_top_line_number(int state);
426   int get_absolute_top_line_number() const;
427   void absolute_top_line_number(int oldFirstChar);
428   int maintaining_absolute_top_line_number() const;
429   void reset_absolute_top_line_number();
430   int position_to_linecol(int pos, int* lineNum, int* column) const;
431   int scroll_(int topLineNum, int horizOffset);
432 
433   void extend_range_for_styles(int* start, int* end);
434 
435   void find_wrap_range(const char *deletedText, int pos, int nInserted,
436                        int nDeleted, int *modRangeStart, int *modRangeEnd,
437                        int *linesInserted, int *linesDeleted);
438   void measure_deleted_lines(int pos, int nDeleted);
439   void wrapped_line_counter(Fl_Text_Buffer *buf, int startPos, int maxPos,
440                             int maxLines, bool startPosIsLineStart,
441                             int styleBufOffset, int *retPos, int *retLines,
442                             int *retLineStart, int *retLineEnd,
443                             bool countLastLineMissingNewLine = true) const;
444   void find_line_end(int pos, bool start_pos_is_line_start, int *lineEnd,
445                      int *nextLineStart) const;
446   double measure_proportional_character(const char *s, int colNum, int pos) const;
447   int wrap_uses_character(int lineEndPos) const;
448 
449   int damage_range1_start, damage_range1_end;
450   int damage_range2_start, damage_range2_end;
451   int mCursorPos;
452   int mCursorOn;
453   int mCursorOldY;              /* Y pos. of cursor for blanking */
454   int mCursorToHint;            /* Tells the buffer modified callback
455                                  where to move the cursor, to reduce
456                                  the number of redraw calls */
457   int mCursorStyle;             /* One of enum cursorStyles above */
458   int mCursorPreferredXPos;     /* Pixel position for vert. cursor movement */
459   int mNVisibleLines;           /* # of visible (displayed) lines */
460   int mNBufferLines;            /* # of newlines in the buffer */
461   Fl_Text_Buffer* mBuffer;      /* Contains text to be displayed */
462   Fl_Text_Buffer* mStyleBuffer; /* Optional parallel buffer containing
463                                  color and font information */
464   int mFirstChar, mLastChar;    /* Buffer positions of first and last
465                                  displayed character (lastChar points
466                                  either to a newline or one character
467                                  beyond the end of the buffer) */
468   int mContinuousWrap;          /* Wrap long lines when displaying */
469   int mWrapMarginPix; 	    	/* Margin in # of pixels for
470                                  wrapping in continuousWrap mode */
471   int* mLineStarts;
472   int mTopLineNum;              /* Line number of top displayed line
473                                  of file (first line of file is 1) */
474   int mAbsTopLineNum;           /* In continuous wrap mode, the line
475                                   number of the top line if the text
476                                   were not wrapped (note that this is
477                                   only maintained as needed). */
478   int mNeedAbsTopLineNum;       /* Externally settable flag to continue
479                                  maintaining absTopLineNum even if
480                                  it isn't needed for line # display */
481   int mHorizOffset;             /* Horizontal scroll pos. in pixels */
482   int mTopLineNumHint;          /* Line number of top displayed line
483                                  of file (first line of file is 1) */
484   int mHorizOffsetHint;         /* Horizontal scroll pos. in pixels */
485   int mNStyles;                 /* Number of entries in styleTable */
486   const Style_Table_Entry *mStyleTable; /* Table of fonts and colors for
487                                          coloring/syntax-highlighting */
488   char mUnfinishedStyle;        /* Style buffer entry which triggers
489                                  on-the-fly reparsing of region */
490   Unfinished_Style_Cb mUnfinishedHighlightCB; /* Callback to parse "unfinished" */
491   /* regions */
492   void* mHighlightCBArg;        /* Arg to unfinishedHighlightCB */
493 
494   int mMaxsize;
495 
496   int mSuppressResync;          /* Suppress resynchronization of line
497                                  starts during buffer updates */
498   int mNLinesDeleted;           /* Number of lines deleted during
499                                  buffer modification (only used
500                                  when resynchronization is suppressed) */
501   int mModifyingTabDistance;    /* Whether tab distance is being
502                                  modified */
503 
504   mutable double mColumnScale; /* Width in pixels of an average character. This
505                                  value is calculated as needed (lazy eval); it
506                                  needs to be mutable so that it can be calculated
507                                  within a method marked as "const" */
508 
509   Fl_Color mCursor_color;
510 
511   Fl_Scrollbar* mHScrollBar;
512   Fl_Scrollbar* mVScrollBar;
513   int scrollbar_width_;
514   Fl_Align scrollbar_align_;
515   int dragPos, dragType, dragging;
516   int display_insert_position_hint;
517   struct { int x, y, w, h; } text_area;
518 
519   int shortcut_;
520 
521   Fl_Font textfont_;
522   Fl_Fontsize textsize_;
523   Fl_Color textcolor_;
524 
525   // Line number margin and width
526   int mLineNumLeft, mLineNumWidth;
527 
528   // Line number font/colors
529 #if FLTK_ABI_VERSION >= 10303
530   Fl_Font     linenumber_font_;
531   Fl_Fontsize linenumber_size_;
532   Fl_Color    linenumber_fgcolor_;
533   Fl_Color    linenumber_bgcolor_;
534   Fl_Align    linenumber_align_;
535   const char* linenumber_format_;
536 #endif
537 };
538 
539 #endif
540 
541 //
542 // End of "$Id$".
543 //
544