]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
Assume unknown formats are EPS, hacky solution before implementing a real one.
[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 #include "LColor.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 = 0,
42                 ///
43                 CHANGED_IN_DRAW = 1,
44                 ///
45                 NEED_VERY_LITTLE_REFRESH = 2,
46                 ///
47                 NEED_MORE_REFRESH = 3
48         };
49         ///
50         enum word_location {
51                 // the word around the cursor, only if the cursor is
52                 //not at a boundary
53                 WHOLE_WORD_STRICT,
54                 // the word around the cursor
55                 WHOLE_WORD,
56                 /// the word begining from the cursor position
57                 PARTIAL_WORD,
58                 /// the word around the cursor or before the cursor
59                 PREVIOUS_WORD,
60                 /// the next word (not yet used)
61                 NEXT_WORD
62         };
63
64         /// Constructor
65         LyXText(BufferView *);
66         ///
67         LyXText(InsetText *);
68    
69         /// Destructor
70         ~LyXText();
71
72         void init(BufferView *, bool reinit = false);
73         ///
74         mutable int number_of_rows;
75         ///
76         mutable int height;
77         ///
78         mutable unsigned int width;
79         /// the current font settings
80         mutable LyXFont current_font;
81         /// the current font
82         mutable LyXFont real_current_font;
83         /// first visible pixel-row is set from LyXScreen!!!
84         // unsigned is wrong here for text-insets!
85         int first;
86         ///
87         BufferView * bv_owner;
88         ///
89         InsetText * inset_owner;
90         ///
91         UpdatableInset * the_locking_inset;
92
93         ///
94         int getRealCursorX(BufferView *) const;
95         ///
96         LyXFont const getFont(Buffer const *, Paragraph * par,
97                         Paragraph::size_type pos) const;
98         ///
99         void setCharFont(Buffer const *, Paragraph * par,
100                          Paragraph::size_type pos, LyXFont const & font);
101         void setCharFont(BufferView *, Paragraph * par,
102                          Paragraph::size_type pos,
103                          LyXFont const & font, bool toggleall);
104         /// returns a pointer to the very first Paragraph
105         Paragraph * firstParagraph() const;
106   
107         /// what you expect when pressing <enter> at cursor position
108         void breakParagraph(BufferView *, char keep_layout = 0);
109
110         /** set layout over selection and make a total rebreak of
111           those paragraphs
112           */
113         Paragraph * setLayout(BufferView *, LyXCursor & actual_cursor,
114                                  LyXCursor & selection_start,
115                                  LyXCursor & selection_end,
116                                  LyXTextClass::size_type layout);
117         void setLayout(BufferView *, LyXTextClass::size_type layout);
118         
119         /// used in setlayout
120         void makeFontEntriesLayoutSpecific(Buffer const *, Paragraph * par);
121         
122         /** increment depth over selection and make a total rebreak of those 
123           paragraphs
124           */
125         void incDepth(BufferView *);
126         
127         /** decrement depth over selection and make a total rebreak of those  
128           paragraphs */
129         void decDepth(BufferView *);
130
131         /** Get the depth at current cursor position
132          */
133         int getDepth() const { return cursor.par()->getDepth(); }
134         
135         /** set font over selection and make a total rebreak of those
136           paragraphs.
137           toggleall defaults to false.
138           */
139         void setFont(BufferView *, LyXFont const &, bool toggleall = false);
140         
141         /** deletes and inserts again all paragaphs between the cursor
142           and the specified par. The Cursor is needed to set the refreshing
143           parameters. 
144           This function is needed after SetLayout and SetFont etc.
145           */
146         void redoParagraphs(BufferView *, LyXCursor const & cursor,
147                             Paragraph const * end_par) const;
148         ///
149         void redoParagraph(BufferView *) const;
150         
151         ///
152         void toggleFree(BufferView *, LyXFont const &, bool toggleall = false);
153         
154         /** recalculates the heights of all previous rows of the
155             specified paragraph.  needed, if the last characters font
156             has changed.  
157             */
158         void redoHeightOfParagraph(BufferView *, LyXCursor const & cursor);
159         
160         /** forces the redrawing of a paragraph. Needed when manipulating a 
161             right address box
162             */ 
163         void redoDrawingOfParagraph(BufferView *, LyXCursor const & cursor);
164         
165         /** insert a character, moves all the following breaks in the 
166           same Paragraph one to the right and make a little rebreak
167           */
168         void insertChar(BufferView *, char c);
169         ///
170         void insertInset(BufferView *, Inset * inset);
171    
172         /** Completes the insertion with a full rebreak.
173             Returns true if something was broken. */
174         bool fullRebreak(BufferView *);
175
176         ///
177         Row * need_break_row;
178         ///
179         mutable int refresh_y;
180         ///
181         int refresh_height;
182         ///
183         int refresh_width;
184         ///
185         int refresh_x;
186         ///
187         mutable Row * refresh_row;
188         ///
189         int refresh_pos;
190
191         /// give and set the LyXText status
192         text_status status() const;
193         void status(BufferView *, text_status) const;
194
195 private:        
196         /** wether the screen needs a refresh,
197            starting with refresh_y
198            */
199         mutable text_status status_;
200         
201 public:
202         /** returns a pointer to the row near the specified y-coordinate
203           (relative to the whole text). y is set to the real beginning
204           of this row
205           */ 
206         Row * getRowNearY(int & y) const;
207         
208         /** returns the column near the specified x-coordinate of the row 
209          x is set to the real beginning of this column
210          */ 
211         int getColumnNearX(BufferView *, Row * row,
212                            int & x, bool & boundary) const;
213         
214         /** returns a pointer to a specified row. y is set to the beginning
215          of the row
216          */
217         Row * getRow(Paragraph * par,
218                      Paragraph::size_type pos, int & y) const;
219
220         /** returns the height of a default row, needed  for scrollbar
221          */
222         int defaultHeight() const;
223    
224         /** The cursor.
225           Later this variable has to be removed. There should be now internal
226           cursor in a text (and thus not in a buffer). By keeping this it is
227           (I think) impossible to have several views with the same buffer, but
228           the cursor placed at different places.
229           [later]
230           Since the LyXText now has been moved from Buffer to BufferView
231           it should not be absolutely needed to move the cursor...
232           */
233         mutable LyXCursor cursor;
234
235         /** The structrue that keeps track of the selections set. */
236         struct Selection {
237                 Selection() 
238                         : set_(false), mark_(false)
239                         {}
240                 bool set() const {
241                         return set_;
242                 }
243                 void set(bool s) {
244                         set_ = s;
245                 }
246                 bool mark() const {
247                         return mark_;
248                 }
249                 void mark(bool m) {
250                         mark_ = m;
251                 }
252                 LyXCursor cursor;
253                 LyXCursor start;
254                 LyXCursor end;
255         private:
256                 bool set_; // former selection
257                 bool mark_; // former mark_set
258                 
259         };
260         mutable Selection selection;
261
262         /// needed for the toggling
263         LyXCursor last_sel_cursor;
264         ///
265         LyXCursor toggle_cursor;
266         ///
267         LyXCursor toggle_end_cursor;
268    
269         /// need the selection cursor:
270         void setSelection(BufferView *);
271         ///
272         void clearSelection(BufferView *) const;
273         ///
274         string const selectionAsString(Buffer const *) const;
275         
276         /// select the word we need depending on word_location
277         void getWord(LyXCursor & from, LyXCursor & to, 
278                      word_location const) const;
279         /// just selects the word the cursor is in
280         void selectWord(BufferView *, word_location const);
281         /// returns the inset at cursor (if it exists), 0 otherwise
282         Inset * getInset() const;
283
284         /** 'selects" the next word, where the cursor is not in 
285          and returns this word as string. THe cursor will be moved 
286          to the beginning of this word. 
287          With SelectSelectedWord can this be highlighted really
288          */ 
289         string const selectNextWord(BufferView *, float & value) const;
290         ///
291         void selectSelectedWord(BufferView *);
292         ///
293         void setCursor(BufferView *, Paragraph * par,
294                        Paragraph::size_type pos,
295                        bool setfont = true,
296                        bool boundary = false) const;
297         ///
298         void setCursor(BufferView *, LyXCursor &, Paragraph * par,
299                        Paragraph::size_type pos,
300                        bool boundary = false) const;
301         ///
302         void setCursorIntern(BufferView *, Paragraph * par,
303                              Paragraph::size_type pos,
304                              bool setfont = true,
305                              bool boundary = false) const;
306         ///
307         void setCurrentFont(BufferView *) const;
308
309         ///
310         bool isBoundary(Buffer const *, Paragraph * par,
311                         Paragraph::size_type pos) const;
312         ///
313         bool isBoundary(Buffer const *, Paragraph * par,
314                          Paragraph::size_type pos,
315                          LyXFont const & font) const;
316
317         ///
318         void setCursorFromCoordinates(BufferView *, int x, int y) const;
319         ///
320         void setCursorFromCoordinates(BufferView *, LyXCursor &,
321                                       int x, int y) const;
322         ///
323         void cursorUp(BufferView *) const;
324         ///
325         void cursorDown(BufferView *) const;
326         ///
327         void cursorLeft(BufferView *, bool internal = true) const;
328         ///
329         void cursorRight(BufferView *, bool internal = true) const;
330         ///
331         void cursorLeftOneWord(BufferView *) const;
332         ///
333         void cursorLeftOneWord(LyXCursor &) const;
334         ///
335         void cursorRightOneWord(BufferView *) const;
336         ///
337         void cursorUpParagraph(BufferView *) const;
338         ///
339         void cursorDownParagraph(BufferView *) const;
340         ///
341         void cursorHome(BufferView *) const;
342         ///
343         void cursorEnd(BufferView *) const;
344         ///
345         void cursorTab(BufferView *) const;
346         ///
347         void cursorTop(BufferView *) const;
348         ///
349         void cursorBottom(BufferView *) const;
350         ///
351         void Delete(BufferView *);
352         ///
353         void backspace(BufferView *);
354         ///
355         void deleteWordForward(BufferView *);
356         ///
357         void deleteWordBackward(BufferView *);
358         ///
359         void deleteLineForward(BufferView *);
360         ///
361         bool selectWordWhenUnderCursor(BufferView *, 
362                                        word_location const);
363         ///
364         enum TextCase {
365                 ///
366                 text_lowercase = 0,
367                 ///
368                 text_capitalization = 1,
369                 ///
370                 text_uppercase = 2
371         };
372         /// Change the case of the word at cursor position.
373         void changeCase(BufferView *, TextCase action);
374         ///
375         void changeRegionCase(BufferView * bview,
376                                        LyXCursor const & from,
377                                        LyXCursor const & to,
378                                        LyXText::TextCase action);
379         ///
380         void transposeChars(BufferView &);
381         
382         /** returns a printed row in a pixmap. The y value is needed to
383           decide, wether it is selected text or not. This is a strange
384           solution but faster.
385          */
386         void getVisibleRow(BufferView *, int y_offset, int x_offset,
387                            Row * row_ptr, int y, bool cleared=false);
388
389         /// 
390         void toggleInset(BufferView *);
391         ///
392         void cutSelection(BufferView *, bool = true);
393         ///
394         void copySelection(BufferView *);
395         ///
396         void pasteSelection(BufferView *);
397         ///
398         void copyEnvironmentType();
399         ///
400         void pasteEnvironmentType(BufferView *);
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         LColor::color backgroundColor();
609
610
611         ///
612         mutable std::vector<Paragraph::size_type> log2vis_list;
613
614         ///
615         mutable std::vector<Paragraph::size_type> vis2log_list;
616
617         ///
618         mutable std::vector<Paragraph::size_type> bidi_levels;
619
620         ///
621         mutable Paragraph::size_type bidi_start;
622
623         ///
624         mutable Paragraph::size_type bidi_end;
625
626         ///
627         mutable bool bidi_same_direction;
628
629         ///
630         unsigned char transformChar(unsigned char c, Paragraph * par,
631                                     Paragraph::size_type pos) const;
632
633         /** returns the paragraph position of the last character in the 
634           specified row
635           */
636         Paragraph::size_type rowLast(Row const * row) const;
637         ///
638         Paragraph::size_type rowLastPrintable(Row const * row) const;
639
640         ///
641         void charInserted();
642 public:
643         //
644         // special owner functions
645         ///
646         Paragraph * ownerParagraph() const;
647         //
648         Paragraph * ownerParagraph(Paragraph *) const;
649         // set it searching first for the right owner using the paragraph id
650         Paragraph * ownerParagraph(int id, Paragraph *) const;
651 };
652
653
654 /* returns a pointer to the row near the specified y-coordinate
655  * (relative to the whole text). y is set to the real beginning
656  * of this row */
657 inline
658 Row * LyXText::getRowNearY(int & y) const
659 {
660         // If possible we should optimize this method. (Lgb)
661         Row * tmprow = firstrow;
662         int tmpy = 0;
663         
664         while (tmprow->next() && tmpy + tmprow->height() <= y) {
665                 tmpy += tmprow->height();
666                 tmprow = tmprow->next();
667         }
668         
669         y = tmpy;   // return the real y
670         return tmprow;
671 }
672 #endif