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