]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
5d55c9ddff2513d63566f69e0a94bf517cc9691e
[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 "undo.h"
21 #include "lyxcursor.h"
22 #include "paragraph.h"
23 #include "layout.h"
24 #include "lyxrow.h"
25 #include "vspace.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,
42                 ///
43                 NEED_MORE_REFRESH,
44                 ///
45                 NEED_VERY_LITTLE_REFRESH,
46                 ///
47                 CHANGED_IN_DRAW
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 *);
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         /** wether the screen needs a refresh,
187            starting with refresh_y
188            */
189         mutable text_status status;
190         
191         /** returns a pointer to the row near the specified y-coordinate
192           (relative to the whole text). y is set to the real beginning
193           of this row
194           */ 
195         Row * getRowNearY(int & y) const;
196         
197         /** returns the column near the specified x-coordinate of the row 
198          x is set to the real beginning of this column
199          */ 
200         int getColumnNearX(BufferView *, Row * row,
201                            int & x, bool & boundary) const;
202         
203         /** returns a pointer to a specified row. y is set to the beginning
204          of the row
205          */
206         Row * getRow(Paragraph * par,
207                      Paragraph::size_type pos, int & y) const;
208
209         /** returns the height of a default row, needed  for scrollbar
210          */
211         int defaultHeight() const;
212    
213         /** The cursor.
214           Later this variable has to be removed. There should be now internal
215           cursor in a text (and thus not in a buffer). By keeping this it is
216           (I think) impossible to have several views with the same buffer, but
217           the cursor placed at different places.
218           [later]
219           Since the LyXText now has been moved from Buffer to BufferView
220           it should not be absolutely needed to move the cursor...
221           */
222         mutable LyXCursor cursor;
223
224         /** The structrue that keeps track of the selections set. */
225         struct Selection {
226                 bool set() const {
227                         return set_;
228                 }
229                 void set(bool s) {
230                         set_ = s;
231                 }
232                 bool mark() const {
233                         return mark_;
234                 }
235                 void mark(bool m) {
236                         mark_ = m;
237                 }
238                 LyXCursor cursor;
239                 LyXCursor start;
240                 LyXCursor end;
241         private:
242                 bool set_; // former selection
243                 bool mark_; // former mark_set
244                 
245         };
246         mutable Selection selection;
247
248         /// needed for the toggling
249         LyXCursor last_sel_cursor;
250         ///
251         LyXCursor toggle_cursor;
252         ///
253         LyXCursor toggle_end_cursor;
254    
255         /// need the selection cursor:
256         void setSelection(BufferView *);
257         ///
258         void clearSelection(BufferView *) const;
259         ///
260         string const selectionAsString(Buffer const *) const;
261         
262         /// select the word we need depending on word_location
263         void getWord(LyXCursor & from, LyXCursor & to, word_location) const;
264         /// just selects the word the cursor is in
265         void selectWord(BufferView *);
266
267         /** 'selects" the next word, where the cursor is not in 
268          and returns this word as string. THe cursor will be moved 
269          to the beginning of this word. 
270          With SelectSelectedWord can this be highlighted really
271          */ 
272         string const selectNextWord(BufferView *, float & value) const;
273         ///
274         void selectSelectedWord(BufferView *);
275         ///
276         void setCursor(BufferView *, Paragraph * par,
277                        Paragraph::size_type pos,
278                        bool setfont = true,
279                        bool boundary = false) const;
280         ///
281         void setCursor(BufferView *, LyXCursor &, Paragraph * par,
282                        Paragraph::size_type pos,
283                        bool boundary = false) const;
284         ///
285         void setCursorIntern(BufferView *, Paragraph * par,
286                              Paragraph::size_type pos,
287                              bool setfont = true,
288                              bool boundary = false) const;
289         ///
290         void setCurrentFont(BufferView *) const;
291
292         ///
293         bool isBoundary(Buffer const *, Paragraph * par,
294                         Paragraph::size_type pos) const;
295         ///
296         bool isBoundary(Buffer const *, Paragraph * par,
297                          Paragraph::size_type pos,
298                          LyXFont const & font) const;
299
300         ///
301         void setCursorFromCoordinates(BufferView *, int x, int y) const;
302         ///
303         void setCursorFromCoordinates(BufferView *, LyXCursor &,
304                                       int x, int y) const;
305         ///
306         void cursorUp(BufferView *) const;
307         ///
308         void cursorDown(BufferView *) const;
309         ///
310         void cursorLeft(BufferView *, bool internal = true) const;
311         ///
312         void cursorRight(BufferView *, bool internal = true) const;
313         ///
314         void cursorLeftOneWord(BufferView *) const;
315         ///
316         void cursorLeftOneWord(LyXCursor &) const;
317         ///
318         void cursorRightOneWord(BufferView *) const;
319         ///
320         void cursorUpParagraph(BufferView *) const;
321         ///
322         void cursorDownParagraph(BufferView *) const;
323         ///
324         void cursorHome(BufferView *) const;
325         ///
326         void cursorEnd(BufferView *) const;
327         ///
328         void cursorTab(BufferView *) const;
329         ///
330         void cursorTop(BufferView *) const;
331         ///
332         void cursorBottom(BufferView *) const;
333         ///
334         void Delete(BufferView *);
335         ///
336         void backspace(BufferView *);
337         ///
338         void deleteWordForward(BufferView *);
339         ///
340         void deleteWordBackward(BufferView *);
341         ///
342         void deleteLineForward(BufferView *);
343         ///
344         bool selectWordWhenUnderCursor(BufferView *);
345         ///
346         enum TextCase {
347                 ///
348                 text_lowercase = 0,
349                 ///
350                 text_capitalization = 1,
351                 ///
352                 text_uppercase = 2
353         };
354         /// Change the case of the word at cursor position.
355         void changeCase(BufferView *, TextCase action);
356         ///
357         void transposeChars(BufferView const &);
358         
359         /** returns a printed row in a pixmap. The y value is needed to
360           decide, wether it is selected text or not. This is a strange
361           solution but faster.
362          */
363         void getVisibleRow(BufferView *, int y_offset, int x_offset,
364                            Row * row_ptr, int y, bool cleared=false);
365
366         ///
367         void cutSelection(BufferView *, bool = true);
368         ///
369         void copySelection(BufferView *);
370         ///
371         void pasteSelection(BufferView *);
372         ///
373         void copyEnvironmentType();
374         ///
375         void pasteEnvironmentType(BufferView *);
376         ///
377         void insertFootnote();
378         ///
379         void insertMarginpar();
380         ///
381         void insertFigure();
382         ///
383         void insertTabular();
384
385         /** the DTP switches for paragraphs. LyX will store the top settings
386          always in the first physical paragraph, the bottom settings in the
387          last. When a paragraph is broken, the top settings rest, the bottom 
388          settings are given to the new one. So I can make shure, they do not
389          duplicate themself (and you cannnot make dirty things with them! )
390          */ 
391         void setParagraph(BufferView *,
392                           bool line_top, bool line_bottom,
393                           bool pagebreak_top, bool pagebreak_bottom,
394                           VSpace const & space_top,
395                           VSpace const & space_bottom,
396                           LyXAlignment align, 
397                           string labelwidthstring,
398                           bool noindent);
399
400         /* these things are for search and replace */
401
402         /** sets the selection over the number of characters of string,
403           no check!!
404           */
405         void setSelectionOverString(BufferView *, string const & str);
406
407         /** simple replacing. The font of the first selected character
408           is used
409           */
410         void replaceSelectionWithString(BufferView *, string const & str);
411
412         /// needed to insert the selection
413         void insertStringAsLines(BufferView *, string const & str);
414         /// needed to insert the selection
415         void insertStringAsParagraphs(BufferView *, string const & str);
416
417         /// Find next inset of some specified type.
418         bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
419                            string const & contents = string()) const;
420         ///
421
422         /* for the greater insets */
423   
424         /// returns false if inset wasn't found
425         bool updateInset(BufferView *, Inset *);
426         ///
427         void checkParagraph(BufferView *, Paragraph * par,
428                             Paragraph::size_type pos);
429         ///
430         int numberOfCell(Paragraph * par,
431                          Paragraph::size_type pos) const;
432         ///
433         Paragraph * getParFromID(int id);
434
435         // undo functions
436         /// returns false if no undo possible
437         bool textUndo(BufferView *);
438         /// returns false if no redo possible
439         bool textRedo(BufferView *);
440         /// used by TextUndo/TextRedo
441         bool textHandleUndo(BufferView *, Undo * undo);
442         /// makes sure the next operation will be stored
443         void finishUndo();
444         /// this is dangerous and for internal use only
445         void freezeUndo();
446         /// this is dangerous and for internal use only
447         void unFreezeUndo();
448         /// the flag used by FinishUndo();
449         mutable bool undo_finished;
450         /// a flag
451         bool undo_frozen;
452         ///
453         void setUndo(Buffer *, Undo::undo_kind kind,
454                      Paragraph const * before,
455                      Paragraph const * end) const;
456         ///
457         void setRedo(Buffer *, Undo::undo_kind kind,
458                      Paragraph const * before,
459                      Paragraph const * end);
460         ///
461         Undo * createUndo(Buffer *, Undo::undo_kind kind,
462                           Paragraph const * before,
463                           Paragraph const * end) const;
464         /// for external use in lyx_cb.C
465         void setCursorParUndo(Buffer *);
466         ///
467         void removeTableRow(LyXCursor & cursor) const;
468         ///
469         bool isEmptyTableCell() const;
470         ///
471         void toggleAppendix(BufferView *);
472         ///
473         int workWidth(BufferView *) const;
474         ///
475         void computeBidiTables(Buffer const *, Row * row) const;
476
477         /// Maps positions in the visual string to positions in logical string.
478         inline
479         Paragraph::size_type log2vis(Paragraph::size_type pos) const {
480                 if (bidi_start == -1)
481                         return pos;
482                 else
483                         return log2vis_list[pos-bidi_start];
484         }
485
486         /// Maps positions in the logical string to positions in visual string.
487         inline
488         Paragraph::size_type vis2log(Paragraph::size_type pos) const {
489                 if (bidi_start == -1)
490                         return pos;
491                 else
492                         return vis2log_list[pos-bidi_start];
493         }
494         ///
495         inline
496         Paragraph::size_type bidi_level(Paragraph::size_type pos) const {
497                 if (bidi_start == -1)
498                         return 0;
499                 else
500                         return bidi_levels[pos-bidi_start];
501         }       
502         ///
503         inline
504         bool bidi_InRange(Paragraph::size_type pos) const {
505                 return bidi_start == -1 ||
506                         (bidi_start <= pos && pos <= bidi_end);
507         }
508 private:
509         ///
510         void init();
511         ///
512         mutable Row * firstrow;
513         ///
514         mutable Row * lastrow;
515
516         /** Copybuffer for copy environment type.
517           Asger has learned that this should be a buffer-property instead
518           Lgb has learned that 'char' is a lousy type for non-characters
519           */
520         LyXTextClass::size_type copylayouttype;
521
522         /** inserts a new row behind the specified row, increments
523             the touched counters */
524         void insertRow(Row * row, Paragraph * par,
525                        Paragraph::size_type pos) const;
526         /** removes the row and reset the touched counters */
527         void removeRow(Row * row) const;
528
529         /** remove all following rows of the paragraph of the specified row. */
530         void removeParagraph(Row * row) const;
531
532         /** insert the specified paragraph behind the specified row */
533         void insertParagraph(BufferView *,
534                              Paragraph * par, Row * row) const;
535
536         /** appends  the implizit specified paragraph behind the specified row,
537          * start at the implizit given position */
538         void appendParagraph(BufferView *, Row * row) const;
539    
540         ///
541         void breakAgain(BufferView *, Row * row) const;
542         ///
543         void breakAgainOneRow(BufferView *, Row * row);
544         /// Calculate and set the height of the row
545         void setHeightOfRow(BufferView *, Row * row_ptr) const;
546
547         /** this calculates the specified parameters. needed when setting
548          * the cursor and when creating a visible row */ 
549         void prepareToPrint(BufferView *, Row * row, float & x,
550                             float & fill_separator, 
551                             float & fill_hfill,
552                             float & fill_label_hfill,
553                             bool bidi = true) const;
554
555         ///
556         void deleteEmptyParagraphMechanism(BufferView *,
557                                            LyXCursor const & old_cursor) const;
558
559         /** Updates all counters starting BEHIND the row. Changed paragraphs
560          * with a dynamic left margin will be rebroken. */ 
561         void updateCounters(BufferView *, Row * row) const;
562         ///
563         void setCounter(Buffer const *, Paragraph * par) const;
564    
565         /*
566          * some low level functions
567          */
568         
569         ///
570         int singleWidth(BufferView *, Paragraph * par,
571                         Paragraph::size_type pos) const;
572         ///
573         int singleWidth(BufferView *, Paragraph * par,
574                         Paragraph::size_type pos, char c) const;
575         ///
576         void draw(BufferView *, Row const * row,
577                   Paragraph::size_type & pos,
578                   int offset, float & x, bool cleared);
579
580         /// get the next breakpoint in a given paragraph
581         Paragraph::size_type nextBreakPoint(BufferView *, Row const * row,
582                                                int width) const;
583         /// returns the minimum space a row needs on the screen in pixel
584         int fill(BufferView *, Row * row, int workwidth) const;
585         
586         /** returns the minimum space a manual label needs on the
587           screen in pixel */ 
588         int labelFill(BufferView *, Row const * row) const;
589
590         ///
591         Paragraph::size_type
592         beginningOfMainBody(Buffer const *, Paragraph const * par) const;
593         
594         /** Returns the left beginning of the text.
595           This information cannot be taken from the layouts-objekt, because
596           in LaTeX the beginning of the text fits in some cases
597           (for example sections) exactly the label-width.
598           */
599         int leftMargin(BufferView *, Row const * row) const;
600         ///
601         int rightMargin(Buffer const *, Row const * row) const;
602         ///
603         int labelEnd (BufferView *, Row const * row) const;
604
605         /** returns the number of separators in the specified row.
606           The separator on the very last column doesnt count
607           */ 
608         int numberOfSeparators(Buffer const *, Row const * row) const;
609
610         /** returns the number of hfills in the specified row. The
611           LyX-Hfill is a LaTeX \hfill so that the hfills at the
612           beginning and at the end were ignored. This is {\em MUCH}
613           more usefull than not to ignore!
614           */
615         int numberOfHfills(Buffer const *, Row const * row) const;
616    
617         /// like NumberOfHfills, but only those in the manual label!
618         int numberOfLabelHfills(Buffer const *, Row const * row) const;
619         /** returns true, if a expansion is needed. Rules are given by 
620           LaTeX
621           */
622         bool hfillExpansion(Buffer const *, Row const * row_ptr,
623                             Paragraph::size_type pos) const;
624
625
626         ///
627         mutable std::vector<Paragraph::size_type> log2vis_list;
628
629         ///
630         mutable std::vector<Paragraph::size_type> vis2log_list;
631
632         ///
633         mutable std::vector<Paragraph::size_type> bidi_levels;
634
635         ///
636         mutable Paragraph::size_type bidi_start;
637
638         ///
639         mutable Paragraph::size_type bidi_end;
640
641         ///
642         mutable bool bidi_same_direction;
643
644         ///
645         unsigned char transformChar(unsigned char c, Paragraph * par,
646                                     Paragraph::size_type pos) const;
647
648         /** returns the paragraph position of the last character in the 
649           specified row
650           */
651         Paragraph::size_type rowLast(Row const * row) const;
652         ///
653         Paragraph::size_type rowLastPrintable(Row const * row) const;
654
655         ///
656         void charInserted();
657         //
658         // special owner functions
659         ///
660         Paragraph * ownerParagraph() const;
661         //
662         Paragraph * ownerParagraph(Paragraph *) const;
663 };
664
665
666 /* returns a pointer to the row near the specified y-coordinate
667  * (relative to the whole text). y is set to the real beginning
668  * of this row */
669 inline
670 Row * LyXText::getRowNearY(int & y) const
671 {
672         // If possible we should optimize this method. (Lgb)
673         Row * tmprow = firstrow;
674         int tmpy = 0;
675         
676         while (tmprow->next() && tmpy + tmprow->height() <= y) {
677                 tmpy += tmprow->height();
678                 tmprow = tmprow->next();
679         }
680         
681         y = tmpy;   // return the real y
682         return tmprow;
683 }
684 #endif