]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parboxinset.C
some \parbox improvements
[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) const
69 {
70         // try to move only one screen row up or down if possible
71         int row = pos2row(pos);
72         int const x = cells_[idx].pos2x(rows_[row].begin, pos, rows_[row].glue);
73         if (up) {
74                 if (row == 0)
75                         return false;
76                 --row;
77         } else {
78                 ++row;
79                 if (row == screenrows())
80                         return false;
81         }
82         pos = xcell(0).x2pos(rows_[row].begin, x, rows_[row].glue);
83         return true;
84 }
85
86
87 void MathParboxInset::metrics(MathMetricsInfo & mi) const
88 {
89         MathFontSetChanger dummy(mi.base, "textnormal");
90
91         // we do our own metrics fiddling
92         // delete old cache
93         rows_.clear();
94
95 #if 0
96
97         dim_ = xcell(0).metrics(mi);
98
99 #else
100
101         vector<Dimension> dims; 
102         xcell(0).metricsExternal(mi, dims);
103
104         int spaces = 0;
105         Dimension safe;
106         Dimension curr;
107         safe.clear(mi.base.font);
108         curr.clear(mi.base.font);
109         int begin = 0;
110         int safepos = 0;
111         int yo = 0;
112         for (size_type i = 0, n = cell(0).size(); i < n; ++i) {
113                 //lyxerr << "at pos: " << i << " of " << n << " safepos: " << safepos
114                 //      << " curr: " << curr << " safe: " << safe
115                 //      << " spaces: " << spaces << endl;
116
117
118                 //   0      1      2      3       4      5      6
119                 // <char> <char> <char> <space> <char> <char> <char>
120                 // ................... <safe>
121                 //                      ..........................<curr>
122                 // ....................<safepos>
123
124                 // Special handling of spaces. We reached a safe position for breaking.
125                 if (cell(0)[i]->getChar() == ' ') {
126                         //lyxerr << "reached safe pos\n";
127                         // we don't count the space into the safe pos
128                         safe += curr;
129                         // we reset to this safepos if the next chunk does not fit
130                         safepos = i;
131                         ++spaces;
132                         // restart chunk with size of the space
133                         curr.clear(mi.base.font);
134                         curr += dims[i];
135                         continue;
136                 }
137
138                 // This is a regular char. Go on if we either don't care for
139                 // the width limit or have not reached that limit.
140                 curr += dims[i];
141                 if (curr.w + safe.w <= lyx_width_) 
142                         continue;
143
144                 // We passed the limit. Create a row entry.
145                 //lyxerr << "passed limit\n";
146                 MathXArray::Row row;
147                 if (spaces) {
148                         // but we had a space break before this position.
149                         // so retreat to this position
150                         int glue  = lyx_width_ - safe.w + dims[safepos].w;
151                         row.dim   = safe;
152                         row.glue  = glue / spaces;
153                         row.begin = begin;
154                         row.end   = safepos;  // this is position of the safe space
155                         i         = safepos;  // i gets incremented at end of loop
156                         begin     = i + 1;    // next chunk starts after the space
157                         //lyxerr << "... but had safe pos. glue: " << row.glue << "\n";
158                         //lyxerr << " safe.w: " << safe.w
159                         //      << "  dim.w: " << dims[safepos].w << " spaces: " << spaces << "\n";
160                         spaces   = 0;
161                 } else {
162                         lyxerr << "... without safe pos\n";
163                         // This item is too large and it is the only one.
164                         // We have no choice but to produce an overfull box.
165                         row.dim   = curr;   // safe should be 0.
166                         row.glue  = 0;      // does not matter
167                         row.begin = begin;
168                         row.end   = i + 1;
169                         begin     = i + 1;
170                 }
171                 row.yo   = yo;
172                 yo      += row.dim.height();
173                 rows_.push_back(row);
174                 // in any case, start the new row with empty boxes
175                 curr.clear(mi.base.font);
176                 safe.clear(mi.base.font);
177         }
178         // last row: put in everything else
179         MathXArray::Row row;
180         row.dim   = safe;
181         row.dim  += curr;
182         row.begin = begin;
183         row.end   = cell(0).size();
184         row.glue  = 0; // last line is left aligned
185         row.yo    = yo;
186         rows_.push_back(row);
187
188         // what to report?
189         dim_.w = lyx_width_;
190         dim_.a = rows_.front().dim.a;
191         dim_.d = rows_.back().dim.d + yo;
192         metricsMarkers();
193         xcell(0).setDim(dim_);
194 #endif
195 }
196
197
198 void MathParboxInset::draw(MathPainterInfo & pi, int x, int y) const
199 {
200         MathFontSetChanger dummy(pi.base, "textnormal");
201 #if 0
202         xcell(0).draw(pi, x + 1, y);
203 #else
204         xcell(0).drawExternal(pi, x + 1, y, rows_);
205 #endif
206         drawMarkers(pi, x, y);
207 }
208
209
210 void MathParboxInset::write(WriteStream & os) const
211 {
212         os << "\\parbox";
213         if (position_ != 'c')
214                 os << '[' << position_ << ']';
215         os << '{' << tex_width_ << "}{" << cell(0) << '}';
216 }
217
218
219 void MathParboxInset::infoize(std::ostream & os) const
220 {
221         os << "Box: Parbox " << tex_width_;
222 }
223