]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
Added new FINISED states FINISHED_RIGHT, FINISHED_UP, FINISHED_DOWN.
[lyx.git] / src / lyxtext.h
1 // -*- C++ -*-
2 /* This file is part of
3  * ====================================================== 
4  * 
5  *           LyX, The Document Processor
6  *       
7  *           Copyright 1995 Matthias Ettrich
8  *           Copyright 1995-2001 The LyX Team.
9  *
10  * ====================================================== */
11
12 #ifndef LYXTEXT_H
13 #define LYXTEXT_H
14
15 #ifdef __GNUG__
16 #pragma interface
17 #endif
18
19 #include "lyxfont.h"
20 #include "lyxcursor.h"
21 #include "paragraph.h"
22 #include "layout.h"
23 #include "lyxrow.h"
24 #include "vspace.h"
25 #include "LColor.h"
26
27 class Buffer;
28 class BufferParams;
29 class BufferView;
30 class InsetText;
31
32
33 /**
34   This class holds the mapping between buffer paragraphs and screen rows.
35   */
36 class LyXText {
37 public:
38         ///
39         enum text_status {
40                 ///
41                 UNCHANGED = 0,
42                 ///
43                 CHANGED_IN_DRAW = 1,
44                 ///
45                 NEED_VERY_LITTLE_REFRESH = 2,
46                 ///
47                 NEED_MORE_REFRESH = 3
48         };
49         ///
50         enum word_location {
51                 // the word around the cursor, only if the cursor is
52                 //not at a boundary
53                 WHOLE_WORD_STRICT,
54                 // the word around the cursor
55                 WHOLE_WORD,
56                 /// the word begining from the cursor position
57                 PARTIAL_WORD,
58                 /// the word around the cursor or before the cursor
59                 PREVIOUS_WORD,
60                 /// the next word (not yet used)
61                 NEXT_WORD
62         };
63
64         /// Constructor
65         LyXText(BufferView *);
66         ///
67         LyXText(InsetText *);
68    
69         /// Destructor
70         ~LyXText();
71
72         void init(BufferView *, bool reinit = false);
73         ///
74         mutable int number_of_rows;
75         ///
76         mutable int height;
77         ///
78         mutable unsigned int width;
79         /// the current font settings
80         mutable LyXFont current_font;
81         /// the current font
82         mutable LyXFont real_current_font;
83         /// first visible pixel-row is set from LyXScreen!!!
84         // unsigned is wrong here for text-insets!
85         int first;
86         ///
87         BufferView * bv_owner;
88         ///
89         InsetText * inset_owner;
90         ///
91         UpdatableInset * the_locking_inset;
92
93         ///
94         int getRealCursorX(BufferView *) const;
95         ///
96         LyXFont const getFont(Buffer const *, Paragraph * par,
97                         Paragraph::size_type pos) const;
98         ///
99         LyXFont const getLayoutFont(Buffer const *, Paragraph * par) const;
100         ///
101         LyXFont const getLabelFont(Buffer const *, Paragraph * par) const;
102         ///
103         void setCharFont(Buffer const *, Paragraph * par,
104                          Paragraph::size_type pos, LyXFont const & font);
105         void setCharFont(BufferView *, Paragraph * par,
106                          Paragraph::size_type pos,
107                          LyXFont const & font, bool toggleall);
108         /// returns a pointer to the very first Paragraph
109         Paragraph * firstParagraph() const;
110   
111         /// what you expect when pressing <enter> at cursor position
112         void breakParagraph(BufferView *, char keep_layout = 0);
113
114         /** set layout over selection and make a total rebreak of
115           those paragraphs
116           */
117         Paragraph * setLayout(BufferView *, LyXCursor & actual_cursor,
118                                  LyXCursor & selection_start,
119                                  LyXCursor & selection_end,
120                                  LyXTextClass::size_type layout);
121         void setLayout(BufferView *, LyXTextClass::size_type layout);
122         
123         /// used in setlayout
124         void makeFontEntriesLayoutSpecific(Buffer const *, Paragraph * par);
125         
126         /** increment depth over selection and make a total rebreak of those 
127           paragraphs
128           */
129         void incDepth(BufferView *);
130         
131         /** decrement depth over selection and make a total rebreak of those  
132           paragraphs */
133         void decDepth(BufferView *);
134
135         /** Get the depth at current cursor position
136          */
137         int getDepth() const { return cursor.par()->getDepth(); }
138         
139         /** set font over selection and make a total rebreak of those
140           paragraphs.
141           toggleall defaults to false.
142           */
143         void setFont(BufferView *, LyXFont const &, bool toggleall = false);
144         
145         /** deletes and inserts again all paragaphs between the cursor
146           and the specified par. The Cursor is needed to set the refreshing
147           parameters. 
148           This function is needed after SetLayout and SetFont etc.
149           */
150         void redoParagraphs(BufferView *, LyXCursor const & cursor,
151                             Paragraph const * end_par) const;
152         ///
153         void redoParagraph(BufferView *) const;
154         
155         ///
156         void toggleFree(BufferView *, LyXFont const &, bool toggleall = false);
157
158         ///
159         string getStringToIndex(BufferView *);
160         
161         /** recalculates the heights of all previous rows of the
162             specified paragraph.  needed, if the last characters font
163             has changed.  
164             */
165         void redoHeightOfParagraph(BufferView *, LyXCursor const & cursor);
166         
167         /** forces the redrawing of a paragraph. Needed when manipulating a 
168             right address box
169             */ 
170         void redoDrawingOfParagraph(BufferView *, LyXCursor const & cursor);
171         
172         /** insert a character, moves all the following breaks in the 
173           same Paragraph one to the right and make a little rebreak
174           */
175         void insertChar(BufferView *, char c);
176         ///
177         void insertInset(BufferView *, Inset * inset);
178    
179         /** Completes the insertion with a full rebreak.
180             Returns true if something was broken. */
181         bool fullRebreak(BufferView *);
182
183         ///
184         mutable Row * need_break_row;
185         ///
186         mutable int refresh_y;
187         ///
188         int refresh_height;
189         ///
190         int refresh_width;
191         ///
192         int refresh_x;
193         ///
194         mutable Row * refresh_row;
195         ///
196         int refresh_pos;
197
198         /// give and set the LyXText status
199         text_status status() const;
200         ///
201         void status(BufferView *, text_status) const;
202
203 private:        
204         /** wether the screen needs a refresh,
205            starting with refresh_y
206            */
207         mutable text_status status_;
208         
209 public:
210         /** returns a pointer to the row near the specified y-coordinate
211           (relative to the whole text). y is set to the real beginning
212           of this row
213           */ 
214         Row * getRowNearY(int & y) const;
215         
216         /** returns the column near the specified x-coordinate of the row 
217          x is set to the real beginning of this column
218          */ 
219         int getColumnNearX(BufferView *, Row * row,
220                            int & x, bool & boundary) const;
221         
222         /** returns a pointer to a specified row. y is set to the beginning
223          of the row
224          */
225         Row * getRow(Paragraph * par,
226                      Paragraph::size_type pos, int & y) const;
227
228         /** returns the height of a default row, needed  for scrollbar
229          */
230         int defaultHeight() const;
231    
232         /** The cursor.
233           Later this variable has to be removed. There should be now internal
234           cursor in a text (and thus not in a buffer). By keeping this it is
235           (I think) impossible to have several views with the same buffer, but
236           the cursor placed at different places.
237           [later]
238           Since the LyXText now has been moved from Buffer to BufferView
239           it should not be absolutely needed to move the cursor...
240           */
241         mutable LyXCursor cursor;
242
243         /** The structrue that keeps track of the selections set. */
244         struct Selection {
245                 Selection() 
246                         : set_(false), mark_(false)
247                         {}
248                 bool set() const {
249                         return set_;
250                 }
251                 void set(bool s) {
252                         set_ = s;
253                 }
254                 bool mark() const {
255                         return mark_;
256                 }
257                 void mark(bool m) {
258                         mark_ = m;
259                 }
260                 LyXCursor cursor;
261                 LyXCursor start;
262                 LyXCursor end;
263         private:
264                 bool set_; // former selection
265                 bool mark_; // former mark_set
266                 
267         };
268         mutable Selection selection;
269
270         /// needed for the toggling
271         LyXCursor last_sel_cursor;
272         ///
273         LyXCursor toggle_cursor;
274         ///
275         LyXCursor toggle_end_cursor;
276    
277         /// need the selection cursor:
278         void setSelection(BufferView *);
279         ///
280         void clearSelection() const;
281         ///
282         string const selectionAsString(Buffer const *) const;
283         
284         /// select the word we need depending on word_location
285         void getWord(LyXCursor & from, LyXCursor & to, 
286                      word_location const) const;
287         /// just selects the word the cursor is in
288         void selectWord(BufferView *, word_location const);
289         /// returns the inset at cursor (if it exists), 0 otherwise
290         Inset * getInset() const;
291
292         /** 'selects" the next word, where the cursor is not in 
293          and returns this word as string. THe cursor will be moved 
294          to the beginning of this word. 
295          With SelectSelectedWord can this be highlighted really
296          */ 
297         string const selectNextWord(BufferView *, float & value) const;
298         ///
299         void selectSelectedWord(BufferView *);
300         ///
301         void setCursor(BufferView *, Paragraph * par,
302                        Paragraph::size_type pos,
303                        bool setfont = true,
304                        bool boundary = false) const;
305         ///
306         void setCursor(BufferView *, LyXCursor &, Paragraph * par,
307                        Paragraph::size_type pos,
308                        bool boundary = false) const;
309         ///
310         void setCursorIntern(BufferView *, Paragraph * par,
311                              Paragraph::size_type pos,
312                              bool setfont = true,
313                              bool boundary = false) const;
314         ///
315         void setCurrentFont(BufferView *) const;
316
317         ///
318         bool isBoundary(Buffer const *, Paragraph * par,
319                         Paragraph::size_type pos) const;
320         ///
321         bool isBoundary(Buffer const *, Paragraph * par,
322                          Paragraph::size_type pos,
323                          LyXFont const & font) const;
324
325         ///
326         void setCursorFromCoordinates(BufferView *, int x, int y) const;
327         ///
328         void setCursorFromCoordinates(BufferView *, LyXCursor &,
329                                       int x, int y) const;
330         ///
331         void cursorUp(BufferView *) const;
332         ///
333         void cursorDown(BufferView *) const;
334         ///
335         void cursorLeft(BufferView *, bool internal = true) const;
336         ///
337         void cursorRight(BufferView *, bool internal = true) const;
338         ///
339         void cursorLeftOneWord(BufferView *) const;
340         ///
341         void cursorLeftOneWord(LyXCursor &) const;
342         ///
343         void cursorRightOneWord(BufferView *) const;
344         ///
345         void cursorUpParagraph(BufferView *) const;
346         ///
347         void cursorDownParagraph(BufferView *) const;
348         ///
349         void cursorHome(BufferView *) const;
350         ///
351         void cursorEnd(BufferView *) const;
352         ///
353         void cursorTab(BufferView *) const;
354         ///
355         void cursorTop(BufferView *) const;
356         ///
357         void cursorBottom(BufferView *) const;
358         ///
359         void Delete(BufferView *);
360         ///
361         void backspace(BufferView *);
362         ///
363         void deleteWordForward(BufferView *);
364         ///
365         void deleteWordBackward(BufferView *);
366         ///
367         void deleteLineForward(BufferView *);
368         ///
369         bool selectWordWhenUnderCursor(BufferView *, 
370                                        word_location const);
371         ///
372         enum TextCase {
373                 ///
374                 text_lowercase = 0,
375                 ///
376                 text_capitalization = 1,
377                 ///
378                 text_uppercase = 2
379         };
380         /// Change the case of the word at cursor position.
381         void changeCase(BufferView *, TextCase action);
382         ///
383         void changeRegionCase(BufferView * bview,
384                                        LyXCursor const & from,
385                                        LyXCursor const & to,
386                                        LyXText::TextCase action);
387         ///
388         void transposeChars(BufferView &);
389         
390         /** returns a printed row in a pixmap. The y value is needed to
391           decide, wether it is selected text or not. This is a strange
392           solution but faster.
393          */
394         void getVisibleRow(BufferView *, int y_offset, int x_offset,
395                            Row * row_ptr, int y, bool cleared=false);
396
397         /// 
398         void toggleInset(BufferView *);
399         ///
400         void cutSelection(BufferView *, bool doclear = true, bool realcut = true);
401         ///
402         void copySelection(BufferView *);
403         ///
404         void pasteSelection(BufferView *);
405         ///
406         void copyEnvironmentType();
407         ///
408         void pasteEnvironmentType(BufferView *);
409
410         /** the DTP switches for paragraphs. LyX will store the top settings
411          always in the first physical paragraph, the bottom settings in the
412          last. When a paragraph is broken, the top settings rest, the bottom 
413          settings are given to the new one. So I can make shure, they do not
414          duplicate themself (and you cannnot make dirty things with them! )
415          */ 
416         void setParagraph(BufferView *,
417                           bool line_top, bool line_bottom,
418                           bool pagebreak_top, bool pagebreak_bottom,
419                           VSpace const & space_top,
420                           VSpace const & space_bottom,
421                           LyXAlignment align, 
422                           string labelwidthstring,
423                           bool noindent);
424
425         /* these things are for search and replace */
426
427         /** sets the selection over the number of characters of string,
428           no check!!
429           */
430         void setSelectionOverString(BufferView *, string const & str);
431
432         /** simple replacing. The font of the first selected character
433           is used
434           */
435         void replaceSelectionWithString(BufferView *, string const & str);
436
437         /// needed to insert the selection
438         void insertStringAsLines(BufferView *, string const & str);
439         /// needed to insert the selection
440         void insertStringAsParagraphs(BufferView *, string const & str);
441
442         /// Find next inset of some specified type.
443         bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
444                            string const & contents = string()) const;
445         ///
446
447         /* for the greater insets */
448   
449         /// returns false if inset wasn't found
450         bool updateInset(BufferView *, Inset *);
451         ///
452         void checkParagraph(BufferView *, Paragraph * par,
453                             Paragraph::size_type pos);
454         ///
455         int numberOfCell(Paragraph * par,
456                          Paragraph::size_type pos) const;
457         ///
458         void removeTableRow(LyXCursor & cursor) const;
459         ///
460         bool isEmptyTableCell() const;
461         ///
462         void toggleAppendix(BufferView *);
463         ///
464         int workWidth(BufferView *) const;
465         ///
466         void computeBidiTables(Buffer const *, Row * row) const;
467
468         /// Maps positions in the visual string to positions in logical string.
469         inline
470         Paragraph::size_type log2vis(Paragraph::size_type pos) const {
471                 if (bidi_start == -1)
472                         return pos;
473                 else
474                         return log2vis_list[pos-bidi_start];
475         }
476
477         /// Maps positions in the logical string to positions in visual string.
478         inline
479         Paragraph::size_type vis2log(Paragraph::size_type pos) const {
480                 if (bidi_start == -1)
481                         return pos;
482                 else
483                         return vis2log_list[pos-bidi_start];
484         }
485         ///
486         inline
487         Paragraph::size_type bidi_level(Paragraph::size_type pos) const {
488                 if (bidi_start == -1)
489                         return 0;
490                 else
491                         return bidi_levels[pos-bidi_start];
492         }       
493         ///
494         inline
495         bool bidi_InRange(Paragraph::size_type pos) const {
496                 return bidi_start == -1 ||
497                         (bidi_start <= pos && pos <= bidi_end);
498         }
499 private:
500         ///
501         mutable Row * firstrow;
502         ///
503         mutable Row * lastrow;
504
505         /** Copybuffer for copy environment type.
506           Asger has learned that this should be a buffer-property instead
507           Lgb has learned that 'char' is a lousy type for non-characters
508           */
509         LyXTextClass::size_type copylayouttype;
510
511         /** inserts a new row behind the specified row, increments
512             the touched counters */
513         void insertRow(Row * row, Paragraph * par,
514                        Paragraph::size_type pos) const;
515         /** removes the row and reset the touched counters */
516         void removeRow(Row * row) const;
517
518         /** remove all following rows of the paragraph of the specified row. */
519         void removeParagraph(Row * row) const;
520
521         /** insert the specified paragraph behind the specified row */
522         void insertParagraph(BufferView *,
523                              Paragraph * par, Row * row) const;
524
525         /** appends  the implizit specified paragraph behind the specified row,
526          * start at the implizit given position */
527         void appendParagraph(BufferView *, Row * row) const;
528    
529         ///
530         void breakAgain(BufferView *, Row * row) const;
531         ///
532         void breakAgainOneRow(BufferView *, Row * row);
533         /// Calculate and set the height of the row
534         void setHeightOfRow(BufferView *, Row * row_ptr) const;
535
536         /** this calculates the specified parameters. needed when setting
537          * the cursor and when creating a visible row */ 
538         void prepareToPrint(BufferView *, Row * row, float & x,
539                             float & fill_separator, 
540                             float & fill_hfill,
541                             float & fill_label_hfill,
542                             bool bidi = true) const;
543
544         ///
545         void deleteEmptyParagraphMechanism(BufferView *,
546                                            LyXCursor const & old_cursor) const;
547
548 public:
549         /** Updates all counters starting BEHIND the row. Changed paragraphs
550          * with a dynamic left margin will be rebroken. */ 
551         void updateCounters(BufferView *, Row * row) const;
552 private:
553         ///
554         void setCounter(Buffer const *, Paragraph * par) const;
555    
556         /*
557          * some low level functions
558          */
559         
560         ///
561         int singleWidth(BufferView *, Paragraph * par,
562                         Paragraph::size_type pos) const;
563         ///
564         int singleWidth(BufferView *, Paragraph * par,
565                         Paragraph::size_type pos, char c) const;
566         ///
567         void draw(BufferView *, Row const * row,
568                   Paragraph::size_type & pos,
569                   int offset, float & x, bool cleared);
570
571         /// get the next breakpoint in a given paragraph
572         Paragraph::size_type nextBreakPoint(BufferView *, Row const * row,
573                                                int width) const;
574         /// returns the minimum space a row needs on the screen in pixel
575         int fill(BufferView *, Row * row, int workwidth) const;
576         
577         /** returns the minimum space a manual label needs on the
578           screen in pixel */ 
579         int labelFill(BufferView *, Row const * row) const;
580
581         ///
582         Paragraph::size_type
583         beginningOfMainBody(Buffer const *, Paragraph const * par) const;
584         
585         /** Returns the left beginning of the text.
586           This information cannot be taken from the layouts-objekt, because
587           in LaTeX the beginning of the text fits in some cases
588           (for example sections) exactly the label-width.
589           */
590         int leftMargin(BufferView *, Row const * row) const;
591         ///
592         int rightMargin(Buffer const *, Row const * row) const;
593         ///
594         int labelEnd (BufferView *, Row const * row) const;
595
596         /** returns the number of separators in the specified row.
597           The separator on the very last column doesnt count
598           */ 
599         int numberOfSeparators(Buffer const *, Row const * row) const;
600
601         /** returns the number of hfills in the specified row. The
602           LyX-Hfill is a LaTeX \hfill so that the hfills at the
603           beginning and at the end were ignored. This is {\em MUCH}
604           more usefull than not to ignore!
605           */
606         int numberOfHfills(Buffer const *, Row const * row) const;
607    
608         /// like NumberOfHfills, but only those in the manual label!
609         int numberOfLabelHfills(Buffer const *, Row const * row) const;
610         /** returns true, if a expansion is needed. Rules are given by 
611           LaTeX
612           */
613         bool hfillExpansion(Buffer const *, Row const * row_ptr,
614                             Paragraph::size_type pos) const;
615         /// 
616         LColor::color backgroundColor();
617
618
619         ///
620         mutable std::vector<Paragraph::size_type> log2vis_list;
621
622         ///
623         mutable std::vector<Paragraph::size_type> vis2log_list;
624
625         ///
626         mutable std::vector<Paragraph::size_type> bidi_levels;
627
628         ///
629         mutable Paragraph::size_type bidi_start;
630
631         ///
632         mutable Paragraph::size_type bidi_end;
633
634         ///
635         mutable bool bidi_same_direction;
636
637         ///
638         unsigned char transformChar(unsigned char c, Paragraph * par,
639                                     Paragraph::size_type pos) const;
640
641         /** returns the paragraph position of the last character in the 
642           specified row
643           */
644         Paragraph::size_type rowLast(Row const * row) const;
645         ///
646         Paragraph::size_type rowLastPrintable(Row const * row) const;
647
648         ///
649         void charInserted();
650 public:
651         //
652         // special owner functions
653         ///
654         Paragraph * ownerParagraph() const;
655         //
656         Paragraph * ownerParagraph(Paragraph *) const;
657         // set it searching first for the right owner using the paragraph id
658         Paragraph * ownerParagraph(int id, Paragraph *) const;
659 };
660
661
662 /* returns a pointer to the row near the specified y-coordinate
663  * (relative to the whole text). y is set to the real beginning
664  * of this row */
665 inline
666 Row * LyXText::getRowNearY(int & y) const
667 {
668         // If possible we should optimize this method. (Lgb)
669         Row * tmprow = firstrow;
670         int tmpy = 0;
671         
672         while (tmprow->next() && tmpy + tmprow->height() <= y) {
673                 tmpy += tmprow->height();
674                 tmprow = tmprow->next();
675         }
676         
677         y = tmpy;   // return the real y
678         return tmprow;
679 }
680 #endif