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