]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/LayoutEngine.C
fix math fonts with LyX/Mac
[lyx.git] / src / frontends / xforms / LayoutEngine.C
1 // -*- C++ -*-
2 /**
3  * \file LayoutEngine.C
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Angus Leeming
8  *
9  * Full author contact details are available in file CREDITS.
10  *
11  * A generic layout engine.
12  *
13  * Draws heavily on the GTK+ files gtkbox.[ch], gtkhbox.[ch],
14  * for both inspiration and implementation,
15  * and from which this notice is taken:
16  *
17  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
18  *
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24
25 #include "LayoutEngine.h"
26 #include "lyx_forms.h"
27 #include <boost/assert.hpp>
28
29
30 namespace lyx {
31 namespace frontend {
32
33
34 bool BoxList::empty() const
35 {
36         return data_.empty();
37 }
38
39
40 BoxList::size_type BoxList::size() const
41 {
42         return data_.size();
43 }
44
45
46 void BoxList::clear()
47 {
48         data_.clear();
49 }
50
51
52 Box & BoxList::push_back(Box const & box)
53 {
54         data_.push_back(box);
55         return data_.back();
56 }
57
58
59 BoxList::iterator BoxList::begin()
60 {
61         return data_.begin();
62 }
63
64
65 BoxList::iterator BoxList::end()
66 {
67         return data_.end();
68 }
69
70
71 BoxList::const_iterator BoxList::begin() const
72 {
73         return data_.begin();
74 }
75
76
77 BoxList::const_iterator BoxList::end() const
78 {
79         return data_.end();
80 }
81
82
83 BoxList::iterator BoxList::erase(iterator where)
84 {
85         return data_.erase(where);
86 }
87
88
89 BoxList::iterator BoxList::erase(iterator begin, iterator end)
90 {
91         return data_.erase(begin, end);
92 }
93
94
95 Box::Orientation Box::default_orientation_ = Box::Vertical;
96 Box::Packing Box::default_packing_ = Box::Shrink;
97
98
99 Box::Box(dimension_t min_w, dimension_t min_h)
100         : visible_(true),
101           min_w_(min_w),
102           min_h_(min_h),
103           w_(min_w),
104           h_(min_h),
105           x_(0),
106           y_(0),
107           orientation_(default_orientation_),
108           packing_(default_packing_),
109           prefered_visibility_(Visible)
110 {}
111
112
113 void Box::setMinimumDimensions(dimension_t min_w, dimension_t min_h)
114 {
115         min_w_ = min_w;
116         min_h_ = min_h;
117 }
118
119
120 Box::Orientation Box::orientation() const
121 {
122         return orientation_;
123 }
124
125
126 void Box::set(Orientation o)
127 {
128         orientation_ = o;
129 }
130
131
132 Box::Orientation Box::defaultOrientation()
133 {
134         return default_orientation_;
135 }
136
137
138 void Box::setDefault(Orientation o)
139 {
140         default_orientation_ = o;
141 }
142
143
144 Box::Packing Box::packing() const
145 {
146         return packing_;
147 }
148
149
150 void Box::set(Packing p)
151 {
152         packing_ = p;
153 }
154
155
156 Box::Packing Box::defaultPacking()
157 {
158         return default_packing_;
159 }
160
161
162 void Box::setDefault(Packing p)
163 {
164         default_packing_ = p;
165 }
166
167
168 bool Box::expandable() const
169 {
170         if (!visible_)
171                 return false;
172
173         if (packing_ == Expand)
174                 return true;
175
176         BoxList::const_iterator it = children_.begin();
177         BoxList::const_iterator const end = children_.end();
178         for (; it != end; ++it) {
179                 if (it->visible() && it->packing() == Expand)
180                         return true;
181         }
182
183         return false;
184 }
185
186
187 Box::PreferedVisibility Box::preferedVisibility() const
188 {
189         return prefered_visibility_;
190 }
191
192
193 void Box::set(PreferedVisibility pv)
194 {
195         prefered_visibility_ = pv;
196         if (pv == Invisible && visible_)
197                 hide();
198 }
199
200
201 bool Box::visible() const
202 {
203         return visible_;
204 }
205
206
207 void Box::show()
208 {
209         if (prefered_visibility_ == Invisible)
210                 return;
211
212         visible_ = true;
213
214         BoxList::iterator it = children_.begin();
215         BoxList::iterator const end = children_.end();
216         for (; it != end; ++it)
217                 it->show();
218 }
219
220
221 void Box::hide()
222 {
223         visible_ = false;
224
225         BoxList::iterator it = children_.begin();
226         BoxList::iterator const end = children_.end();
227         for (; it != end; ++it)
228                 it->hide();
229 }
230
231
232 BoxList & Box::children()
233 {
234         return children_;
235 }
236
237
238 BoxList const & Box::children() const
239 {
240         return children_;
241 }
242
243
244 Box::dimension_t Box::width() const
245 {
246         return w_;
247 }
248
249
250 Box::dimension_t Box::height() const
251 {
252         return h_;
253 }
254
255
256 Box::dimension_t Box::xorigin() const
257 {
258         return x_;
259 }
260
261
262 Box::dimension_t Box::yorigin() const
263 {
264         return y_;
265 }
266
267
268 void Box::updateMetrics()
269 {
270         shrinkMetrics();
271         expandMetrics(x_, y_, w_, h_);
272 }
273
274
275 void Box::shrinkMetrics()
276 {
277         dimension_t width = 0;
278         dimension_t height = 0;
279
280         BoxList::iterator it = children_.begin();
281         BoxList::iterator const end = children_.end();
282         for (; it != end; ++it) {
283                 if (!it->visible())
284                         continue;
285
286                 it->shrinkMetrics();
287                 dimension_t child_width = it->width();
288                 dimension_t child_height = it->height();
289
290                 if (orientation_ == Horizontal) {
291                         width += child_width;
292                         height = std::max(height, child_height);
293                 } else {
294                         width = std::max(width, child_width);
295                         height += child_height;
296                 }
297         }
298
299         w_ = visible_ ? std::max(min_w_, width) : 0;
300         h_ = visible_ ? std::max(min_h_, height) : 0;
301 }
302
303
304 void Box::expandMetrics(dimension_t x_in, dimension_t y_in,
305                         dimension_t w_avail, dimension_t h_avail)
306 {
307         x_ = x_in;
308         y_ = y_in;
309         w_ = w_avail;
310         h_ = h_avail;
311
312         if (orientation_ == Vertical)
313                 expandVbox(x_in, y_in, w_avail, h_avail);
314         else
315                 expandHbox(x_in, y_in, w_avail, h_avail);
316 }
317
318
319 void Box::expandHbox(dimension_t x_in, dimension_t y_in,
320                      dimension_t w_avail, dimension_t h_avail)
321 {
322         int nvisible_children = 0;
323         int nexpanded_children = 0;
324         dimension_t w_fixed = 0;
325
326         BoxList::const_iterator cit = children_.begin();
327         BoxList::const_iterator const cend = children_.end();
328         for (; cit != cend; ++cit) {
329                 if (cit->visible()) {
330                         nvisible_children += 1;
331                         if (cit->expandable())
332                                 nexpanded_children += 1;
333                         else
334                                 w_fixed += cit->width();
335                 }
336         }
337
338         if (nvisible_children == 0)
339                 return;
340
341         dimension_t width = 0;
342         dimension_t extra = 0;
343         if (nexpanded_children > 0) {
344                 width = w_avail - w_fixed;
345                 extra = width / nexpanded_children;
346         }
347
348         dimension_t x_child = x_in;
349         dimension_t y_child = y_in;
350         dimension_t h_child = h_avail;
351
352         BoxList::iterator it = children_.begin();
353         BoxList::iterator const end = children_.end();
354         for (; it != end; ++it) {
355                 if (!it->visible())
356                         continue;
357
358                 dimension_t w_child = it->width();
359                 if (it->expandable()) {
360                         if (nexpanded_children == 1)
361                                 w_child = std::max(w_child, width);
362                         else
363                                 w_child = std::max(w_child, extra);
364
365                         nexpanded_children -= 1;
366                         width -= w_child;
367                 }
368
369                 it->expandMetrics(x_child, y_child, w_child, h_child);
370                 x_child += w_child;
371         }
372 }
373
374
375 void Box::expandVbox(dimension_t x_in, dimension_t y_in,
376                      dimension_t w_avail, dimension_t h_avail)
377 {
378         int nvisible_children = 0;
379         int nexpanded_children = 0;
380         dimension_t h_fixed = 0;
381
382         BoxList::const_iterator cit = children_.begin();
383         BoxList::const_iterator const cend = children_.end();
384         for (; cit != cend; ++cit) {
385                 if (cit->visible()) {
386                         nvisible_children += 1;
387                         if (cit->expandable())
388                                 nexpanded_children += 1;
389                         else
390                                 h_fixed += cit->height();
391                 }
392         }
393
394         if (nvisible_children == 0)
395                 return;
396
397         dimension_t height = 0;
398         dimension_t extra = 0;
399         if (nexpanded_children > 0) {
400                 height = h_avail - h_fixed;
401                 extra = height / nexpanded_children;
402         }
403
404         dimension_t x_child = x_in;
405         dimension_t y_child = y_in;
406         dimension_t w_child = w_avail;
407
408         BoxList::iterator it = children_.begin();
409         BoxList::iterator const end = children_.end();
410         for (; it != end; ++it) {
411                 if (!it->visible())
412                         continue;
413
414                 dimension_t h_child = it->height();
415                 if (it->expandable()) {
416                         if (nexpanded_children == 1)
417                                 h_child = std::max(h_child, height);
418                         else
419                                 h_child = std::max(h_child, extra);
420                         nexpanded_children -= 1;
421                         height -= h_child;
422                 }
423
424                 it->expandMetrics(x_child, y_child, w_child, h_child);
425                 y_child += h_child;
426         }
427 }
428
429
430 Box & WidgetMap::add(FL_OBJECT * ob, BoxList & container,
431                      dimension_t min_w, dimension_t min_h)
432 {
433         Box & box = container.push_back(Box(min_w, min_h));
434         widgets_[ob] = &box;
435         return box;
436 }
437
438
439 void WidgetMap::updateMetrics() const
440 {
441         DataMap::const_iterator it = widgets_.begin();
442         DataMap::const_iterator const end = widgets_.end();
443         for (; it != end; ++it) {
444                 FL_OBJECT * ob = it->first;
445                 Box & box = *it->second;
446
447                 if (box.visible()) {
448                         fl_set_object_geometry(ob,
449                                                box.xorigin(), box.yorigin(),
450                                                box.width(), box.height());
451                         if (!ob->visible)
452                                 fl_show_object(ob);
453                 } else {
454                         if (ob->visible)
455                                 fl_hide_object(ob);
456                 }
457         }
458 }
459
460
461 Box & embed(FL_OBJECT * ob, BoxList & container, WidgetMap & widgets, int bw)
462 {
463         container.push_back(Box(0, bw));
464         Box & middle = container.push_back(Box(0, 0));
465         middle.set(Box::Horizontal);
466         container.push_back(Box(0, bw));
467
468         middle.children().push_back(Box(bw, 0));
469         Box & center = widgets.add(ob, middle.children(), 0, 0);
470         middle.children().push_back(Box(bw, 0));
471
472         return center;
473 }
474
475 } // namespace frontend
476 } // namespace lyx