]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
Minor code shuffle.
[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 openStuff(BufferView *);
381         ///
382         void cutSelection(BufferView *, bool = true);
383         ///
384         void copySelection(BufferView *);
385         ///
386         void pasteSelection(BufferView *);
387         ///
388         void copyEnvironmentType();
389         ///
390         void pasteEnvironmentType(BufferView *);
391         ///
392         void insertFootnote();
393         ///
394         void insertMarginpar();
395         ///
396         void insertFigure();
397         ///
398         void insertTabular();
399
400         /** the DTP switches for paragraphs. LyX will store the top settings
401          always in the first physical paragraph, the bottom settings in the
402          last. When a paragraph is broken, the top settings rest, the bottom 
403          settings are given to the new one. So I can make shure, they do not
404          duplicate themself (and you cannnot make dirty things with them! )
405          */ 
406         void setParagraph(BufferView *,
407                           bool line_top, bool line_bottom,
408                           bool pagebreak_top, bool pagebreak_bottom,
409                           VSpace const & space_top,
410                           VSpace const & space_bottom,
411                           LyXAlignment align, 
412                           string labelwidthstring,
413                           bool noindent);
414
415         /* these things are for search and replace */
416
417         /** sets the selection over the number of characters of string,
418           no check!!
419           */
420         void setSelectionOverString(BufferView *, string const & str);
421
422         /** simple replacing. The font of the first selected character
423           is used
424           */
425         void replaceSelectionWithString(BufferView *, string const & str);
426
427         /// needed to insert the selection
428         void insertStringAsLines(BufferView *, string const & str);
429         /// needed to insert the selection
430         void insertStringAsParagraphs(BufferView *, string const & str);
431
432         /// Find next inset of some specified type.
433         bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
434                            string const & contents = string()) const;
435         ///
436
437         /* for the greater insets */
438   
439         /// returns false if inset wasn't found
440         bool updateInset(BufferView *, Inset *);
441         ///
442         void checkParagraph(BufferView *, Paragraph * par,
443                             Paragraph::size_type pos);
444         ///
445         int numberOfCell(Paragraph * par,
446                          Paragraph::size_type pos) const;
447         ///
448         void removeTableRow(LyXCursor & cursor) const;
449         ///
450         bool isEmptyTableCell() const;
451         ///
452         void toggleAppendix(BufferView *);
453         ///
454         int workWidth(BufferView *) const;
455         ///
456         void computeBidiTables(Buffer const *, Row * row) const;
457
458         /// Maps positions in the visual string to positions in logical string.
459         inline
460         Paragraph::size_type log2vis(Paragraph::size_type pos) const {
461                 if (bidi_start == -1)
462                         return pos;
463                 else
464                         return log2vis_list[pos-bidi_start];
465         }
466
467         /// Maps positions in the logical string to positions in visual string.
468         inline
469         Paragraph::size_type vis2log(Paragraph::size_type pos) const {
470                 if (bidi_start == -1)
471                         return pos;
472                 else
473                         return vis2log_list[pos-bidi_start];
474         }
475         ///
476         inline
477         Paragraph::size_type bidi_level(Paragraph::size_type pos) const {
478                 if (bidi_start == -1)
479                         return 0;
480                 else
481                         return bidi_levels[pos-bidi_start];
482         }       
483         ///
484         inline
485         bool bidi_InRange(Paragraph::size_type pos) const {
486                 return bidi_start == -1 ||
487                         (bidi_start <= pos && pos <= bidi_end);
488         }
489 private:
490         ///
491         mutable Row * firstrow;
492         ///
493         mutable Row * lastrow;
494
495         /** Copybuffer for copy environment type.
496           Asger has learned that this should be a buffer-property instead
497           Lgb has learned that 'char' is a lousy type for non-characters
498           */
499         LyXTextClass::size_type copylayouttype;
500
501         /** inserts a new row behind the specified row, increments
502             the touched counters */
503         void insertRow(Row * row, Paragraph * par,
504                        Paragraph::size_type pos) const;
505         /** removes the row and reset the touched counters */
506         void removeRow(Row * row) const;
507
508         /** remove all following rows of the paragraph of the specified row. */
509         void removeParagraph(Row * row) const;
510
511         /** insert the specified paragraph behind the specified row */
512         void insertParagraph(BufferView *,
513                              Paragraph * par, Row * row) const;
514
515         /** appends  the implizit specified paragraph behind the specified row,
516          * start at the implizit given position */
517         void appendParagraph(BufferView *, Row * row) const;
518    
519         ///
520         void breakAgain(BufferView *, Row * row) const;
521         ///
522         void breakAgainOneRow(BufferView *, Row * row);
523         /// Calculate and set the height of the row
524         void setHeightOfRow(BufferView *, Row * row_ptr) const;
525
526         /** this calculates the specified parameters. needed when setting
527          * the cursor and when creating a visible row */ 
528         void prepareToPrint(BufferView *, Row * row, float & x,
529                             float & fill_separator, 
530                             float & fill_hfill,
531                             float & fill_label_hfill,
532                             bool bidi = true) const;
533
534         ///
535         void deleteEmptyParagraphMechanism(BufferView *,
536                                            LyXCursor const & old_cursor) const;
537
538 public:
539         /** Updates all counters starting BEHIND the row. Changed paragraphs
540          * with a dynamic left margin will be rebroken. */ 
541         void updateCounters(BufferView *, Row * row) const;
542 private:
543         ///
544         void setCounter(Buffer const *, Paragraph * par) const;
545    
546         /*
547          * some low level functions
548          */
549         
550         ///
551         int singleWidth(BufferView *, Paragraph * par,
552                         Paragraph::size_type pos) const;
553         ///
554         int singleWidth(BufferView *, Paragraph * par,
555                         Paragraph::size_type pos, char c) const;
556         ///
557         void draw(BufferView *, Row const * row,
558                   Paragraph::size_type & pos,
559                   int offset, float & x, bool cleared);
560
561         /// get the next breakpoint in a given paragraph
562         Paragraph::size_type nextBreakPoint(BufferView *, Row const * row,
563                                                int width) const;
564         /// returns the minimum space a row needs on the screen in pixel
565         int fill(BufferView *, Row * row, int workwidth) const;
566         
567         /** returns the minimum space a manual label needs on the
568           screen in pixel */ 
569         int labelFill(BufferView *, Row const * row) const;
570
571         ///
572         Paragraph::size_type
573         beginningOfMainBody(Buffer const *, Paragraph const * par) const;
574         
575         /** Returns the left beginning of the text.
576           This information cannot be taken from the layouts-objekt, because
577           in LaTeX the beginning of the text fits in some cases
578           (for example sections) exactly the label-width.
579           */
580         int leftMargin(BufferView *, Row const * row) const;
581         ///
582         int rightMargin(Buffer const *, Row const * row) const;
583         ///
584         int labelEnd (BufferView *, Row const * row) const;
585
586         /** returns the number of separators in the specified row.
587           The separator on the very last column doesnt count
588           */ 
589         int numberOfSeparators(Buffer const *, Row const * row) const;
590
591         /** returns the number of hfills in the specified row. The
592           LyX-Hfill is a LaTeX \hfill so that the hfills at the
593           beginning and at the end were ignored. This is {\em MUCH}
594           more usefull than not to ignore!
595           */
596         int numberOfHfills(Buffer const *, Row const * row) const;
597    
598         /// like NumberOfHfills, but only those in the manual label!
599         int numberOfLabelHfills(Buffer const *, Row const * row) const;
600         /** returns true, if a expansion is needed. Rules are given by 
601           LaTeX
602           */
603         bool hfillExpansion(Buffer const *, Row const * row_ptr,
604                             Paragraph::size_type pos) const;
605
606
607         ///
608         mutable std::vector<Paragraph::size_type> log2vis_list;
609
610         ///
611         mutable std::vector<Paragraph::size_type> vis2log_list;
612
613         ///
614         mutable std::vector<Paragraph::size_type> bidi_levels;
615
616         ///
617         mutable Paragraph::size_type bidi_start;
618
619         ///
620         mutable Paragraph::size_type bidi_end;
621
622         ///
623         mutable bool bidi_same_direction;
624
625         ///
626         unsigned char transformChar(unsigned char c, Paragraph * par,
627                                     Paragraph::size_type pos) const;
628
629         /** returns the paragraph position of the last character in the 
630           specified row
631           */
632         Paragraph::size_type rowLast(Row const * row) const;
633         ///
634         Paragraph::size_type rowLastPrintable(Row const * row) const;
635
636         ///
637         void charInserted();
638 public:
639         //
640         // special owner functions
641         ///
642         Paragraph * ownerParagraph() const;
643         //
644         Paragraph * ownerParagraph(Paragraph *) const;
645         // set it searching first for the right owner using the paragraph id
646         Paragraph * ownerParagraph(int id, Paragraph *) const;
647 };
648
649
650 /* returns a pointer to the row near the specified y-coordinate
651  * (relative to the whole text). y is set to the real beginning
652  * of this row */
653 inline
654 Row * LyXText::getRowNearY(int & y) const
655 {
656         // If possible we should optimize this method. (Lgb)
657         Row * tmprow = firstrow;
658         int tmpy = 0;
659         
660         while (tmprow->next() && tmpy + tmprow->height() <= y) {
661                 tmpy += tmprow->height();
662                 tmprow = tmprow->next();
663         }
664         
665         y = tmpy;   // return the real y
666         return tmprow;
667 }
668 #endif