]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parboxinset.C
the up/down stuff reworked
[lyx.git] / src / mathed / math_parboxinset.C
1
2 #include "math_parboxinset.h"
3 #include "math_mathmlstream.h"
4 #include "math_streamstr.h"
5 #include "lyxlength.h"
6 #include "debug.h"
7
8 using std::vector;
9
10 MathParboxInset::MathParboxInset()
11         : MathNestInset(1), lyx_width_(0), tex_width_("0mm"),
12           position_('c')
13 {
14         lyxerr << "constructing MathParboxInset\n";
15 }
16
17
18 MathInset * MathParboxInset::clone() const
19 {
20         return new MathParboxInset(*this);
21 }
22
23
24 void MathParboxInset::setPosition(string const & p)
25 {
26         position_ = p.size() > 0 ? p[0] : 'c';
27 }
28
29
30 void MathParboxInset::setWidth(string const & w)
31 {
32         tex_width_ = w;
33         lyx_width_ = LyXLength(w).inBP();
34         lyxerr << "setting " << w << " to " << lyx_width_ << " pixel\n";
35 }
36
37
38 int MathParboxInset::screenrows() const
39 {
40         return rows_.size();
41 }
42
43
44 int MathParboxInset::pos2row(pos_type pos) const
45 {
46         for (int r = 0, n = rows_.size(); r < n; ++r) 
47                 if (pos >= rows_[r].begin && pos <= rows_[r].end)
48                         return r;
49         lyxerr << "illegal row for pos " << pos << "\n";
50         return 0;
51 }
52
53
54 void MathParboxInset::getPos(idx_type idx, pos_type pos, int & x, int & y) const
55 {
56         int const r = pos2row(pos);
57         MathXArray const & ar = cells_[idx];
58         x = ar.xo() + ar.pos2x(rows_[r].begin, pos, rows_[r].glue);
59         y = ar.yo() + rows_[r].yo;
60         // move cursor visually into empty cells ("blue rectangles");
61         if (cell(0).empty())
62                 x += 2;
63         //lyxerr << "getPos cursor at pos " << pos << " in row " << r
64         //      << "  x: " << x << " y: " << y << "\n";
65 }
66
67
68 bool MathParboxInset::idxUpDown(idx_type & idx, pos_type & pos, bool up,
69         int targetx) const
70 {
71         // try to move only one screen row up or down if possible
72         int row = pos2row(pos);
73         int const x = cells_[idx].pos2x(rows_[row].begin, pos, rows_[row].glue);
74         if (up) {
75                 if (row == 0)
76                         return false;
77                 --row;
78         } else {
79                 ++row;
80                 if (row == screenrows())
81                         return false;
82         }
83         pos = xcell(0).x2pos(rows_[row].begin, x, rows_[row].glue);
84         return true;
85 }
86
87
88 void MathParboxInset::metrics(MathMetricsInfo & mi) const
89 {
90         MathFontSetChanger dummy(mi.base, "textnormal");
91
92         // we do our own metrics fiddling
93         // delete old cache
94         rows_.clear();
95
96 #if 0
97
98         dim_ = xcell(0).metrics(mi);
99
100 #else
101
102         vector<Dimension> dims; 
103         xcell(0).metricsExternal(mi, dims);
104
105         int spaces = 0;
106         Dimension safe;
107         Dimension curr;
108         safe.clear(mi.base.font);
109         curr.clear(mi.base.font);
110         int begin = 0;
111         int safepos = 0;
112         int yo = 0;
113         for (size_type i = 0, n = cell(0).size(); i < n; ++i) {
114                 //lyxerr << "at pos: " << i << " of " << n << " safepos: " << safepos
115                 //      << " curr: " << curr << " safe: " << safe
116                 //      << " spaces: " << spaces << endl;
117
118
119                 //   0      1      2      3       4      5      6
120                 // <char> <char> <char> <space> <char> <char> <char>
121                 // ................... <safe>
122                 //                      ..........................<curr>
123                 // ....................<safepos>
124
125                 // Special handling of spaces. We reached a safe position for breaking.
126                 if (cell(0)[i]->getChar() == ' ') {
127                         //lyxerr << "reached safe pos\n";
128                         // we don't count the space into the safe pos
129                         safe += curr;
130                         // we reset to this safepos if the next chunk does not fit
131                         safepos = i;
132                         ++spaces;
133                         // restart chunk with size of the space
134                         curr.clear(mi.base.font);
135                         curr += dims[i];
136                         continue;
137                 }
138
139                 // This is a regular char. Go on if we either don't care for
140                 // the width limit or have not reached that limit.
141                 curr += dims[i];
142                 if (curr.w + safe.w <= lyx_width_) 
143                         continue;
144
145                 // We passed the limit. Create a row entry.
146                 //lyxerr << "passed limit\n";
147                 MathXArray::Row row;
148                 if (spaces) {
149                         // but we had a space break before this position.
150                         // so retreat to this position
151                         int glue  = lyx_width_ - safe.w + dims[safepos].w;
152                         row.dim   = safe;
153                         row.glue  = glue / spaces;
154                         row.begin = begin;
155                         row.end   = safepos;  // this is position of the safe space
156                         i         = safepos;  // i gets incremented at end of loop
157                         begin     = i + 1;    // next chunk starts after the space
158                         //lyxerr << "... but had safe pos. glue: " << row.glue << "\n";
159                         //lyxerr << " safe.w: " << safe.w
160                         //      << "  dim.w: " << dims[safepos].w << " spaces: " << spaces << "\n";
161                         spaces   = 0;
162                 } else {
163                         lyxerr << "... without safe pos\n";
164                         // This item is too large and it is the only one.
165                         // We have no choice but to produce an overfull box.
166                         row.dim   = curr;   // safe should be 0.
167                         row.glue  = 0;      // does not matter
168                         row.begin = begin;
169                         row.end   = i + 1;
170                         begin     = i + 1;
171                 }
172                 row.yo   = yo;
173                 yo      += row.dim.height();
174                 rows_.push_back(row);
175                 // in any case, start the new row with empty boxes
176                 curr.clear(mi.base.font);
177                 safe.clear(mi.base.font);
178         }
179         // last row: put in everything else
180         MathXArray::Row row;
181         row.dim   = safe;
182         row.dim  += curr;
183         row.begin = begin;
184         row.end   = cell(0).size();
185         row.glue  = 0; // last line is left aligned
186         row.yo    = yo;
187         rows_.push_back(row);
188
189         // what to report?
190         dim_.w = lyx_width_;
191         dim_.a = rows_.front().dim.a;
192         dim_.d = rows_.back().dim.d + yo;
193         metricsMarkers2();
194         xcell(0).setDim(dim_);
195 #endif
196 }
197
198
199 void MathParboxInset::draw(MathPainterInfo & pi, int x, int y) const
200 {
201         MathFontSetChanger dummy(pi.base, "textnormal");
202 #if 0
203         xcell(0).draw(pi, x + 1, y);
204 #else
205         xcell(0).drawExternal(pi, x + 1, y, rows_);
206 #endif
207         drawMarkers2(pi, x, y);
208 }
209
210
211 void MathParboxInset::drawSelection(MathPainterInfo & pi,
212                 idx_type, pos_type pos1, idx_type, pos_type pos2) const
213 {
214         int row1 = pos2row(pos1);
215         int row2 = pos2row(pos2);
216         if (row1 == row2) {
217 /*
218                 MathXArray & c = xcell(0);
219                 int x1 = c.xo() + c.pos2x(i1.pos_);
220                 int y1 = c.yo() - c.ascent();
221                 int x2 = c.xo() + c.pos2x(i2.pos_);
222                 int y2 = c.yo() + c.descent();
223                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
224         } else {
225                 vector<MathInset::idx_type> indices = idxBetween(idx1, idx2);
226                 for (unsigned i = 0; i < indices.size(); ++i) {
227                         MathXArray & c = i1.xcell(indices[i]);
228                         int x1 = c.xo();
229                         int y1 = c.yo() - c.ascent();
230                         int x2 = c.xo() + c.width();
231                         int y2 = c.yo() + c.descent();
232                         pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
233                 }
234 */
235         }
236 }
237
238
239 void MathParboxInset::write(WriteStream & os) const
240 {
241         os << "\\parbox";
242         if (position_ != 'c')
243                 os << '[' << position_ << ']';
244         os << '{' << tex_width_ << "}{" << cell(0) << '}';
245 }
246
247
248 void MathParboxInset::infoize(std::ostream & os) const
249 {
250         os << "Box: Parbox " << tex_width_;
251 }
252