lyx_mirror/src/frontends/xforms/LayoutEngine.C
Lars Gullik Bjønnes 1f9d992ce0 Make us satisfy concept checks
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@9260 a592a061-630c-0410-9148-cb99ea01b6c8
2004-11-16 20:41:38 +00:00

480 lines
8.4 KiB
C

// -*- C++ -*-
/**
* \file LayoutEngine.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Angus Leeming
*
* Full author contact details are available in file CREDITS.
*
* A generic layout engine.
*
* Draws heavily on the GTK+ files gtkbox.[ch], gtkhbox.[ch],
* for both inspiration and implementation,
* and from which this notice is taken:
*
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "LayoutEngine.h"
#include "lyx_forms.h"
#include <boost/assert.hpp>
#include <boost/bind.hpp>
using boost::bind;
using boost::shared_ptr;
using std::for_each;
namespace lyx {
namespace frontend {
bool BoxList::empty() const
{
return data_.empty();
}
BoxList::size_type BoxList::size() const
{
return data_.size();
}
void BoxList::clear()
{
data_.clear();
}
shared_ptr<Box> BoxList::push_back(Box const & box)
{
data_.push_back(shared_ptr<Box>(new Box(box)));
return data_.back();
}
BoxList::iterator BoxList::begin()
{
return data_.begin();
}
BoxList::iterator BoxList::end()
{
return data_.end();
}
BoxList::const_iterator BoxList::begin() const
{
return data_.begin();
}
BoxList::const_iterator BoxList::end() const
{
return data_.end();
}
BoxList::iterator BoxList::erase(iterator where)
{
return data_.erase(where);
}
BoxList::iterator BoxList::erase(iterator begin, iterator end)
{
return data_.erase(begin, end);
}
Box::Orientation Box::default_orientation_ = Box::Vertical;
Box::Packing Box::default_packing_ = Box::Shrink;
Box::Box(dimension_t min_w, dimension_t min_h)
: visible_(true),
min_w_(min_w),
min_h_(min_h),
w_(min_w),
h_(min_h),
x_(0),
y_(0),
orientation_(default_orientation_),
packing_(default_packing_),
prefered_visibility_(Visible)
{}
void Box::setMinimumDimensions(dimension_t min_w, dimension_t min_h)
{
min_w_ = min_w;
min_h_ = min_h;
}
Box::Orientation Box::orientation() const
{
return orientation_;
}
void Box::set(Orientation o)
{
orientation_ = o;
}
Box::Orientation Box::defaultOrientation()
{
return default_orientation_;
}
void Box::setDefault(Orientation o)
{
default_orientation_ = o;
}
Box::Packing Box::packing() const
{
return packing_;
}
void Box::set(Packing p)
{
packing_ = p;
}
Box::Packing Box::defaultPacking()
{
return default_packing_;
}
void Box::setDefault(Packing p)
{
default_packing_ = p;
}
bool Box::expandable() const
{
if (!visible_)
return false;
if (packing_ == Expand)
return true;
BoxList::const_iterator it = children_.begin();
BoxList::const_iterator const end = children_.end();
for (; it != end; ++it) {
if ((*it)->visible() && (*it)->packing() == Expand)
return true;
}
return false;
}
Box::PreferedVisibility Box::preferedVisibility() const
{
return prefered_visibility_;
}
void Box::set(PreferedVisibility pv)
{
prefered_visibility_ = pv;
if (pv == Invisible && visible_)
hide();
}
bool Box::visible() const
{
return visible_;
}
void Box::show()
{
if (prefered_visibility_ == Invisible)
return;
visible_ = true;
for_each(children_.begin(), children_.end(),
bind(&Box::show, _1));
}
void Box::hide()
{
visible_ = false;
for_each(children_.begin(), children_.end(),
bind(&Box::hide, _1));
}
BoxList & Box::children()
{
return children_;
}
BoxList const & Box::children() const
{
return children_;
}
Box::dimension_t Box::width() const
{
return w_;
}
Box::dimension_t Box::height() const
{
return h_;
}
Box::dimension_t Box::xorigin() const
{
return x_;
}
Box::dimension_t Box::yorigin() const
{
return y_;
}
void Box::updateMetrics()
{
shrinkMetrics();
expandMetrics(x_, y_, w_, h_);
}
void Box::shrinkMetrics()
{
dimension_t width = 0;
dimension_t height = 0;
BoxList::iterator it = children_.begin();
BoxList::iterator const end = children_.end();
for (; it != end; ++it) {
if (!(*it)->visible())
continue;
(*it)->shrinkMetrics();
dimension_t child_width = (*it)->width();
dimension_t child_height = (*it)->height();
if (orientation_ == Horizontal) {
width += child_width;
height = std::max(height, child_height);
} else {
width = std::max(width, child_width);
height += child_height;
}
}
w_ = visible_ ? std::max(min_w_, width) : 0;
h_ = visible_ ? std::max(min_h_, height) : 0;
}
void Box::expandMetrics(dimension_t x_in, dimension_t y_in,
dimension_t w_avail, dimension_t h_avail)
{
x_ = x_in;
y_ = y_in;
w_ = w_avail;
h_ = h_avail;
if (orientation_ == Vertical)
expandVbox(x_in, y_in, w_avail, h_avail);
else
expandHbox(x_in, y_in, w_avail, h_avail);
}
void Box::expandHbox(dimension_t x_in, dimension_t y_in,
dimension_t w_avail, dimension_t h_avail)
{
int nvisible_children = 0;
int nexpanded_children = 0;
dimension_t w_fixed = 0;
BoxList::const_iterator cit = children_.begin();
BoxList::const_iterator const cend = children_.end();
for (; cit != cend; ++cit) {
if ((*cit)->visible()) {
nvisible_children += 1;
if ((*cit)->expandable())
nexpanded_children += 1;
else
w_fixed += (*cit)->width();
}
}
if (nvisible_children == 0)
return;
dimension_t width = 0;
dimension_t extra = 0;
if (nexpanded_children > 0) {
width = w_avail - w_fixed;
extra = width / nexpanded_children;
}
dimension_t x_child = x_in;
dimension_t y_child = y_in;
dimension_t h_child = h_avail;
BoxList::iterator it = children_.begin();
BoxList::iterator const end = children_.end();
for (; it != end; ++it) {
if (!(*it)->visible())
continue;
dimension_t w_child = (*it)->width();
if ((*it)->expandable()) {
if (nexpanded_children == 1)
w_child = std::max(w_child, width);
else
w_child = std::max(w_child, extra);
nexpanded_children -= 1;
width -= w_child;
}
(*it)->expandMetrics(x_child, y_child, w_child, h_child);
x_child += w_child;
}
}
void Box::expandVbox(dimension_t x_in, dimension_t y_in,
dimension_t w_avail, dimension_t h_avail)
{
int nvisible_children = 0;
int nexpanded_children = 0;
dimension_t h_fixed = 0;
BoxList::const_iterator cit = children_.begin();
BoxList::const_iterator const cend = children_.end();
for (; cit != cend; ++cit) {
if ((*cit)->visible()) {
nvisible_children += 1;
if ((*cit)->expandable())
nexpanded_children += 1;
else
h_fixed += (*cit)->height();
}
}
if (nvisible_children == 0)
return;
dimension_t height = 0;
dimension_t extra = 0;
if (nexpanded_children > 0) {
height = h_avail - h_fixed;
extra = height / nexpanded_children;
}
dimension_t x_child = x_in;
dimension_t y_child = y_in;
dimension_t w_child = w_avail;
BoxList::iterator it = children_.begin();
BoxList::iterator const end = children_.end();
for (; it != end; ++it) {
if (!(*it)->visible())
continue;
dimension_t h_child = (*it)->height();
if ((*it)->expandable()) {
if (nexpanded_children == 1)
h_child = std::max(h_child, height);
else
h_child = std::max(h_child, extra);
nexpanded_children -= 1;
height -= h_child;
}
(*it)->expandMetrics(x_child, y_child, w_child, h_child);
y_child += h_child;
}
}
shared_ptr<Box> WidgetMap::add(FL_OBJECT * ob, BoxList & container,
dimension_t min_w, dimension_t min_h)
{
shared_ptr<Box> box = container.push_back(Box(min_w, min_h));
widgets_[ob] = box;
return box;
}
void WidgetMap::updateMetrics() const
{
DataMap::const_iterator it = widgets_.begin();
DataMap::const_iterator const end = widgets_.end();
for (; it != end; ++it) {
FL_OBJECT * ob = it->first;
Box & box = *it->second;
if (box.visible()) {
fl_set_object_geometry(ob,
box.xorigin(), box.yorigin(),
box.width(), box.height());
if (!ob->visible)
fl_show_object(ob);
} else {
if (ob->visible)
fl_hide_object(ob);
}
}
}
shared_ptr<Box>
embed(FL_OBJECT * ob, BoxList & container, WidgetMap & widgets, int bw)
{
container.push_back(Box(0, bw));
shared_ptr<Box> middle = container.push_back(Box(0, 0));
middle->set(Box::Horizontal);
container.push_back(Box(0, bw));
middle->children().push_back(Box(bw, 0));
shared_ptr<Box> center = widgets.add(ob, middle->children(), 0, 0);
middle->children().push_back(Box(bw, 0));
return center;
}
} // namespace frontend
} // namespace lyx