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