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