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