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