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