]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
another pesky \#warning snuck in
[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-2000 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 "lyxparagraph.h"
23 #include "layout.h"
24 #include "lyxrow.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,
41                 ///
42                 NEED_MORE_REFRESH,
43                 ///
44                 NEED_VERY_LITTLE_REFRESH,
45                 ///
46                 CHANGED_IN_DRAW
47         };
48
49         /// Constructor
50         LyXText(BufferView *);
51         ///
52         LyXText(InsetText *);
53    
54         /// Destructor
55         ~LyXText();
56
57         void init(BufferView *);
58         ///
59         mutable int number_of_rows;
60         ///
61         mutable int height;
62         ///
63         mutable unsigned int width;
64         /// the current font settings
65         mutable LyXFont current_font;
66         /// the current font
67         mutable LyXFont real_current_font;
68         /// first visible pixel-row is set from LyXScreen!!!
69         // unsigned is wrong here for text-insets!
70         int first;
71         ///
72         BufferView * bv_owner;
73         ///
74         InsetText * inset_owner;
75         ///
76         UpdatableInset * the_locking_inset;
77
78         ///
79         int GetRealCursorX(BufferView *) const;
80         ///
81         LyXFont const GetFont(Buffer const *, LyXParagraph * par,
82                         LyXParagraph::size_type pos) const;
83         ///
84         void SetCharFont(Buffer const *, LyXParagraph * par,
85                          LyXParagraph::size_type pos,
86                          LyXFont const & font);
87         /// returns a pointer to the very first LyXParagraph
88         LyXParagraph * FirstParagraph() const;
89   
90         /// what you expect when pressing <enter> at cursor position
91         void BreakParagraph(BufferView *, char keep_layout = 0);
92
93         /** set layout over selection and make a total rebreak of
94           those paragraphs
95           */
96         LyXParagraph * SetLayout(BufferView *, LyXCursor & actual_cursor,
97                                  LyXCursor & selection_start,
98                                  LyXCursor & selection_end,
99                                  LyXTextClass::size_type layout);
100         void SetLayout(BufferView *, LyXTextClass::size_type layout);
101         
102         /// used in setlayout
103         void MakeFontEntriesLayoutSpecific(Buffer const *, LyXParagraph * par);
104         
105         /** increment depth over selection and make a total rebreak of those 
106           paragraphs
107           */
108         void IncDepth(BufferView *);
109         
110         /** decrement depth over selection and make a total rebreak of those  
111           paragraphs */
112         void DecDepth(BufferView *);
113
114         /** Get the depth at current cursor position
115          */
116         int GetDepth() const { return cursor.par()->GetDepth(); }
117         
118         /** set font over selection and make a total rebreak of those
119           paragraphs.
120           toggleall defaults to false.
121           */
122         void SetFont(BufferView *, LyXFont const &, bool toggleall = false);
123         
124         /** deletes and inserts again all paragaphs between the cursor
125           and the specified par. The Cursor is needed to set the refreshing
126           parameters. 
127           This function is needed after SetLayout and SetFont etc.
128           */
129         void RedoParagraphs(BufferView *, LyXCursor const & cursor,
130                             LyXParagraph const * end_par) const;
131         ///
132         void RedoParagraph(BufferView *) const;
133         
134         ///
135         void ToggleFree(BufferView *, LyXFont const &, bool toggleall = false);
136         
137         /** recalculates the heights of all previous rows of the
138             specified paragraph.  needed, if the last characters font
139             has changed.  
140             */
141         void RedoHeightOfParagraph(BufferView *, LyXCursor const & cursor);
142         
143         /** forces the redrawing of a paragraph. Needed when manipulating a 
144             right address box
145             */ 
146         void RedoDrawingOfParagraph(BufferView *, LyXCursor const & cursor);
147         
148         /** insert a character, moves all the following breaks in the 
149           same Paragraph one to the right and make a little rebreak
150           */
151         void InsertChar(BufferView *, char c);
152         ///
153         void InsertInset(BufferView *, Inset * inset);
154    
155         /** Completes the insertion with a full rebreak.
156             Returns true if something was broken. */
157         bool FullRebreak(BufferView *);
158
159 #ifndef NEW_INSETS
160         ///
161         LyXParagraph::footnote_flag GetFootnoteFlag(int row);
162 #endif
163         ///
164         Row * need_break_row;
165         ///
166         mutable int refresh_y;
167         ///
168         int refresh_height;
169         ///
170         int refresh_width;
171         ///
172         int refresh_x;
173         ///
174         mutable Row * refresh_row;
175         ///
176         int refresh_pos;
177         
178         /** wether the screen needs a refresh,
179            starting with refresh_y
180            */
181         mutable text_status status;
182         
183         /** returns a pointer to the row near the specified y-coordinate
184           (relative to the whole text). y is set to the real beginning
185           of this row
186           */ 
187         Row * GetRowNearY(int & y) const;
188         
189         /** returns the column near the specified x-coordinate of the row 
190          x is set to the real beginning of this column
191          */ 
192         int GetColumnNearX(BufferView *, Row * row,
193                            int & x, bool & boundary) const;
194         
195         /** returns a pointer to a specified row. y is set to the beginning
196          of the row
197          */
198         Row * GetRow(LyXParagraph * par,
199                      LyXParagraph::size_type pos, int & y) const;
200
201         /** returns the height of a default row, needed  for scrollbar
202          */
203         int DefaultHeight() const;
204    
205         /** The cursor.
206           Later this variable has to be removed. There should be now internal
207           cursor in a text (and thus not in a buffer). By keeping this it is
208           (I think) impossible to have several views with the same buffer, but
209           the cursor placed at different places.
210           [later]
211           Since the LyXText now has been moved from Buffer to BufferView
212           it should not be absolutely needed to move the cursor...
213           */
214         mutable LyXCursor cursor;
215    
216         /* the selection cursor */
217         /// 
218         mutable bool selection;
219         ///
220         mutable bool mark_set;
221
222         ///
223         mutable LyXCursor sel_cursor;
224         ///
225         LyXCursor sel_start_cursor;
226         ///
227         mutable LyXCursor sel_end_cursor;
228         /// needed for the toggling
229         LyXCursor last_sel_cursor;
230         ///
231         LyXCursor toggle_cursor;
232         ///
233         LyXCursor toggle_end_cursor;
234    
235         /// need the selection cursor:
236         void SetSelection(BufferView *);
237         ///
238         void ClearSelection(BufferView *) const;
239         ///
240         string const selectionAsString(Buffer const *) const;
241         
242         /// just selects the word the cursor is in
243         void SelectWord(BufferView *);
244
245         /** 'selects" the next word, where the cursor is not in 
246          and returns this word as string. THe cursor will be moved 
247          to the beginning of this word. 
248          With SelectSelectedWord can this be highlighted really
249          */ 
250         string const SelectNextWord(BufferView *, float & value) const;
251         ///
252         void SelectSelectedWord(BufferView *);
253         ///
254         void SetCursor(BufferView *, LyXParagraph * par,
255                        LyXParagraph::size_type pos,
256                        bool setfont = true,
257                        bool boundary = false) const;
258         ///
259         void SetCursor(BufferView *, LyXCursor &, LyXParagraph * par,
260                        LyXParagraph::size_type pos,
261                        bool boundary = false) const;
262         ///
263         void SetCursorIntern(BufferView *, LyXParagraph * par,
264                              LyXParagraph::size_type pos,
265                              bool setfont = true,
266                              bool boundary = false) const;
267         ///
268         void SetCurrentFont(BufferView *) const;
269
270         ///
271         bool IsBoundary(Buffer const *, LyXParagraph * par,
272                         LyXParagraph::size_type pos) const;
273         ///
274         bool IsBoundary(Buffer const *, LyXParagraph * par,
275                          LyXParagraph::size_type pos,
276                          LyXFont const & font) const;
277
278         ///
279         void SetCursorFromCoordinates(BufferView *, int x, int y) const;
280         ///
281         void SetCursorFromCoordinates(BufferView *, LyXCursor &,
282                                       int x, int y) const;
283         ///
284         void CursorUp(BufferView *) const;
285         ///
286         void CursorDown(BufferView *) const;
287         ///
288         void CursorLeft(BufferView *, bool internal = true) const;
289         ///
290         void CursorRight(BufferView *, bool internal = true) const;
291         ///
292         void CursorLeftOneWord(BufferView *) const;
293         ///
294         void CursorRightOneWord(BufferView *) const;
295         ///
296         void CursorUpParagraph(BufferView *) const;
297         ///
298         void CursorDownParagraph(BufferView *) const;
299         ///
300         void CursorHome(BufferView *) const;
301         ///
302         void CursorEnd(BufferView *) const;
303         ///
304         void CursorTab(BufferView *) const;
305         ///
306         void CursorTop(BufferView *) const;
307         ///
308         void CursorBottom(BufferView *) const;
309         ///
310         void Delete(BufferView *);
311         ///
312         void Backspace(BufferView *);
313         ///
314         void DeleteWordForward(BufferView *);
315         ///
316         void DeleteWordBackward(BufferView *);
317         ///
318         void DeleteLineForward(BufferView *);
319         ///
320         bool SelectWordWhenUnderCursor(BufferView *);
321         ///
322         enum TextCase {
323                 ///
324                 text_lowercase = 0,
325                 ///
326                 text_capitalization = 1,
327                 ///
328                 text_uppercase = 2
329         };
330         /// Change the case of the word at cursor position.
331         void ChangeWordCase(BufferView *, TextCase action);
332
333         /** returns a printed row in a pixmap. The y value is needed to
334           decide, wether it is selected text or not. This is a strange
335           solution but faster.
336          */
337         void GetVisibleRow(BufferView *, int y_offset, int x_offset,
338                            Row * row_ptr, int y, bool cleared=false);
339
340 #ifndef NEW_INSETS
341         /* footnotes: */
342         ///
343         void ToggleFootnote(BufferView *);
344         ///
345         void OpenStuff(BufferView *);
346         ///
347         void OpenFootnotes();
348         ///
349         void OpenFootnote(BufferView *);
350         ///
351         void CloseFootnotes();
352         ///
353         void CloseFootnote(BufferView *);
354
355         /** turn the selection into a new environment. If there is no
356           selection, create an empty environment
357          */ 
358         void InsertFootnoteEnvironment(BufferView *,
359                                        LyXParagraph::footnote_kind kind);
360         ///
361         void MeltFootnoteEnvironment(BufferView *);
362 #endif
363         ///
364         void CutSelection(BufferView *, bool = true);
365         ///
366         void CopySelection(BufferView *);
367         ///
368         void PasteSelection(BufferView *);
369         ///
370         void copyEnvironmentType();
371         ///
372         void pasteEnvironmentType(BufferView *);
373         ///
374         void InsertFootnote();
375         ///
376         void InsertMarginpar();
377         ///
378         void InsertFigure();
379         ///
380         void InsertTabular();
381
382         /** the DTP switches for paragraphs. LyX will store the top settings
383          always in the first physical paragraph, the bottom settings in the
384          last. When a paragraph is broken, the top settings rest, the bottom 
385          settings are given to the new one. So I can make shure, they do not
386          duplicate themself (and you cannnot make dirty things with them! )
387          */ 
388         void SetParagraph(BufferView *,
389                           bool line_top, bool line_bottom,
390                           bool pagebreak_top, bool pagebreak_bottom,
391                           VSpace const & space_top,
392                           VSpace const & space_bottom,
393                           LyXAlignment align, 
394                           string labelwidthstring,
395                           bool noindent);
396 #ifndef NO_PEXTRA
397         ///
398         void SetParagraphExtraOpt(BufferView *, int type,
399                                   string const & width,
400                                   string const & widthp,
401                                   int alignment, bool hfill,
402                                   bool start_minipage);
403 #endif
404         /* these things are for search and replace */
405
406         /** sets the selection over the number of characters of string,
407           no check!!
408           */
409         void SetSelectionOverString(BufferView *, string const & str);
410
411         /** simple replacing. The font of the first selected character
412           is used
413           */
414         void ReplaceSelectionWithString(BufferView *, string const & str);
415
416         /// needed to insert the selection
417         void InsertStringA(BufferView *, string const & str);
418         /// needed to insert the selection
419         void InsertStringB(BufferView *, string const & str);
420
421         /// Find next inset of some specified type.
422         bool GotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
423                            string const & contents = string()) const;
424         ///
425
426         /* for the greater insets */
427   
428         /// returns false if inset wasn't found
429         bool UpdateInset(BufferView *, Inset *);
430         ///
431         void CheckParagraph(BufferView *, LyXParagraph * par,
432                             LyXParagraph::size_type pos);
433         ///
434         int NumberOfCell(LyXParagraph * par,
435                          LyXParagraph::size_type pos) const;
436         ///
437         LyXParagraph * GetParFromID(int id);
438
439         // undo functions
440         /// returns false if no undo possible
441         bool TextUndo(BufferView *);
442         /// returns false if no redo possible
443         bool TextRedo(BufferView *);
444         /// used by TextUndo/TextRedo
445         bool TextHandleUndo(BufferView *, Undo * undo);
446         /// makes sure the next operation will be stored
447         void FinishUndo();
448         /// this is dangerous and for internal use only
449         void FreezeUndo();
450         /// this is dangerous and for internal use only
451         void UnFreezeUndo();
452         /// the flag used by FinishUndo();
453         mutable bool undo_finished;
454         /// a flag
455         bool undo_frozen;
456         ///
457         void SetUndo(Buffer *, Undo::undo_kind kind,
458                      LyXParagraph const * before,
459                      LyXParagraph const * end) const;
460         ///
461         void SetRedo(Buffer *, Undo::undo_kind kind,
462                      LyXParagraph const * before,
463                      LyXParagraph const * end);
464         ///
465         Undo * CreateUndo(Buffer *, Undo::undo_kind kind,
466                           LyXParagraph const * before,
467                           LyXParagraph const * end) const;
468         /// for external use in lyx_cb.C
469         void SetCursorParUndo(Buffer *);
470         ///
471         void RemoveTableRow(LyXCursor & cursor) const;
472         ///
473         bool IsEmptyTableCell() const;
474         ///
475         void toggleAppendix(BufferView *);
476         ///
477         int workWidth(BufferView *) const;
478         ///
479         void ComputeBidiTables(Buffer const *, Row * row) const;
480
481         /// Maps positions in the visual string to positions in logical string.
482         inline
483         LyXParagraph::size_type log2vis(LyXParagraph::size_type pos) const {
484                 if (bidi_start == -1)
485                         return pos;
486                 else
487                         return log2vis_list[pos-bidi_start];
488         }
489
490         /// Maps positions in the logical string to positions in visual string.
491         inline
492         LyXParagraph::size_type vis2log(LyXParagraph::size_type pos) const {
493                 if (bidi_start == -1)
494                         return pos;
495                 else
496                         return vis2log_list[pos-bidi_start];
497         }
498         ///
499         inline
500         LyXParagraph::size_type bidi_level(LyXParagraph::size_type pos) const {
501                 if (bidi_start == -1)
502                         return 0;
503                 else
504                         return bidi_levels[pos-bidi_start];
505         }       
506         ///
507         inline
508         bool bidi_InRange(LyXParagraph::size_type pos) const {
509                 return bidi_start == -1 ||
510                         (bidi_start <= pos && pos <= bidi_end);
511         }
512 private:
513         ///
514         void init();
515         ///
516         mutable Row * firstrow;
517         ///
518         mutable Row * lastrow;
519
520         /** Copybuffer for copy environment type.
521           Asger has learned that this should be a buffer-property instead
522           Lgb has learned that 'char' is a lousy type for non-characters
523           */
524         LyXTextClass::size_type copylayouttype;
525
526         /** inserts a new row behind the specified row, increments
527             the touched counters */
528         void InsertRow(Row * row, LyXParagraph * par,
529                        LyXParagraph::size_type pos) const;
530         /** removes the row and reset the touched counters */
531         void RemoveRow(Row * row) const;
532
533         /** remove all following rows of the paragraph of the specified row. */
534         void RemoveParagraph(Row * row) const;
535
536         /** insert the specified paragraph behind the specified row */
537         void InsertParagraph(BufferView *,
538                              LyXParagraph * par, Row * row) const;
539
540         /** appends  the implizit specified paragraph behind the specified row,
541          * start at the implizit given position */
542         void AppendParagraph(BufferView *, Row * row) const;
543    
544         ///
545         void BreakAgain(BufferView *, Row * row) const;
546         ///
547         void BreakAgainOneRow(BufferView *, Row * row);
548         /// Calculate and set the height of the row
549         void SetHeightOfRow(BufferView *, Row * row_ptr) const;
550
551         /** this calculates the specified parameters. needed when setting
552          * the cursor and when creating a visible row */ 
553         void PrepareToPrint(BufferView *, Row * row, float & x,
554                             float & fill_separator, 
555                             float & fill_hfill,
556                             float & fill_label_hfill,
557                             bool bidi = true) const;
558
559         ///
560         void DeleteEmptyParagraphMechanism(BufferView *,
561                                            LyXCursor const & old_cursor) const;
562
563         /** Updates all counters starting BEHIND the row. Changed paragraphs
564          * with a dynamic left margin will be rebroken. */ 
565         void UpdateCounters(BufferView *, Row * row) const;
566         ///
567         void SetCounter(Buffer const *, LyXParagraph * par) const;
568    
569         /*
570          * some low level functions
571          */
572         
573         ///
574         int SingleWidth(BufferView *, LyXParagraph * par,
575                         LyXParagraph::size_type pos) const;
576         ///
577         int SingleWidth(BufferView *, LyXParagraph * par,
578                         LyXParagraph::size_type pos, char c) const;
579         ///
580         void draw(BufferView *, Row const * row,
581                   LyXParagraph::size_type & pos,
582                   int offset, float & x, bool cleared);
583
584         /// get the next breakpoint in a given paragraph
585         LyXParagraph::size_type NextBreakPoint(BufferView *, Row const * row,
586                                                int width) const;
587         /// returns the minimum space a row needs on the screen in pixel
588         int Fill(BufferView *, Row * row, int workwidth) const;
589         
590         /** returns the minimum space a manual label needs on the
591           screen in pixel */ 
592         int LabelFill(BufferView *, Row const * row) const;
593
594         ///
595         LyXParagraph::size_type
596         BeginningOfMainBody(Buffer const *, LyXParagraph const * par) const;
597         
598         /** Returns the left beginning of the text.
599           This information cannot be taken from the layouts-objekt, because
600           in LaTeX the beginning of the text fits in some cases
601           (for example sections) exactly the label-width.
602           */
603         int LeftMargin(BufferView *, Row const * row) const;
604         ///
605         int RightMargin(Buffer const *, Row const * row) const;
606         ///
607         int LabelEnd (BufferView *, Row const * row) const;
608
609         /** returns the number of separators in the specified row.
610           The separator on the very last column doesnt count
611           */ 
612         int NumberOfSeparators(Buffer const *, Row const * row) const;
613
614         /** returns the number of hfills in the specified row. The
615           LyX-Hfill is a LaTeX \hfill so that the hfills at the
616           beginning and at the end were ignored. This is {\em MUCH}
617           more usefull than not to ignore!
618           */
619         int NumberOfHfills(Buffer const *, Row const * row) const;
620    
621         /// like NumberOfHfills, but only those in the manual label!
622         int NumberOfLabelHfills(Buffer const *, Row const * row) const;
623         /** returns true, if a expansion is needed. Rules are given by 
624           LaTeX
625           */
626         bool HfillExpansion(Buffer const *, Row const * row_ptr,
627                             LyXParagraph::size_type pos) const;
628
629
630         ///
631         mutable std::vector<LyXParagraph::size_type> log2vis_list;
632
633         ///
634         mutable std::vector<LyXParagraph::size_type> vis2log_list;
635
636         ///
637         mutable std::vector<LyXParagraph::size_type> bidi_levels;
638
639         ///
640         mutable LyXParagraph::size_type bidi_start;
641
642         ///
643         mutable LyXParagraph::size_type bidi_end;
644
645         ///
646         mutable bool bidi_same_direction;
647
648         ///
649         unsigned char TransformChar(unsigned char c, LyXParagraph * par,
650                                 LyXParagraph::size_type pos) const;
651
652         /** returns the paragraph position of the last character in the 
653           specified row
654           */
655         LyXParagraph::size_type RowLast(Row const * row) const;
656         ///
657         LyXParagraph::size_type RowLastPrintable(Row const * row) const;
658
659         ///
660         void charInserted();
661         //
662         // special owner functions
663         ///
664         LyXParagraph * OwnerParagraph() const;
665         //
666         LyXParagraph * OwnerParagraph(LyXParagraph *) const;
667 };
668
669
670 /* returns a pointer to the row near the specified y-coordinate
671  * (relative to the whole text). y is set to the real beginning
672  * of this row */
673 inline
674 Row * LyXText::GetRowNearY(int & y) const
675 {
676         // If possible we should optimize this method. (Lgb)
677         Row * tmprow = firstrow;
678         int tmpy = 0;
679         
680         while (tmprow->next() && tmpy + tmprow->height() <= y) {
681                 tmpy += tmprow->height();
682                 tmprow = tmprow->next();
683         }
684         
685         y = tmpy;   // return the real y
686         return tmprow;
687 }
688 #endif