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