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