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