2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1995 Matthias Ettrich
8 * Copyright 1995-2001 The LyX Team.
10 * ====================================================== */
16 #include "lyxcursor.h"
19 #include "insets/inset.h"
34 This class holds the mapping between buffer paragraphs and screen rows.
45 NEED_VERY_LITTLE_REFRESH = 2,
51 // the word around the cursor, only if the cursor is
54 // the word around the cursor
56 /// the word begining from the cursor position
58 /// the word around the cursor or before the cursor
60 /// the next word (not yet used)
65 LyXText(BufferView *);
66 /// sets inset as owner
72 void init(BufferView *, bool reinit = false);
76 mutable unsigned int width;
77 /// the current font settings
78 mutable LyXFont current_font;
80 mutable LyXFont real_current_font;
81 /// first visible pixel-row is set from LyXScreen!!!
82 // unsigned is wrong here for text-insets!
85 InsetText * inset_owner;
87 UpdatableInset * the_locking_inset;
90 int getRealCursorX(BufferView *) const;
92 LyXFont const getFont(Buffer const *, Paragraph * par,
93 lyx::pos_type pos) const;
95 LyXFont const getLayoutFont(Buffer const *, Paragraph * par) const;
97 LyXFont const getLabelFont(Buffer const *, Paragraph * par) const;
99 void setCharFont(Buffer const *, Paragraph * par,
100 lyx::pos_type pos, LyXFont const & font);
101 void setCharFont(BufferView *, Paragraph * par,
102 lyx::pos_type pos, LyXFont const & font, bool toggleall);
104 /// what you expect when pressing <enter> at cursor position
105 void breakParagraph(BufferView *, char keep_layout = 0);
107 /** set layout over selection and make a total rebreak of
110 Paragraph * setLayout(BufferView *, LyXCursor & actual_cursor,
111 LyXCursor & selection_start,
112 LyXCursor & selection_end,
113 string const & layout);
115 void setLayout(BufferView *, string const & layout);
117 /** increment depth over selection and make a total rebreak of those
120 void incDepth(BufferView *);
122 /** decrement depth over selection and make a total rebreak of those
124 void decDepth(BufferView *);
126 /// get the depth at current cursor position
127 int getDepth() const;
129 /** set font over selection and make a total rebreak of those
131 toggleall defaults to false.
133 void setFont(BufferView *, LyXFont const &, bool toggleall = false);
135 /** deletes and inserts again all paragaphs between the cursor
136 and the specified par. The Cursor is needed to set the refreshing
138 This function is needed after SetLayout and SetFont etc.
140 void redoParagraphs(BufferView *, LyXCursor const & cursor,
141 Paragraph const * end_par) const;
143 void redoParagraph(BufferView *) const;
146 void toggleFree(BufferView *, LyXFont const &, bool toggleall = false);
149 string getStringToIndex(BufferView *);
151 /** recalculates the heights of all previous rows of the
152 specified paragraph. needed, if the last characters font
155 void redoHeightOfParagraph(BufferView *, LyXCursor const & cursor);
157 /** insert a character, moves all the following breaks in the
158 same Paragraph one to the right and make a little rebreak
160 void insertChar(BufferView *, char c);
162 void insertInset(BufferView *, Inset * inset);
164 /// Completes the insertion with a full rebreak
165 void fullRebreak(BufferView *);
168 mutable Row * need_break_row;
170 mutable int refresh_y;
172 mutable Row * refresh_row;
174 /// give and set the LyXText status
175 text_status status() const;
177 void status(BufferView *, text_status) const;
180 Inset::RESULT dispatch(FuncRequest const & cmd);
183 /// only the top-level LyXText has this non-zero
184 BufferView * bv_owner;
186 /** wether the screen needs a refresh,
187 starting with refresh_y
189 mutable text_status status_;
192 /** returns a pointer to the row near the specified y-coordinate
193 (relative to the whole text). y is set to the real beginning
196 Row * getRowNearY(int & y) const;
198 /** returns the column near the specified x-coordinate of the row
199 x is set to the real beginning of this column
201 lyx::pos_type getColumnNearX(BufferView *, Row * row,
202 int & x, bool & boundary) const;
204 /** returns a pointer to a specified row. y is set to the beginning
207 Row * getRow(Paragraph * par, lyx::pos_type pos, int & y) const;
208 /** returns the firstrow, this could be done with the above too but
209 IMO it's stupid to have to allocate a dummy y all the time I need
212 Row * firstRow() { return firstrow; }
215 Later this variable has to be removed. There should be now internal
216 cursor in a text (and thus not in a buffer). By keeping this it is
217 (I think) impossible to have several views with the same buffer, but
218 the cursor placed at different places.
220 Since the LyXText now has been moved from Buffer to BufferView
221 it should not be absolutely needed to move the cursor...
223 mutable LyXCursor cursor; // actual cursor position
225 /** The structure that keeps track of the selections set. */
228 : set_(false), mark_(false)
242 LyXCursor cursor; // temporary cursor to hold a cursor position
243 // until setSelection is called!
244 LyXCursor start; // start of a REAL selection
245 LyXCursor end; // end of a REAL selection
247 bool set_; // former selection
248 bool mark_; // former mark_set
251 mutable Selection selection;
252 // this is used to handle XSelection events in the right manner
253 mutable Selection xsel_cache;
255 /// needed for the toggling (cursor position on last selection made)
256 mutable LyXCursor last_sel_cursor;
257 /// needed for toggling the selection in screen.C
258 mutable LyXCursor toggle_cursor;
259 /// needed for toggling the selection in screen.C
260 mutable LyXCursor toggle_end_cursor;
262 /// need the selection cursor:
263 void setSelection(BufferView *);
265 void clearSelection() const;
267 string const selectionAsString(Buffer const *, bool label) const;
269 /// select the word we need depending on word_location
270 void getWord(LyXCursor & from, LyXCursor & to,
271 word_location const) const;
272 /// just selects the word the cursor is in
273 void selectWord(BufferView *, word_location const);
274 /// returns the inset at cursor (if it exists), 0 otherwise
275 Inset * getInset() const;
277 /// accept selected change
278 void acceptChange(BufferView * bv);
280 /// reject selected change
281 void rejectChange(BufferView * bv);
283 /** 'selects" the next word, where the cursor is not in
284 and returns this word as string. THe cursor will be moved
285 to the beginning of this word.
286 With SelectSelectedWord can this be highlighted really
288 WordLangTuple const selectNextWordToSpellcheck(BufferView *, float & value) const;
290 void selectSelectedWord(BufferView *);
291 /// returns true if par was empty and was removed
292 bool setCursor(BufferView *, Paragraph * par,
295 bool boundary = false) const;
297 void setCursor(BufferView *, LyXCursor &, Paragraph * par,
299 bool boundary = false) const;
301 void setCursorIntern(BufferView *, Paragraph * par,
304 bool boundary = false) const;
306 void setCurrentFont(BufferView *) const;
309 bool isBoundary(Buffer const *, Paragraph * par,
310 lyx::pos_type pos) const;
312 bool isBoundary(Buffer const *, Paragraph * par,
314 LyXFont const & font) const;
317 void setCursorFromCoordinates(BufferView *, int x, int y) const;
319 void setCursorFromCoordinates(BufferView *, LyXCursor &,
322 void cursorUp(BufferView *, bool selecting = false) const;
324 void cursorDown(BufferView *, bool selecting = false) const;
326 void cursorLeft(BufferView *, bool internal = true) const;
328 void cursorRight(BufferView *, bool internal = true) const;
330 void cursorLeftOneWord(BufferView *) const;
332 void cursorRightOneWord(BufferView *) const;
334 void cursorUpParagraph(BufferView *) const;
336 void cursorDownParagraph(BufferView *) const;
338 void cursorHome(BufferView *) const;
340 void cursorEnd(BufferView *) const;
342 void cursorPrevious(BufferView * bv);
344 void cursorNext(BufferView * bv);
346 void cursorTab(BufferView *) const;
348 void cursorTop(BufferView *) const;
350 void cursorBottom(BufferView *) const;
352 void Delete(BufferView *);
354 void backspace(BufferView *);
356 bool selectWordWhenUnderCursor(BufferView *,
357 word_location const);
363 text_capitalization = 1,
367 /// Change the case of the word at cursor position.
368 void changeCase(BufferView *, TextCase action);
370 void transposeChars(BufferView &);
372 /** returns a printed row in a pixmap. The y value is needed to
373 decide, wether it is selected text or not. This is a strange
376 void getVisibleRow(BufferView *, int y_offset, int x_offset,
377 Row * row_ptr, int y, bool cleared=false);
380 void toggleInset(BufferView *);
382 void cutSelection(BufferView *, bool doclear = true, bool realcut = true);
384 void copySelection(BufferView *);
386 void pasteSelection(BufferView *);
388 void copyEnvironmentType();
390 void pasteEnvironmentType(BufferView *);
392 /** the DTP switches for paragraphs. LyX will store the top settings
393 always in the first physical paragraph, the bottom settings in the
394 last. When a paragraph is broken, the top settings rest, the bottom
395 settings are given to the new one. So I can make shure, they do not
396 duplicate themself (and you cannnot make dirty things with them! )
398 void setParagraph(BufferView *,
399 bool line_top, bool line_bottom,
400 bool pagebreak_top, bool pagebreak_bottom,
401 VSpace const & space_top,
402 VSpace const & space_bottom,
403 Spacing const & spacing,
405 string labelwidthstring,
408 /* these things are for search and replace */
411 * Sets the selection from the current cursor position to length
412 * characters to the right. No safety checks.
414 void setSelectionRange(BufferView *, lyx::pos_type length);
416 /** simple replacing. The font of the first selected character
419 void replaceSelectionWithString(BufferView *, string const & str);
421 /// needed to insert the selection
422 void insertStringAsLines(BufferView *, string const & str);
423 /// needed to insert the selection
424 void insertStringAsParagraphs(BufferView *, string const & str);
426 /// Find next inset of some specified type.
427 bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
428 string const & contents = string()) const;
430 void gotoInset(BufferView * bv, std::vector<Inset::Code> const & codes,
433 void gotoInset(BufferView * bv, Inset::Code code, bool same_content);
436 /* for the greater insets */
438 /// returns false if inset wasn't found
439 bool updateInset(BufferView *, Inset *);
441 void checkParagraph(BufferView *, Paragraph * par, lyx::pos_type pos);
443 int workWidth(BufferView *) const;
445 int workWidth(BufferView *, Inset * inset) const;
447 void computeBidiTables(Buffer const *, Row * row) const;
449 /// Maps positions in the visual string to positions in logical string.
451 lyx::pos_type log2vis(lyx::pos_type pos) const {
452 if (bidi_start == -1)
455 return log2vis_list[pos-bidi_start];
458 /// Maps positions in the logical string to positions in visual string.
460 lyx::pos_type vis2log(lyx::pos_type pos) const {
461 if (bidi_start == -1)
464 return vis2log_list[pos-bidi_start];
468 lyx::pos_type bidi_level(lyx::pos_type pos) const {
469 if (bidi_start == -1)
472 return bidi_levels[pos-bidi_start];
476 bool bidi_InRange(lyx::pos_type pos) const {
477 return bidi_start == -1 ||
478 (bidi_start <= pos && pos <= bidi_end);
482 mutable Row * firstrow;
484 mutable Row * lastrow;
487 void cursorLeftOneWord(LyXCursor &) const;
490 float getCursorX(BufferView *, Row *, lyx::pos_type pos,
491 lyx::pos_type last, bool boundary) const;
493 void changeRegionCase(BufferView * bv,
494 LyXCursor const & from,
495 LyXCursor const & to,
496 LyXText::TextCase action);
497 /// used in setlayout
498 void makeFontEntriesLayoutSpecific(Buffer const *, Paragraph * par);
500 /** forces the redrawing of a paragraph. Needed when manipulating a
503 void redoDrawingOfParagraph(BufferView *, LyXCursor const & cursor);
505 /** Copybuffer for copy environment type.
506 Asger has learned that this should be a buffer-property instead
507 Lgb has learned that 'char' is a lousy type for non-characters
509 string copylayouttype;
511 /** inserts a new row behind the specified row, increments
512 the touched counters */
513 void insertRow(Row * row, Paragraph * par, lyx::pos_type pos) const;
514 /// removes the row and reset the touched counters
515 void removeRow(Row * row) const;
517 /// remove all following rows of the paragraph of the specified row.
518 void removeParagraph(Row * row) const;
520 /// insert the specified paragraph behind the specified row
521 void insertParagraph(BufferView *,
522 Paragraph * par, Row * row) const;
524 /** appends the implizit specified paragraph behind the specified row,
525 * start at the implizit given position */
526 void appendParagraph(BufferView *, Row * row) const;
529 void breakAgain(BufferView *, Row * row) const;
531 void breakAgainOneRow(BufferView *, Row * row);
532 /// Calculate and set the height of the row
533 void setHeightOfRow(BufferView *, Row * row_ptr) const;
535 /** this calculates the specified parameters. needed when setting
536 * the cursor and when creating a visible row */
537 void prepareToPrint(BufferView *, Row * row, float & x,
538 float & fill_separator,
540 float & fill_label_hfill,
541 bool bidi = true) const;
543 /// A struct used for drawing routines
544 struct DrawRowParams {
549 // the painter to use
551 // has the background been cleared
553 /// x offset (e.g. for insets)
555 /// y offset (e.g. for insets)
561 /// the inset/view full width
567 /// fill separator size
571 /// paint the background
572 bool paintRowBackground(DrawRowParams & p);
574 /// paint the selection background
575 void paintRowSelection(DrawRowParams & p);
578 void paintChangeBar(DrawRowParams & p);
580 /// paint appendix marker
581 void paintRowAppendix(DrawRowParams & p);
583 /// paint page break marker. Returns its height.
584 int paintPageBreak(string const & label, int y, DrawRowParams & p);
586 /// paint env depth bar
587 void paintRowDepthBar(DrawRowParams & p);
589 /// get the on-screen size of the length marker
590 int getLengthMarkerHeight(BufferView * bv, VSpace const & vsp) const;
592 /// paint an added space marker
593 int drawLengthMarker(DrawRowParams & p, string const & str,
594 VSpace const & vsp, int start);
596 /// paint a first row in a paragraph
597 void paintFirstRow(DrawRowParams & p);
599 /// paint a last row in a paragraph
600 void paintLastRow(DrawRowParams & p);
603 void paintRowText(DrawRowParams & p);
605 // fix the cursor `cur' after a characters has been deleted at `where'
606 // position. Called by deleteEmptyParagraphMechanism
607 void fixCursorAfterDelete(BufferView * bv,
609 LyXCursor const & where) const;
611 /// delete double space (false) or empty paragraphs (true) around old_cursor
612 bool deleteEmptyParagraphMechanism(BufferView *,
613 LyXCursor const & old_cursor) const;
616 /** Updates all counters starting BEHIND the row. Changed paragraphs
617 * with a dynamic left margin will be rebroken. */
618 void updateCounters(BufferView *) const;
620 void update(BufferView * bv, bool changed = true);
622 * Returns an inset if inset was hit, or 0 if not.
623 * If hit, the coordinates are changed relative to the inset.
625 Inset * checkInsetHit(BufferView * bv, int & x, int & y) const;
629 void setCounter(Buffer const *, Paragraph * par) const;
631 void deleteWordForward(BufferView *);
633 void deleteWordBackward(BufferView *);
635 void deleteLineForward(BufferView *);
638 * some low level functions
642 int singleWidth(BufferView *, Paragraph * par,
643 lyx::pos_type pos) const;
645 int singleWidth(BufferView *, Paragraph * par,
646 lyx::pos_type pos, char c) const;
649 /// draw normal chars
650 void drawChars(DrawRowParams & p, lyx::pos_type & vpos,
651 bool hebrew, bool arabic);
652 /// draw from arabic composed char
653 void drawArabicComposeChar(DrawRowParams & p, lyx::pos_type & vpos);
654 /// draw from hebrew composed char
655 void drawHebrewComposeChar(DrawRowParams & p, lyx::pos_type & vpos);
656 /// draw a mark for foreign language, starting from orig_x
657 void drawForeignMark(DrawRowParams & p, float const orig_x, LyXFont const & orig_font);
659 bool drawInset(DrawRowParams & p, lyx::pos_type const pos);
660 /// draw new line marker
661 void drawNewline(DrawRowParams & p, lyx::pos_type const pos);
663 bool draw(DrawRowParams & p, lyx::pos_type & vpos);
665 /// get the next breakpoint in a given paragraph
666 lyx::pos_type nextBreakPoint(BufferView *, Row const * row, int width) const;
667 /// returns the minimum space a row needs on the screen in pixel
668 int fill(BufferView *, Row * row, int workwidth) const;
670 /** returns the minimum space a manual label needs on the
672 int labelFill(BufferView *, Row const * row) const;
675 * Returns the left beginning of the text.
676 * This information cannot be taken from the layout object, because
677 * in LaTeX the beginning of the text fits in some cases
678 * (for example sections) exactly the label-width.
680 int leftMargin(BufferView *, Row const * row) const;
682 int rightMargin(Buffer const *, Row const * row) const;
684 int labelEnd (BufferView *, Row const * row) const;
687 LColor::color backgroundColor();
691 mutable std::vector<lyx::pos_type> log2vis_list;
694 mutable std::vector<lyx::pos_type> vis2log_list;
697 mutable std::vector<lyx::pos_type> bidi_levels;
700 mutable lyx::pos_type bidi_start;
703 mutable lyx::pos_type bidi_end;
706 mutable bool bidi_same_direction;
709 unsigned char transformChar(unsigned char c, Paragraph * par,
710 lyx::pos_type pos) const;
716 // special owner functions
718 Paragraph * ownerParagraph() const;
720 void ownerParagraph(Paragraph *) const;
721 // set it searching first for the right owner using the paragraph id
722 void ownerParagraph(int id, Paragraph *) const;
724 /// return true if this is the outer-most lyxtext
725 bool isTopLevel() const;
728 /// return the default height of a row in pixels, considering font zoom
729 extern int defaultRowHeight();