]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
87d6b78c4b69127129341faf36ee4f9ce8bfca03
[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 *, bool reinit = false);
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, 
272                      word_location const) const;
273         /// just selects the word the cursor is in
274         void selectWord(BufferView *, word_location const = WHOLE_WORD);
275         /// returns the inset at cursor (if it exists), 0 otherwise
276         Inset * getInset() const;
277
278         /** 'selects" the next word, where the cursor is not in 
279          and returns this word as string. THe cursor will be moved 
280          to the beginning of this word. 
281          With SelectSelectedWord can this be highlighted really
282          */ 
283         string const selectNextWord(BufferView *, float & value) const;
284         ///
285         void selectSelectedWord(BufferView *);
286         ///
287         void setCursor(BufferView *, Paragraph * par,
288                        Paragraph::size_type pos,
289                        bool setfont = true,
290                        bool boundary = false) const;
291         ///
292         void setCursor(BufferView *, LyXCursor &, Paragraph * par,
293                        Paragraph::size_type pos,
294                        bool boundary = false) const;
295         ///
296         void setCursorIntern(BufferView *, Paragraph * par,
297                              Paragraph::size_type pos,
298                              bool setfont = true,
299                              bool boundary = false) const;
300         ///
301         void setCurrentFont(BufferView *) const;
302
303         ///
304         bool isBoundary(Buffer const *, Paragraph * par,
305                         Paragraph::size_type pos) const;
306         ///
307         bool isBoundary(Buffer const *, Paragraph * par,
308                          Paragraph::size_type pos,
309                          LyXFont const & font) const;
310
311         ///
312         void setCursorFromCoordinates(BufferView *, int x, int y) const;
313         ///
314         void setCursorFromCoordinates(BufferView *, LyXCursor &,
315                                       int x, int y) const;
316         ///
317         void cursorUp(BufferView *) const;
318         ///
319         void cursorDown(BufferView *) const;
320         ///
321         void cursorLeft(BufferView *, bool internal = true) const;
322         ///
323         void cursorRight(BufferView *, bool internal = true) const;
324         ///
325         void cursorLeftOneWord(BufferView *) const;
326         ///
327         void cursorLeftOneWord(LyXCursor &) const;
328         ///
329         void cursorRightOneWord(BufferView *) const;
330         ///
331         void cursorUpParagraph(BufferView *) const;
332         ///
333         void cursorDownParagraph(BufferView *) const;
334         ///
335         void cursorHome(BufferView *) const;
336         ///
337         void cursorEnd(BufferView *) const;
338         ///
339         void cursorTab(BufferView *) const;
340         ///
341         void cursorTop(BufferView *) const;
342         ///
343         void cursorBottom(BufferView *) const;
344         ///
345         void Delete(BufferView *);
346         ///
347         void backspace(BufferView *);
348         ///
349         void deleteWordForward(BufferView *);
350         ///
351         void deleteWordBackward(BufferView *);
352         ///
353         void deleteLineForward(BufferView *);
354         ///
355         bool selectWordWhenUnderCursor(BufferView *, 
356                                        word_location const = WHOLE_WORD);
357         ///
358         enum TextCase {
359                 ///
360                 text_lowercase = 0,
361                 ///
362                 text_capitalization = 1,
363                 ///
364                 text_uppercase = 2
365         };
366         /// Change the case of the word at cursor position.
367         void changeCase(BufferView *, TextCase action);
368         ///
369         void changeRegionCase(BufferView * bview,
370                                        LyXCursor const & from,
371                                        LyXCursor const & to,
372                                        LyXText::TextCase action);
373         ///
374         void transposeChars(BufferView &);
375         
376         /** returns a printed row in a pixmap. The y value is needed to
377           decide, wether it is selected text or not. This is a strange
378           solution but faster.
379          */
380         void getVisibleRow(BufferView *, int y_offset, int x_offset,
381                            Row * row_ptr, int y, bool cleared=false);
382
383         /// 
384         void toggleInset(BufferView *);
385         ///
386         void cutSelection(BufferView *, bool = true);
387         ///
388         void copySelection(BufferView *);
389         ///
390         void pasteSelection(BufferView *);
391         ///
392         void copyEnvironmentType();
393         ///
394         void pasteEnvironmentType(BufferView *);
395         ///
396         void insertFootnote();
397         ///
398         void insertMarginpar();
399         ///
400         void insertFigure();
401         ///
402         void insertTabular();
403
404         /** the DTP switches for paragraphs. LyX will store the top settings
405          always in the first physical paragraph, the bottom settings in the
406          last. When a paragraph is broken, the top settings rest, the bottom 
407          settings are given to the new one. So I can make shure, they do not
408          duplicate themself (and you cannnot make dirty things with them! )
409          */ 
410         void setParagraph(BufferView *,
411                           bool line_top, bool line_bottom,
412                           bool pagebreak_top, bool pagebreak_bottom,
413                           VSpace const & space_top,
414                           VSpace const & space_bottom,
415                           LyXAlignment align, 
416                           string labelwidthstring,
417                           bool noindent);
418
419         /* these things are for search and replace */
420
421         /** sets the selection over the number of characters of string,
422           no check!!
423           */
424         void setSelectionOverString(BufferView *, string const & str);
425
426         /** simple replacing. The font of the first selected character
427           is used
428           */
429         void replaceSelectionWithString(BufferView *, string const & str);
430
431         /// needed to insert the selection
432         void insertStringAsLines(BufferView *, string const & str);
433         /// needed to insert the selection
434         void insertStringAsParagraphs(BufferView *, string const & str);
435
436         /// Find next inset of some specified type.
437         bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
438                            string const & contents = string()) const;
439         ///
440
441         /* for the greater insets */
442   
443         /// returns false if inset wasn't found
444         bool updateInset(BufferView *, Inset *);
445         ///
446         void checkParagraph(BufferView *, Paragraph * par,
447                             Paragraph::size_type pos);
448         ///
449         int numberOfCell(Paragraph * par,
450                          Paragraph::size_type pos) const;
451         ///
452         void removeTableRow(LyXCursor & cursor) const;
453         ///
454         bool isEmptyTableCell() const;
455         ///
456         void toggleAppendix(BufferView *);
457         ///
458         int workWidth(BufferView *) const;
459         ///
460         void computeBidiTables(Buffer const *, Row * row) const;
461
462         /// Maps positions in the visual string to positions in logical string.
463         inline
464         Paragraph::size_type log2vis(Paragraph::size_type pos) const {
465                 if (bidi_start == -1)
466                         return pos;
467                 else
468                         return log2vis_list[pos-bidi_start];
469         }
470
471         /// Maps positions in the logical string to positions in visual string.
472         inline
473         Paragraph::size_type vis2log(Paragraph::size_type pos) const {
474                 if (bidi_start == -1)
475                         return pos;
476                 else
477                         return vis2log_list[pos-bidi_start];
478         }
479         ///
480         inline
481         Paragraph::size_type bidi_level(Paragraph::size_type pos) const {
482                 if (bidi_start == -1)
483                         return 0;
484                 else
485                         return bidi_levels[pos-bidi_start];
486         }       
487         ///
488         inline
489         bool bidi_InRange(Paragraph::size_type pos) const {
490                 return bidi_start == -1 ||
491                         (bidi_start <= pos && pos <= bidi_end);
492         }
493 private:
494         ///
495         mutable Row * firstrow;
496         ///
497         mutable Row * lastrow;
498
499         /** Copybuffer for copy environment type.
500           Asger has learned that this should be a buffer-property instead
501           Lgb has learned that 'char' is a lousy type for non-characters
502           */
503         LyXTextClass::size_type copylayouttype;
504
505         /** inserts a new row behind the specified row, increments
506             the touched counters */
507         void insertRow(Row * row, Paragraph * par,
508                        Paragraph::size_type pos) const;
509         /** removes the row and reset the touched counters */
510         void removeRow(Row * row) const;
511
512         /** remove all following rows of the paragraph of the specified row. */
513         void removeParagraph(Row * row) const;
514
515         /** insert the specified paragraph behind the specified row */
516         void insertParagraph(BufferView *,
517                              Paragraph * par, Row * row) const;
518
519         /** appends  the implizit specified paragraph behind the specified row,
520          * start at the implizit given position */
521         void appendParagraph(BufferView *, Row * row) const;
522    
523         ///
524         void breakAgain(BufferView *, Row * row) const;
525         ///
526         void breakAgainOneRow(BufferView *, Row * row);
527         /// Calculate and set the height of the row
528         void setHeightOfRow(BufferView *, Row * row_ptr) const;
529
530         /** this calculates the specified parameters. needed when setting
531          * the cursor and when creating a visible row */ 
532         void prepareToPrint(BufferView *, Row * row, float & x,
533                             float & fill_separator, 
534                             float & fill_hfill,
535                             float & fill_label_hfill,
536                             bool bidi = true) const;
537
538         ///
539         void deleteEmptyParagraphMechanism(BufferView *,
540                                            LyXCursor const & old_cursor) const;
541
542 public:
543         /** Updates all counters starting BEHIND the row. Changed paragraphs
544          * with a dynamic left margin will be rebroken. */ 
545         void updateCounters(BufferView *, Row * row) const;
546 private:
547         ///
548         void setCounter(Buffer const *, Paragraph * par) const;
549    
550         /*
551          * some low level functions
552          */
553         
554         ///
555         int singleWidth(BufferView *, Paragraph * par,
556                         Paragraph::size_type pos) const;
557         ///
558         int singleWidth(BufferView *, Paragraph * par,
559                         Paragraph::size_type pos, char c) const;
560         ///
561         void draw(BufferView *, Row const * row,
562                   Paragraph::size_type & pos,
563                   int offset, float & x, bool cleared);
564
565         /// get the next breakpoint in a given paragraph
566         Paragraph::size_type nextBreakPoint(BufferView *, Row const * row,
567                                                int width) const;
568         /// returns the minimum space a row needs on the screen in pixel
569         int fill(BufferView *, Row * row, int workwidth) const;
570         
571         /** returns the minimum space a manual label needs on the
572           screen in pixel */ 
573         int labelFill(BufferView *, Row const * row) const;
574
575         ///
576         Paragraph::size_type
577         beginningOfMainBody(Buffer const *, Paragraph const * par) const;
578         
579         /** Returns the left beginning of the text.
580           This information cannot be taken from the layouts-objekt, because
581           in LaTeX the beginning of the text fits in some cases
582           (for example sections) exactly the label-width.
583           */
584         int leftMargin(BufferView *, Row const * row) const;
585         ///
586         int rightMargin(Buffer const *, Row const * row) const;
587         ///
588         int labelEnd (BufferView *, Row const * row) const;
589
590         /** returns the number of separators in the specified row.
591           The separator on the very last column doesnt count
592           */ 
593         int numberOfSeparators(Buffer const *, Row const * row) const;
594
595         /** returns the number of hfills in the specified row. The
596           LyX-Hfill is a LaTeX \hfill so that the hfills at the
597           beginning and at the end were ignored. This is {\em MUCH}
598           more usefull than not to ignore!
599           */
600         int numberOfHfills(Buffer const *, Row const * row) const;
601    
602         /// like NumberOfHfills, but only those in the manual label!
603         int numberOfLabelHfills(Buffer const *, Row const * row) const;
604         /** returns true, if a expansion is needed. Rules are given by 
605           LaTeX
606           */
607         bool hfillExpansion(Buffer const *, Row const * row_ptr,
608                             Paragraph::size_type pos) const;
609
610
611         ///
612         mutable std::vector<Paragraph::size_type> log2vis_list;
613
614         ///
615         mutable std::vector<Paragraph::size_type> vis2log_list;
616
617         ///
618         mutable std::vector<Paragraph::size_type> bidi_levels;
619
620         ///
621         mutable Paragraph::size_type bidi_start;
622
623         ///
624         mutable Paragraph::size_type bidi_end;
625
626         ///
627         mutable bool bidi_same_direction;
628
629         ///
630         unsigned char transformChar(unsigned char c, Paragraph * par,
631                                     Paragraph::size_type pos) const;
632
633         /** returns the paragraph position of the last character in the 
634           specified row
635           */
636         Paragraph::size_type rowLast(Row const * row) const;
637         ///
638         Paragraph::size_type rowLastPrintable(Row const * row) const;
639
640         ///
641         void charInserted();
642 public:
643         //
644         // special owner functions
645         ///
646         Paragraph * ownerParagraph() const;
647         //
648         Paragraph * ownerParagraph(Paragraph *) const;
649         // set it searching first for the right owner using the paragraph id
650         Paragraph * ownerParagraph(int id, Paragraph *) const;
651 };
652
653
654 /* returns a pointer to the row near the specified y-coordinate
655  * (relative to the whole text). y is set to the real beginning
656  * of this row */
657 inline
658 Row * LyXText::getRowNearY(int & y) const
659 {
660         // If possible we should optimize this method. (Lgb)
661         Row * tmprow = firstrow;
662         int tmpy = 0;
663         
664         while (tmprow->next() && tmpy + tmprow->height() <= y) {
665                 tmpy += tmprow->height();
666                 tmprow = tmprow->next();
667         }
668         
669         y = tmpy;   // return the real y
670         return tmprow;
671 }
672 #endif