]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
paint cleanups as sent to list
[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         /// clear any pending paints
192         void clearPaint();
193
194         /// post notice that we changed during a draw
195         void postChangedInDraw();
196
197         /**
198          * Mark position y as the starting point for a repaint
199          */
200         void postPaint(BufferView & bv, int start_y);
201
202         /**
203          * Mark the given row at position y as needing a repaint.
204          */
205         void postRowPaint(BufferView & bv, Row * row, int start_y);
206
207         ///
208         Inset::RESULT dispatch(FuncRequest const & cmd);
209
210         friend class LyXScreen;
211
212         /**
213          * Return the status. This represents what repaints are
214          * pending after some operation (e.g. inserting a char).
215          */
216         text_status status() const;
217
218 private:
219         /**
220          * The pixel y position from which to repaint the screen.
221          * The position is absolute along the height of outermost
222          * lyxtext (I think). NEED_MORE_REFRESH and NEED_LITTLE_REFRESH
223          * repaints both use this as a starting point (if it's within
224          * the viewable portion of the lyxtext).
225          */
226         int refresh_y;
227         /**
228          * The row from which to repaint the screen, used by screen.c.
229          * This must be set if the pending update is NEED_LITTLE_REFRESH.
230          * It doesn't make any difference for NEED_MORE_REFRESH.
231          */
232         mutable Row * refresh_row;
233
234         /// refresh status
235         text_status status_;
236
237         /// only the top-level LyXText has this non-zero
238         BufferView * bv_owner;
239
240 public:
241         /** returns a pointer to the row near the specified y-coordinate
242           (relative to the whole text). y is set to the real beginning
243           of this row
244           */
245         Row * getRowNearY(int & y) const;
246
247         /** returns the column near the specified x-coordinate of the row
248          x is set to the real beginning of this column
249          */
250         lyx::pos_type getColumnNearX(BufferView *, Row * row,
251                                             int & x, bool & boundary) const;
252
253         /** returns a pointer to a specified row. y is set to the beginning
254          of the row
255          */
256         Row * getRow(Paragraph * par, lyx::pos_type pos, int & y) const;
257         /** returns the firstrow, this could be done with the above too but
258             IMO it's stupid to have to allocate a dummy y all the time I need
259             the first row
260         */
261         Row * firstRow() { return firstrow; }
262
263         /** The cursor.
264           Later this variable has to be removed. There should be now internal
265           cursor in a text (and thus not in a buffer). By keeping this it is
266           (I think) impossible to have several views with the same buffer, but
267           the cursor placed at different places.
268           [later]
269           Since the LyXText now has been moved from Buffer to BufferView
270           it should not be absolutely needed to move the cursor...
271           */
272         mutable LyXCursor cursor; // actual cursor position
273
274         /** The structure that keeps track of the selections set. */
275         struct Selection {
276                 Selection()
277                         : set_(false), mark_(false)
278                         {}
279                 bool set() const {
280                         return set_;
281                 }
282                 void set(bool s) {
283                         set_ = s;
284                 }
285                 bool mark() const {
286                         return mark_;
287                 }
288                 void mark(bool m) {
289                         mark_ = m;
290                 }
291                 LyXCursor cursor; // temporary cursor to hold a cursor position
292                                   // until setSelection is called!
293                 LyXCursor start;  // start of a REAL selection
294                 LyXCursor end;    // end of a REAL selection
295         private:
296                 bool set_; // former selection
297                 bool mark_; // former mark_set
298
299         };
300         mutable Selection selection;
301         // this is used to handle XSelection events in the right manner
302         mutable Selection xsel_cache;
303
304         /// needed for the toggling (cursor position on last selection made)
305         mutable LyXCursor last_sel_cursor;
306         /// needed for toggling the selection in screen.C
307         mutable LyXCursor toggle_cursor;
308         /// needed for toggling the selection in screen.C
309         mutable LyXCursor toggle_end_cursor;
310
311         /// need the selection cursor:
312         void setSelection(BufferView *);
313         ///
314         void clearSelection() const;
315         ///
316         string const selectionAsString(Buffer const *, bool label) const;
317
318         /// select the word we need depending on word_location
319         void getWord(LyXCursor & from, LyXCursor & to,
320                      word_location const) const;
321         /// just selects the word the cursor is in
322         void selectWord(BufferView *, word_location const);
323         /// returns the inset at cursor (if it exists), 0 otherwise
324         Inset * getInset() const;
325
326         /// accept selected change
327         void acceptChange(BufferView * bv);
328
329         /// reject selected change
330         void rejectChange(BufferView * bv);
331
332         /** 'selects" the next word, where the cursor is not in
333          and returns this word as string. THe cursor will be moved
334          to the beginning of this word.
335          With SelectSelectedWord can this be highlighted really
336          */
337         WordLangTuple const selectNextWordToSpellcheck(BufferView *, float & value) const;
338         ///
339         void selectSelectedWord(BufferView *);
340         /// returns true if par was empty and was removed
341         bool setCursor(BufferView *, Paragraph * par,
342                        lyx::pos_type pos,
343                        bool setfont = true,
344                        bool boundary = false) const;
345         ///
346         void setCursor(BufferView *, LyXCursor &, Paragraph * par,
347                        lyx::pos_type pos,
348                        bool boundary = false) const;
349         ///
350         void setCursorIntern(BufferView *, Paragraph * par,
351                              lyx::pos_type pos,
352                              bool setfont = true,
353                              bool boundary = false) const;
354         ///
355         void setCurrentFont(BufferView *) const;
356
357         ///
358         bool isBoundary(Buffer const *, Paragraph * par,
359                         lyx::pos_type pos) const;
360         ///
361         bool isBoundary(Buffer const *, Paragraph * par,
362                          lyx::pos_type pos,
363                          LyXFont const & font) const;
364
365         ///
366         void setCursorFromCoordinates(BufferView *, int x, int y) const;
367         ///
368         void setCursorFromCoordinates(BufferView *, LyXCursor &,
369                                       int x, int y) const;
370         ///
371         void cursorUp(BufferView *, bool selecting = false) const;
372         ///
373         void cursorDown(BufferView *, bool selecting = false) const;
374         ///
375         void cursorLeft(BufferView *, bool internal = true) const;
376         ///
377         void cursorRight(BufferView *, bool internal = true) const;
378         ///
379         void cursorLeftOneWord(BufferView *) const;
380         ///
381         void cursorRightOneWord(BufferView *) const;
382         ///
383         void cursorUpParagraph(BufferView *) const;
384         ///
385         void cursorDownParagraph(BufferView *) const;
386         ///
387         void cursorHome(BufferView *) const;
388         ///
389         void cursorEnd(BufferView *) const;
390         ///
391         void cursorPrevious(BufferView * bv);
392         ///
393         void cursorNext(BufferView * bv);
394         ///
395         void cursorTab(BufferView *) const;
396         ///
397         void cursorTop(BufferView *) const;
398         ///
399         void cursorBottom(BufferView *) const;
400         ///
401         void Delete(BufferView *);
402         ///
403         void backspace(BufferView *);
404         ///
405         bool selectWordWhenUnderCursor(BufferView *,
406                                        word_location const);
407         ///
408         enum TextCase {
409                 ///
410                 text_lowercase = 0,
411                 ///
412                 text_capitalization = 1,
413                 ///
414                 text_uppercase = 2
415         };
416         /// Change the case of the word at cursor position.
417         void changeCase(BufferView &, TextCase action);
418         ///
419         void transposeChars(BufferView &);
420
421         ///
422         void toggleInset(BufferView *);
423         ///
424         void cutSelection(BufferView *, bool doclear = true, bool realcut = true);
425         ///
426         void copySelection(BufferView *);
427         ///
428         void pasteSelection(BufferView *);
429         ///
430         void copyEnvironmentType();
431         ///
432         void pasteEnvironmentType(BufferView *);
433
434         /** the DTP switches for paragraphs. LyX will store the top settings
435          always in the first physical paragraph, the bottom settings in the
436          last. When a paragraph is broken, the top settings rest, the bottom
437          settings are given to the new one. So I can make shure, they do not
438          duplicate themself (and you cannnot make dirty things with them! )
439          */
440         void setParagraph(BufferView *,
441                           bool line_top, bool line_bottom,
442                           bool pagebreak_top, bool pagebreak_bottom,
443                           VSpace const & space_top,
444                           VSpace const & space_bottom,
445                           Spacing const & spacing,
446                           LyXAlignment align,
447                           string labelwidthstring,
448                           bool noindent);
449
450         /* these things are for search and replace */
451
452         /**
453          * Sets the selection from the current cursor position to length
454          * characters to the right. No safety checks.
455          */
456         void setSelectionRange(BufferView *, lyx::pos_type length);
457
458         /** simple replacing. The font of the first selected character
459           is used
460           */
461         void replaceSelectionWithString(BufferView *, string const & str);
462
463         /// needed to insert the selection
464         void insertStringAsLines(BufferView *, string const & str);
465         /// needed to insert the selection
466         void insertStringAsParagraphs(BufferView *, string const & str);
467
468         /// Find next inset of some specified type.
469         bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
470                            string const & contents = string()) const;
471         ///
472         void gotoInset(BufferView * bv, std::vector<Inset::Code> const & codes,
473                                                 bool same_content);
474         ///
475         void gotoInset(BufferView * bv, Inset::Code code, bool same_content);
476         ///
477
478         /* for the greater insets */
479
480         /// returns false if inset wasn't found
481         bool updateInset(BufferView *, Inset *);
482         ///
483         void checkParagraph(BufferView *, Paragraph * par, lyx::pos_type pos);
484         ///
485         int workWidth(BufferView &) const;
486         ///
487         int workWidth(BufferView &, Inset * inset) const;
488         ///
489         void computeBidiTables(Buffer const *, Row * row) const;
490
491         /// Maps positions in the visual string to positions in logical string.
492         inline
493         lyx::pos_type log2vis(lyx::pos_type pos) const {
494                 if (bidi_start == -1)
495                         return pos;
496                 else
497                         return log2vis_list[pos-bidi_start];
498         }
499
500         /// Maps positions in the logical string to positions in visual string.
501         inline
502         lyx::pos_type vis2log(lyx::pos_type pos) const {
503                 if (bidi_start == -1)
504                         return pos;
505                 else
506                         return vis2log_list[pos-bidi_start];
507         }
508         ///
509         inline
510         lyx::pos_type bidi_level(lyx::pos_type pos) const {
511                 if (bidi_start == -1)
512                         return 0;
513                 else
514                         return bidi_levels[pos-bidi_start];
515         }
516         ///
517         inline
518         bool bidi_InRange(lyx::pos_type pos) const {
519                 return bidi_start == -1 ||
520                         (bidi_start <= pos && pos <= bidi_end);
521         }
522 private:
523         ///
524         mutable Row * firstrow;
525         ///
526         mutable Row * lastrow;
527
528         ///
529         void cursorLeftOneWord(LyXCursor &) const;
530
531         ///
532         float getCursorX(BufferView *, Row *, lyx::pos_type pos,
533                                          lyx::pos_type last, bool boundary) const;
534         /// used in setlayout
535         void makeFontEntriesLayoutSpecific(Buffer const &, Paragraph & par);
536
537         /** forces the redrawing of a paragraph. Needed when manipulating a
538             right address box
539             */
540         void redoDrawingOfParagraph(BufferView *, LyXCursor const & cursor);
541
542         /** Copybuffer for copy environment type.
543           Asger has learned that this should be a buffer-property instead
544           Lgb has learned that 'char' is a lousy type for non-characters
545           */
546         string copylayouttype;
547
548         /** inserts a new row behind the specified row, increments
549             the touched counters */
550         void insertRow(Row * row, Paragraph * par, lyx::pos_type pos) const;
551         /// removes the row and reset the touched counters
552         void removeRow(Row * row) const;
553
554         /// remove all following rows of the paragraph of the specified row.
555         void removeParagraph(Row * row) const;
556
557         /// insert the specified paragraph behind the specified row
558         void insertParagraph(BufferView *,
559                              Paragraph * par, Row * row) const;
560
561         /** appends  the implizit specified paragraph behind the specified row,
562          * start at the implizit given position */
563         void appendParagraph(BufferView *, Row * row) const;
564
565         ///
566         void breakAgain(BufferView *, Row * row) const;
567         /// Calculate and set the height of the row
568         void setHeightOfRow(BufferView *, Row * row_ptr) const;
569
570         // fix the cursor `cur' after a characters has been deleted at `where'
571         // position. Called by deleteEmptyParagraphMechanism
572         void fixCursorAfterDelete(BufferView * bv,
573                                   LyXCursor & cur,
574                                   LyXCursor const & where) const;
575
576         /// delete double space (false) or empty paragraphs (true) around old_cursor
577         bool deleteEmptyParagraphMechanism(BufferView *,
578                                            LyXCursor const & old_cursor) const;
579
580 public:
581         /** Updates all counters starting BEHIND the row. Changed paragraphs
582          * with a dynamic left margin will be rebroken. */
583         void updateCounters(BufferView *) const;
584         ///
585         void update(BufferView * bv, bool changed = true);
586         /**
587          * Returns an inset if inset was hit, or 0 if not.
588          * If hit, the coordinates are changed relative to the inset.
589          */
590         Inset * checkInsetHit(BufferView * bv, int & x, int & y) const;
591
592         ///
593         int singleWidth(BufferView *, Paragraph * par,
594                 lyx::pos_type pos) const;
595         ///
596         int singleWidth(BufferView *, Paragraph * par,
597                 lyx::pos_type pos, char c) const;
598
599         /// return the color of the canvas
600         LColor::color backgroundColor() const;
601
602         ///
603         mutable bool bidi_same_direction;
604
605         unsigned char transformChar(unsigned char c, Paragraph * par,
606                                     lyx::pos_type pos) const;
607
608         /**
609          * Returns the left beginning of the text.
610          * This information cannot be taken from the layout object, because
611          * in LaTeX the beginning of the text fits in some cases
612          * (for example sections) exactly the label-width.
613          */
614         int leftMargin(BufferView *, Row const * row) const;
615         ///
616         int rightMargin(Buffer const &, Row const & row) const;
617
618         /** this calculates the specified parameters. needed when setting
619          * the cursor and when creating a visible row */
620         void prepareToPrint(BufferView *, Row * row, float & x,
621                             float & fill_separator,
622                             float & fill_hfill,
623                             float & fill_label_hfill,
624                             bool bidi = true) const;
625
626 private:
627         ///
628         void setCounter(Buffer const *, Paragraph * par) const;
629         ///
630         void deleteWordForward(BufferView *);
631         ///
632         void deleteWordBackward(BufferView *);
633         ///
634         void deleteLineForward(BufferView *);
635
636         /*
637          * some low level functions
638          */
639
640
641         /// return the pos value *before* which a row should break.
642         /// for example, the pos at which IsNewLine(pos) == true
643         lyx::pos_type rowBreakPoint(BufferView &, Row const & row) const;
644
645         /// returns the minimum space a row needs on the screen in pixel
646         int fill(BufferView &, Row & row, int workwidth) const;
647
648         /**
649          * returns the minimum space a manual label needs on the
650          * screen in pixels
651          */
652         int labelFill(BufferView &, Row const & row) const;
653
654         /// FIXME
655         int labelEnd(BufferView &, Row const & row) const;
656
657         ///
658         mutable std::vector<lyx::pos_type> log2vis_list;
659
660         ///
661         mutable std::vector<lyx::pos_type> vis2log_list;
662
663         ///
664         mutable std::vector<lyx::pos_type> bidi_levels;
665
666         ///
667         mutable lyx::pos_type bidi_start;
668
669         ///
670         mutable lyx::pos_type bidi_end;
671
672         ///
673         void charInserted();
674 public:
675         //
676         // special owner functions
677         ///
678         Paragraph * ownerParagraph() const;
679         //
680         void ownerParagraph(Paragraph *) const;
681         // set it searching first for the right owner using the paragraph id
682         void ownerParagraph(int id, Paragraph *) const;
683
684         /// return true if this is the outer-most lyxtext
685         bool isTopLevel() const;
686
687         /// return true if this is owned by an inset. FIXME: why the difference
688         /// with isTopLevel() ??
689         bool isInInset() const;
690 };
691
692 /// return the default height of a row in pixels, considering font zoom
693 extern int defaultRowHeight();
694
695 #endif // LYXTEXT_H