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