3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Lars Gullik Bjønnes
10 * \author Jürgen Vigna
12 * Full author contact details are available in file CREDITS.
14 * Metrics for an on-screen text row.
21 #include "DocIterator.h"
23 #include "frontends/FontMetrics.h"
25 #include "support/debug.h"
35 : separator(0), label_hfill(0), x(0),
36 sel_beg(-1), sel_end(-1),
37 begin_margin_sel(false), end_margin_sel(false),
38 changed_(false), crc_(0), pos_(0), end_(0)
42 void Row::setCrc(size_type crc) const
44 changed_ = crc != crc_;
49 void Row::pos(pos_type p)
55 void Row::endpos(pos_type p)
61 bool Row::isMarginSelected(bool left_margin, DocIterator const & beg,
62 DocIterator const & end) const
64 pos_type const sel_pos = left_margin ? sel_beg : sel_end;
65 pos_type const margin_pos = left_margin ? pos_ : end_;
67 // Is the chosen margin selected ?
68 if (sel_pos == margin_pos) {
69 if (beg.pos() == end.pos())
70 // This is a special case in which the space between after
71 // pos i-1 and before pos i is selected, i.e. the margins
72 // (see DocIterator::boundary_).
73 return beg.boundary() && !end.boundary();
74 else if (end.pos() == margin_pos)
75 // If the selection ends around the margin, it is only
76 // drawn if the cursor is after the margin.
77 return !end.boundary();
78 else if (beg.pos() == margin_pos)
79 // If the selection begins around the margin, it is
80 // only drawn if the cursor is before the margin.
81 return beg.boundary();
89 void Row::setSelectionAndMargins(DocIterator const & beg,
90 DocIterator const & end) const
92 setSelection(beg.pos(), end.pos());
95 end_margin_sel = isMarginSelected(false, beg, end);
96 begin_margin_sel = isMarginSelected(true, beg, end);
101 void Row::setSelection(pos_type beg, pos_type end) const
103 if (pos_ >= beg && pos_ <= end)
105 else if (beg > pos_ && beg <= end_)
110 if (end_ >= beg && end_ <= end)
112 else if (end < end_ && end >= pos_)
119 bool Row::selection() const
121 return sel_beg != -1 && sel_end != -1;
124 ostream & operator<<(ostream & os, Row const & row)
126 os << " pos: " << row.pos_ << " end: " << row.end_
127 << " width: " << row.dim_.wid
128 << " ascent: " << row.dim_.asc
129 << " descent: " << row.dim_.des << "\n";
130 Row::Elements::const_iterator it = row.elements_.begin();
131 for ( ; it != row.elements_.end() ; ++it) {
133 case Row::Element::STRING:
134 os << "**STRING: " << to_utf8(it->str) << endl;
136 case Row::Element::INSET:
137 os << "**INSET: " << to_utf8(it->inset->layoutName()) << endl;
139 case Row::Element::SEPARATOR:
140 os << "**SEPARATOR: " << endl;
142 case Row::Element::SPACE:
143 os << "**SPACE: " << it->dim.wid << endl;
151 bool Row::sameString(Font const & f, Change const & ch) const
153 if (elements_.empty())
155 Element const & elt = elements_.back();
156 return elt.type == Element::STRING && !elt.final
157 && elt.font == f && elt.change == ch;
161 void Row::finalizeLast()
163 if (elements_.empty())
165 Element & elt = elements_.back();
170 if (elt.type == Element::STRING) {
171 elt.dim.wid = theFontMetrics(elt.font).width(elt.str);
172 dim_.wid += elt.dim.wid;
177 void Row::add(pos_type const pos, Inset const * ins, Dimension const & dim,
178 Font const & f, Change const & ch)
181 Element e(Element::INSET, pos, f, ch);
184 elements_.push_back(e);
189 void Row::add(pos_type const pos, char_type const c,
190 Font const & f, Change const & ch)
192 if (!sameString(f, ch)) {
194 Element e(Element::STRING, pos, f, ch);
195 elements_.push_back(e);
197 //lyxerr << "FONT " <<back().font.language() << endl;
199 back().endpos = pos + 1;
203 void Row::add(pos_type const pos, docstring const & s,
204 Font const & f, Change const & ch)
206 if (!sameString(f, ch)) {
208 Element e(Element::STRING, pos, f, ch);
209 elements_.push_back(e);
212 back().endpos = pos + 1;
216 void Row::addSeparator(pos_type const pos, char_type const c,
217 Font const & f, Change const & ch)
220 Element e(Element::SEPARATOR, pos, f, ch);
222 e.dim.wid = theFontMetrics(f).width(c);
223 elements_.push_back(e);
224 dim_.wid += e.dim.wid;
228 void Row::addSpace(pos_type const pos, int const width,
229 Font const & f, Change const & ch)
232 Element e(Element::SEPARATOR, pos, f, ch);
234 elements_.push_back(e);
235 dim_.wid += e.dim.wid;
241 dim_.wid -= elements_.back().dim.wid;
242 elements_.pop_back();
246 void Row::separate_back(pos_type const keep)
250 int i = elements_.size();
252 int new_wid = dim_.wid;
253 if (i > 0 && elements_[i - 1].isLineSeparator() && new_end > keep) {
255 new_end = elements_[i].pos;
256 new_wid -= elements_[i].dim.wid;
259 while (i > 0 && !elements_[i - 1].isLineSeparator() && new_end > keep) {
261 new_end = elements_[i].pos;
262 new_wid -= elements_[i].dim.wid;
268 elements_.erase(elements_.begin() + i, elements_.end());
272 void Row::reverseRtL()
275 pos_type const end = elements_.size();
278 while (!elements_[i].font.isRightToLeft() && i < end)
283 // look for a RtL sequence
285 while (elements_[j].font.isRightToLeft() && j < end)
287 reverse(elements_.begin() + i, elements_.begin() + j);