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