]> git.lyx.org Git - lyx.git/blob - src/Row.h
When selecting text with the mouse, inset selection happens in the middle
[lyx.git] / src / Row.h
1 // -*- C++ -*-
2 /**
3  * \file Row.h
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Matthias Ettrich
8  * \author Lars Gullik Bjønnes
9  *
10  * Full author contact details are available in file CREDITS.
11  *
12  * Metrics for an on-screen text row.
13  */
14
15 #ifndef ROW_H
16 #define ROW_H
17
18 #include "Changes.h"
19 #include "Dimension.h"
20 #include "Font.h"
21
22 #include "support/docstring.h"
23 #include "support/types.h"
24
25 #include <vector>
26
27 namespace lyx {
28
29 class DocIterator;
30 class Inset;
31
32 /**
33  * An on-screen row of text. A paragraph is broken into a RowList for
34  * display. Each Row contains a tokenized description of the contents
35  * of the line.
36  */
37 class Row {
38 public:
39         // Possible types of row elements
40         enum Type {
41                 // a string of character
42                 STRING,
43                 /**
44                  * Something (completion, end-of-par marker)
45                  * that occupies space one screen but does not
46                  * correspond to any paragraph contents
47                  */
48                 VIRTUAL,
49                 // An inset
50                 INSET,
51                 // Some spacing described by its width, not a string
52                 SPACE
53         };
54
55 /**
56  * One element of a Row. It has a set of attributes that can be used
57  * by other methods that need to parse the Row contents.
58  */
59         struct Element {
60                 Element(Type const t, pos_type p, Font const & f, Change const & ch)
61                         : type(t), pos(p), endpos(p + 1), inset(0),
62                           extra(0), font(f), change(ch), final(false) {}
63
64                 // Return the number of separator in the element (only STRING type)
65                 int countSeparators() const;
66
67                 // Return total width of element, including separator overhead
68                 // FIXME: Cache this value or the number of expanders?
69                 double full_width() const { return dim.wid + extra * countExpanders(); }
70                 // Return the number of expanding characters in the element (only STRING
71                 // type).
72                 int countExpanders() const;
73                 // Return the amount of expansion: the number of expanding characters
74                 // that get stretched during justification, times the em of the font
75                 // (only STRING type).
76                 int expansionAmount() const;
77                 // set extra proportionally to the font em value.
78                 void setExtra(double extra_per_em);
79
80                 /** Return position in pixels (from the left) of position
81                  * \param i in the row element.
82                  */
83                 double pos2x(pos_type i) const;
84                 /** Return character position that is the closest to
85                  *  pixel position \param x. The value \param x is
86                  *  adjusted to the actual pixel position.
87                  *  \param select if true, return the right edge when closer.
88                  */
89                 pos_type x2pos(int & x, bool select = false) const;
90                 /** Break the element if possible, so that its width is less
91                  * than \param w. Returns true on success. When \param force
92                  * is true, the string is cut at any place, other wise it
93                  * respects the row breaking rules of characters.
94                  */
95                 bool breakAt(int w, bool force);
96
97                 // Returns the position on left side of the element.
98                 pos_type left_pos() const;
99                 // Returns the position on right side of the element.
100                 pos_type right_pos() const;
101
102                 //
103                 bool isRTL() const { return font.isVisibleRightToLeft(); }
104                 // This is true for virtual elements.
105                 // Note that we do not use the type here. The two definitions
106                 // should be equivalent
107                 bool isVirtual() const { return pos == endpos; }
108
109                 // The kind of row element
110                 Type type;
111                 // position of the element in the paragraph
112                 pos_type pos;
113                 // first position after the element in the paragraph
114                 pos_type endpos;
115                 // The dimension of the chunk (does not contains the
116                 // separator correction)
117                 Dimension dim;
118
119                 // Non-zero only if element is an inset
120                 Inset const * inset;
121
122                 // Only non-null for justified rows
123                 double extra;
124
125                 // Non-empty if element is a string or is virtual
126                 docstring str;
127                 //
128                 Font font;
129                 //
130                 Change change;
131                 // is it possible to add contents to this element?
132                 bool final;
133
134                 friend std::ostream & operator<<(std::ostream & os, Element const & row);
135         };
136
137
138         ///
139         Row();
140         ///
141         bool changed() const { return changed_; }
142         ///
143         void setChanged(bool c) { changed_ = c; }
144         ///
145         void setCrc(size_type crc) const;
146         /// Set the selection begin and end.
147         /**
148           * This is const because we update the selection status only at draw()
149           * time.
150           */
151         void setSelection(pos_type sel_beg, pos_type sel_end) const;
152         ///
153         bool selection() const;
154         /// Set the selection begin and end and whether the left and/or right
155         /// margins are selected.
156         void setSelectionAndMargins(DocIterator const & beg,
157                 DocIterator const & end) const;
158
159         ///
160         void pit(pit_type p) { pit_ = p; }
161         ///
162         pit_type pit() const { return pit_; }
163         ///
164         void pos(pos_type p) { pos_ = p; }
165         ///
166         pos_type pos() const { return pos_; }
167         ///
168         void endpos(pos_type p) { end_ = p; }
169         ///
170         pos_type endpos() const { return end_; }
171         ///
172         void right_boundary(bool b) { right_boundary_ = b; }
173         ///
174         bool right_boundary() const { return right_boundary_; }
175         ///
176         void flushed(bool b) { flushed_ = b; }
177         ///
178         bool flushed() const { return flushed_; }
179
180         ///
181         Dimension const & dimension() const { return dim_; }
182         ///
183         Dimension & dimension() { return dim_; }
184         ///
185         int height() const { return dim_.height(); }
186         /// The width of the row, including the left margin, but not the right one.
187         int width() const { return dim_.wid; }
188         ///
189         int ascent() const { return dim_.asc; }
190         ///
191         int descent() const { return dim_.des; }
192
193         /// The offset of the left-most cursor position on the row
194         int left_x() const;
195         /// The offset of the right-most cursor position on the row
196         int right_x() const;
197
198         // Return the number of separators in the row
199         int countSeparators() const;
200         // Set the extra spacing for every expanding character in STRING-type
201         // elements.  \param w is the total amount of extra width for the row to be
202         // distributed among expanders.  \return false if the justification fails.
203         bool setExtraWidth(int w);
204
205         ///
206         void add(pos_type pos, Inset const * ins, Dimension const & dim,
207                  Font const & f, Change const & ch);
208         ///
209         void add(pos_type pos, char_type const c,
210                  Font const & f, Change const & ch);
211         ///
212         void addVirtual(pos_type pos, docstring const & s,
213                         Font const & f, Change const & ch);
214         ///
215         void addSpace(pos_type pos, int width, Font const & f, Change const & ch);
216
217         ///
218         typedef std::vector<Element> Elements;
219         ///
220         typedef Elements::iterator iterator;
221         ///
222         typedef Elements::const_iterator const_iterator;
223         ///
224         iterator begin() { return elements_.begin(); }
225         ///
226         iterator end() { return elements_.end(); }
227         ///
228         const_iterator begin() const { return elements_.begin(); }
229         ///
230         const_iterator end() const { return elements_.end(); }
231
232         ///
233         bool empty() const { return elements_.empty(); }
234         ///
235         Element & front() { return elements_.front(); }
236         ///
237         Element const & front() const { return elements_.front(); }
238         ///
239         Element & back() { return elements_.back(); }
240         ///
241         Element const & back() const { return elements_.back(); }
242         /// remove last element
243         void pop_back();
244         /// remove all row elements
245         void clear() { elements_.clear(); }
246         /**
247          * if row width is too large, remove all elements after last
248          * separator and update endpos if necessary. If all that
249          * remains is a large word, cut it to \param width.
250          * \param body_pos minimum amount of text to keep.
251          * \param width maximum width of the row.
252          * \param available width on next row.
253          * \return true if the row has been shortened.
254          */
255         bool shortenIfNeeded(pos_type const body_pos, int const width, int const next_width);
256
257         /**
258          * If last element of the row is a string, compute its width
259          * and mark it final.
260          */
261         void finalizeLast();
262
263         /**
264          * Find sequences of right-to-left elements and reverse them.
265          * This should be called once the row is completely built.
266          */
267         void reverseRTL(bool rtl_par);
268         ///
269         bool isRTL() const { return rtl_; }
270         /// Find row element that contains \c pos, and compute x offset.
271         const_iterator const findElement(pos_type pos, bool boundary, double & x) const;
272
273         friend std::ostream & operator<<(std::ostream & os, Row const & row);
274
275         /// additional width for separators in justified rows (i.e. space)
276         double separator;
277         /// width of hfills in the label
278         double label_hfill;
279         /// the left margin position of the row
280         int left_margin;
281         /// the right margin of the row
282         int right_margin;
283         ///
284         mutable pos_type sel_beg;
285         ///
286         mutable pos_type sel_end;
287         ///
288         mutable bool begin_margin_sel;
289         ///
290         mutable bool end_margin_sel;
291
292 private:
293         /// Decides whether the margin is selected.
294         /**
295           * \param margin_begin
296           * \param beg
297           * \param end
298           */
299         bool isMarginSelected(bool left_margin, DocIterator const & beg,
300                 DocIterator const & end) const;
301
302         /**
303          * Returns true if a char or string with font \c f and change
304          * type \c ch can be added to the current last element of the
305          * row.
306          */
307         bool sameString(Font const & f, Change const & ch) const;
308
309         ///
310         Elements elements_;
311
312         /// has the Row appearance changed since last drawing?
313         mutable bool changed_;
314         /// CRC of row contents.
315         mutable size_type crc_;
316         /// Index of the paragraph that contains this row
317         pit_type pit_;
318         /// first pos covered by this row
319         pos_type pos_;
320         /// one behind last pos covered by this row
321         pos_type end_;
322         // Is there a boundary at the end of the row (display inset...)
323         bool right_boundary_;
324         // Shall the row be flushed when it is supposed to be justified?
325         bool flushed_;
326         /// Row dimension.
327         Dimension dim_;
328         /// true when this row lives in a right-to-left paragraph
329         bool rtl_;
330 };
331
332
333 } // namespace lyx
334
335 #endif