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