layout.h

Go to the documentation of this file.
00001 /*
00002   libwt - Vassilis Virvilis Toolkit - a widget library
00003   Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm>
00004  
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009   
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014   
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the
00017   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018   Boston, MA  02111-1307, SA.
00019 */
00020 
00021 #ifndef WT_LAYOUT_H
00022 #define WT_LAYOUT_H
00023 
00024 #include <wt/object.h>
00025 #include <wt/wvar.h>
00026 #include <wt/sizepolicy.h>
00027 #include <wt/size.h>
00028 #include <wt/rect.h>
00029 #include <wt/trace.h>
00030 #include <wt/flags.h>
00031 
00032 namespace Wt {
00033 
00034 class LayoutItem;
00035 class Widget;
00036 class LayoutHintEvent;
00037 
00038 /*
00039 We cannot possibly split the design to ContainerInterface and IteratorInterface
00040 because we can't return Iterator* from std containers
00041 */
00042 class LayoutIteratorInterface {
00043 public:
00044     virtual ~LayoutIteratorInterface() {}
00045     virtual LayoutItem* operator*() const = 0;
00046     virtual bool operator!=(const LayoutIteratorInterface& other) const = 0;
00047     bool operator==(const LayoutIteratorInterface& other) const {
00048         return !(**this != *other);
00049     }
00050     //postfix only
00051     virtual LayoutIteratorInterface& operator++(int) = 0;
00052 
00053     // we bastardize iterator and container here
00054     virtual void start() = 0;
00055     virtual bool finish() = 0;
00056     virtual LayoutItem* pop() = 0;
00057 };
00058 
00059 class NullLayoutIterator : public LayoutIteratorInterface {
00060 public:
00061     virtual LayoutItem* operator*() const {
00062         return 0;
00063     }
00064     virtual bool operator!=(const LayoutIteratorInterface&) const {
00065         return false;
00066     }
00067     //postfix only
00068     virtual NullLayoutIterator& operator++(int) {
00069         return *this;
00070     }
00071 
00072     // we bastardize iterator and container here
00073     virtual void start() {}
00074     virtual bool finish() {
00075         return true;
00076     }
00077     virtual LayoutItem* pop() {
00078         return 0;
00079     }
00080 };
00081 
00082 class LayoutIterator {
00083 public:
00084     /// we cannot avoid the pointer here since we need the virtualized behaviour
00085     LayoutIterator(LayoutIteratorInterface * li) :
00086     li_(li) {}
00087     ~LayoutIterator () {
00088         delete li_;
00089     }
00090     LayoutItem* operator*() const {
00091         return **li_;
00092     }
00093     LayoutIterator operator=(const LayoutIterator &i) {
00094         return li_ = i.li_;
00095     }
00096     bool operator!=(const LayoutIteratorInterface& other) const {
00097         return (**li_ != *other);
00098     }
00099     //postfix only
00100     LayoutIterator& operator++(int) {
00101         (*li_)++;
00102         return *this;
00103     }
00104     // we bastardize iterator and container here
00105     void start() {
00106         return li_->start();
00107     }
00108     bool finish() {
00109         return li_->finish();
00110     }
00111     LayoutItem* pop() {
00112         return li_->pop();
00113     }
00114 
00115 private:
00116     LayoutIteratorInterface *li_;
00117 };
00118 
00119 /// all layoutItems should inherit from this. It's their interface
00120 /*!
00121 The following functions must be reimplemented
00122  - setGeometry()
00123  - isEmpty() const;
00124  - hasHeightForWidth()
00125  - heightForWidth()
00126  - iterator()
00127 */
00128 class LayoutItem {
00129 public:
00130     LayoutItem(int alignment = AlignAuto,
00131                const SizePolicy& size_policy = SizePolicy(),
00132                const Size& size_hint = Size(default_hint_size, default_hint_size),
00133                const Size& minimum_size = Size(default_min_size, default_min_size),
00134                const Size& maximum_size = Size(default_max_size, default_max_size)) :
00135             alignment(alignment),
00136             invalidated_(true),
00137             size_policy_(size_policy),
00138             size_hint_(size_hint),
00139             minimum_size_(minimum_size),
00140     maximum_size_(maximum_size) {}
00141 
00142     virtual ~LayoutItem() {}
00143 
00144     virtual Size sizeHint() const {
00145         return size_hint_;
00146     }
00147 
00148     virtual Size minimumSize() const {
00149         return minimum_size_;
00150     }
00151     virtual void setMinimumSize(const Size& size) {
00152         minimum_size_ = size;
00153     }
00154 
00155     virtual Size maximumSize() const {
00156         return maximum_size_;
00157     }
00158     virtual void setMaximumSize(const Size& size) {
00159         maximum_size_ = size;
00160     }
00161 
00162     virtual SizePolicy sizePolicy() const {
00163         return size_policy_;
00164     }
00165 
00166     virtual void setSizePolicy(const SizePolicy& size_policy) {
00167         size_policy_ = size_policy;
00168     }
00169 
00170     virtual SizePolicy::ExpandData expanding() const {
00171         return size_policy_.expandData;
00172     }
00173 
00174     /// return the widget's geometry relative to its parent
00175     virtual const Rect& geometry() const {
00176         return geometry_rect_;
00177     }
00178 
00179     //  --- necessary interface --- default implementations
00180     virtual void setGeometry(const Rect& r) {
00181         geometry_rect_ = r;
00182     }
00183 
00184     virtual bool isEmpty() const {
00185         return false;
00186     }
00187 
00188     bool isNonEmpty() const {
00189         return (this) ? !isEmpty() : false;
00190     }
00191 
00192     virtual bool hasHeightForWidth() const {
00193         return false;
00194     }
00195     virtual int heightForWidth(int) const {
00196         return -1;
00197     }
00198 
00199     virtual LayoutIterator iterator() {
00200         return LayoutIterator(new NullLayoutIterator());
00201     }
00202 
00203     template<typename TEST_TYPE>
00204     TEST_TYPE type() const {
00205         return dynamic_cast<TEST_TYPE>(const_cast<LayoutItem *>(this));
00206     }
00207 
00208     template<typename TEST_TYPE>
00209     bool is() const {
00210         return (type<TEST_TYPE>() != 0);
00211     }
00212 
00213     // sensible defaults
00214     static const int default_max_size = ((int) ((unsigned int) (~0) >> 1));
00215     static const int default_min_size = 30;
00216     static const int default_hint_size = 100;
00217 
00218     WVar<int> alignment;
00219 
00220 protected:
00221     void invalidateRecursively();
00222 
00223     virtual void validate() {
00224         invalidated_ = false;
00225     }
00226 
00227     bool invalidated() const {
00228         return invalidated_;
00229     }
00230 
00231     virtual void setSizeHint(const Size& size) {
00232         size_hint_ = size;
00233     }
00234 
00235 private:
00236     bool invalidated_;
00237     SizePolicy size_policy_;
00238     Size size_hint_;
00239     Size minimum_size_;
00240     Size maximum_size_;
00241     Rect geometry_rect_;
00242 };
00243 
00244 /// handles the layout of widgets
00245 /*!
00246 The Layout class takes ownership of child layouts (Objects),
00247 and other layoutitems that are not widgets. Widgets have their
00248 own ierarchy and so a Layout absolutely does not delete Widgets,
00249 in any way.
00250  
00251 Layouts will be deleted when the parent layout dies or when they
00252 are explictely deleted. The rest of the layout items (spacer)
00253 will be deleted on Layout::remove() and/or ~Layout().
00254  
00255 In the mean time however, we keep track of all these pointers into
00256 our container layout and layout actively syncronizes the list when
00257 a child is deleted.
00258  
00259 In short: Layout contains LayoutItems. LayoutItems can be Layouts,
00260 Widgets and Spacers. Layouts are also children to parent Layout.
00261  
00262                       Layout Widgets Spacer
00263 Deleted on remove       y       n      y
00264 Deleted on ~Layout      y       n      y
00265 removed on deletion     y       y      *
00266  
00267 * don't do that. That objects are now belong to Layout and cannot
00268 be deleted safely since they are not Objects. If you want them to
00269 be deleted remove them from the Layout via Layout::remove()
00270  
00271 */
00272 class Layout : public Object, public LayoutItem {
00273 public:
00274     Layout(Widget *parent, int margin = 0, int spacing = -1,
00275            const std::string &name = "Layout::anon");
00276     Layout(Layout * parentLayout, int margin = 0, int spacing = -1,
00277            const std::string &name = "Layout::anon");
00278     Layout(int spacing = -1, const std::string &name = "Layout::anon");
00279     virtual ~Layout() {
00280         Layout *l = dynamic_cast<Layout *>(parent());
00281         if (l) {
00282             l->markDeleted(this);
00283             l->removeItem(this);
00284         }
00285     }
00286 
00287     Widget *mainWidget() const;
00288     bool isTopLevel() const;
00289 
00290     virtual Size sizeHint() const;
00291     virtual Size minimumSize() const;
00292     // The reason we need this if Layout parent is a Layout (in constructor)
00293     virtual void addItem(LayoutItem *li);
00294 
00295     /// returns true if a layoutitem is actually removed
00296     virtual bool removeItem(LayoutItem *li);
00297 
00298     virtual bool eventFilter(Object *, Event *);
00299 
00300     virtual void setGeometry(const Rect& r);
00301 
00302     WVar<int> margin;
00303     WVar<int> spacing;
00304     WVar<bool> autoAdd;
00305 
00306 protected:
00307     virtual bool onAboutToChangeAutoAdd(bool auto_add);
00308     virtual int onSpacingOverride(int spacing);
00309     void adjustMaximumSize(int margin);
00310     virtual bool exists(const LayoutItem *li) const = 0;
00311     void markDeleted(LayoutItem *li) {
00312         deleted_li_ = li;
00313     }
00314     bool isDeleted(LayoutItem *li) const {
00315         return deleted_li_ == li;
00316     }
00317     void enforce();
00318     void postLayoutHintEvent();
00319 
00320     void setWidthasPrimaryLength(bool width = true);
00321     bool isWidthPrimaryLength() const {
00322         return width_as_primary_length;
00323     }
00324 
00325     template<typename TYPE>
00326     int primaryLength(const TYPE& t) const {
00327         return (width_as_primary_length) ? t.width() : t.height();
00328     }
00329 
00330     int preferredLength(const LayoutItem *li, bool expand) const;
00331 
00332     template<typename TYPE>
00333     int secondaryLength(const TYPE& t) const;
00334 
00335     template<typename TYPE>
00336     int primaryOffset(const TYPE& t) const;
00337 
00338     template<typename TYPE>
00339     int secondaryOffset(const TYPE& t) const;
00340 
00341     Point getPoint(int primary_offset, int secondary_offset) const;
00342     Size getSize(int primary, int secondary) const;
00343     Rect getRect(int primary_offset, int secondary_offset,
00344                  int primary_size, int secondary_size) const;
00345 
00346     int primaryStretch(const SizePolicy& sp) const;
00347     bool mayGrowPrimally(const SizePolicy& sp) const;
00348     bool mayShrinkPrimally(const SizePolicy& sp) const;
00349     bool expandingPrimally(const SizePolicy& sp) const;
00350 
00351 private:
00352     void on_wobject_item_death(const Object *obj);
00353     LayoutItem *deleted_li_;
00354 
00355     void init();
00356     bool width_as_primary_length;
00357 };
00358 
00359 class NullClass {
00360 public:
00361 };
00362 
00363 template <typename ValueType = NullClass>
00364 class LayoutItemCompound {
00365 public:
00366     typedef ValueType LayoutItemValue;
00367 
00368     LayoutItemCompound(const LayoutItem * li_ = 0,
00369                        const LayoutItemValue& val = LayoutItemValue()) :
00370     li(const_cast<LayoutItem *>(li_)), value(val) {}
00371 
00372     operator LayoutItem *() const {
00373         return li;
00374     }
00375 
00376     operator const LayoutItemValue& () const {
00377         return value;
00378     }
00379 
00380     operator LayoutItemValue& () {
00381         return value;
00382     }
00383 
00384     bool operator==(const LayoutItemCompound& other) const {
00385         return li == other.li;
00386     }
00387 
00388     bool operator==(const LayoutItem *other) const {
00389         return li == other;
00390     }
00391 
00392 private:
00393     LayoutItem *li;
00394     LayoutItemValue value;
00395 };
00396 
00397 template <typename Container>
00398 class LayoutStdContainerIterator : public LayoutIteratorInterface {
00399 public:
00400     typedef typename Container::value_type Compound;
00401     LayoutStdContainerIterator(Container& container) :
00402             container_(container),
00403     end(container_.end()) {}
00404 
00405     virtual LayoutItem* operator*() const {
00406         return *it_;
00407     }
00408 
00409     typename Compound::LayoutItemValue& value() {
00410         return *it_;
00411     }
00412 
00413     virtual bool operator!=(const LayoutIteratorInterface& other) const {
00414         return *it_ != *other;
00415     }
00416 
00417     //postfix only
00418     virtual LayoutStdContainerIterator& operator++(int) {
00419         ++it_;
00420         return *this;
00421     }
00422 
00423     // we bastardize iterator and container here
00424     virtual void start() {
00425         it_ = container_.begin();
00426     }
00427     virtual bool finish() {
00428         return (it_ == end);
00429     }
00430     virtual LayoutItem* pop() {
00431         LayoutItem *li = *it_;
00432         container_.erase(it_);
00433         return li;
00434     }
00435 
00436 private:
00437     Container& container_;
00438     typename Container::iterator it_;
00439     typename Container::iterator end;
00440 };
00441 
00442 /*!
00443  Each LayoutItem is possible associated with a value class where the
00444  the Layout can store effective or current configuration per item.
00445  The way to access this value field is via the operator[] or by
00446  the value() function. Both are equivalents and return a reference
00447  to the value part of the compound type. Access is going through a
00448  limited (one item only) cache scheme.
00449  
00450  The ways to access the value part are:
00451  (*this)[li].stretch = 1;
00452  or
00453  XXXLayout& self(*this);
00454  self[li].stretch = 1;
00455  or
00456  value(li).stretch = 1;
00457  
00458  where stretch is a member of the value part of the compound type
00459 */
00460 template <typename Container>
00461 class LayoutStdContainer : public Layout, public Container {
00462 public:
00463     typedef typename Container::value_type Compound;
00464     LayoutStdContainer(Widget *parent, int margin = 0, int spacing = -1,
00465                        const std::string &name = "StdLayout::anon") :
00466             Layout(parent, margin, spacing, name),
00467     cached_li_(0) {}
00468 
00469     LayoutStdContainer(Layout * parent_layout, int margin = 0, int spacing = -1,
00470                        const std::string &name = "StdLayout::anon") :
00471             Layout(parent_layout, margin, spacing, name),
00472     cached_li_(0) {}
00473 
00474     LayoutStdContainer(int spacing = -1, const std::string &name = "StdLayout::anon") :
00475             Layout(spacing, name),
00476     cached_li_(0) {}
00477 
00478     ~LayoutStdContainer() {
00479         for (typename Container::iterator it(Container::begin()),
00480                 e(Container::end()); it != e;) {
00481             LayoutItem *li = *it;
00482             // Delete only non Objects, Objects will be deleted by ~Object()
00483             if (li && !li->is<Object *>()) {
00484                 delete li;
00485             }
00486             it = Container::erase(it);
00487         }
00488     }
00489 
00490     virtual bool isEmpty() const {
00491         return Container::empty();
00492     }
00493 
00494     // you cannot have multiple inheritance in order to fill up pure virtual functions
00495     virtual void addItem(LayoutItem *li) {
00496         Layout::addItem(li);
00497         Container::push_back(li);
00498     }
00499 
00500     virtual bool removeItem(LayoutItem *li) {
00501         bool exist = Layout::removeItem(li);
00502         if (exist) {
00503             Container::remove
00504                 (li);
00505         }
00506         return exist;
00507     }
00508 
00509     virtual LayoutIterator iterator() {
00510         return LayoutIterator(new LayoutStdContainerIterator<Container>(*this));
00511     }
00512 
00513 protected:
00514     virtual bool exists(const LayoutItem *li) const {
00515         typename Container::const_iterator end = Container::end();
00516         typename Container::const_iterator p = find(Container::begin(), end, li);
00517         return (p != end);
00518     }
00519 
00520     typename Compound::LayoutItemValue& value(const LayoutItem *li) {
00521         if (li != cached_li_) {
00522             cached_li_ = li;
00523             cached_it_ = find(Container::begin(), Container::end(), li);
00524         }
00525         return (cached_it_ != Container::end()) ? *cached_it_ : null_;
00526     }
00527 
00528     typename Compound::LayoutItemValue& operator[](const LayoutItem *li) {
00529         return value(li);
00530     }
00531 
00532 private:
00533     const LayoutItem *cached_li_;
00534     typename Container::iterator cached_it_;
00535     typename Compound::LayoutItemValue null_;
00536 };
00537 
00538 class BoxLayoutItemValue {
00539 public:
00540     BoxLayoutItemValue() :
00541             stretch(0),
00542     extra_space(0) {}
00543 
00544     int stretch;
00545     int extra_space;
00546 };
00547 
00548 typedef LayoutItemCompound<BoxLayoutItemValue> BoxLayoutItemCompound;
00549 typedef std::list<BoxLayoutItemCompound> BoxLayoutItemList;
00550 
00551 class BoxLayoutIterator : public LayoutStdContainerIterator<BoxLayoutItemList> {
00552 public:
00553     BoxLayoutIterator(BoxLayoutItemList& list) :
00554     LayoutStdContainerIterator<BoxLayoutItemList>(list) {}
00555 private:
00556 };
00557 
00558 /*!
00559  - stretch beats expanding
00560  - expanding beats mayGrow
00561  - expanding and or stretch does not propagate outside layout
00562  - if there is stretch turns on expanding
00563  
00564  The extra space is first divided between layout items with a stretch value.
00565  If there is none then the space is divided among expanding layout items. If there
00566  is none then space is divided among layout items that have the mayGrow flag set.
00567 */
00568 typedef LayoutStdContainer<BoxLayoutItemList> BoxLayoutBase;
00569 class BoxLayout : public BoxLayoutBase {
00570 public:
00571     friend class Box;
00572 
00573     typedef enum  {
00574         LeftToRight,
00575         RightToLeft,
00576         TopToBottom,
00577         BottomToTop,
00578         Down = TopToBottom,
00579         Up = BottomToTop
00580     } Direction;
00581 
00582     BoxLayout(Widget *parent, Direction direction, int margin = 0,
00583               int spacing = -1, const std::string &name = "BoxLayout::anon") :
00584             BoxLayoutBase(parent, margin, spacing, name),
00585     direction(direction) {
00586         setWidthasPrimaryLength(direction == LeftToRight ||
00587                                 direction == RightToLeft);
00588     }
00589 
00590     BoxLayout(Layout * parent_layout, Direction direction, int margin = 0,
00591               int spacing = -1, const std::string &name = "BoxLayout::anon") :
00592             BoxLayoutBase(parent_layout, margin, spacing, name),
00593     direction(direction) {
00594         setWidthasPrimaryLength(direction == LeftToRight ||
00595                                 direction == RightToLeft);
00596     }
00597 
00598     BoxLayout(Direction direction, int spacing = -1,
00599               const std::string &name = "BoxLayout::anon") :
00600             BoxLayoutBase(spacing, name),
00601     direction(direction) {
00602         setWidthasPrimaryLength(direction == LeftToRight ||
00603                                 direction == RightToLeft);
00604     }
00605 
00606     Direction direction;
00607 
00608     virtual void appendItem(LayoutItem *li);
00609     virtual void prependItem(LayoutItem *li);
00610     virtual void addItem(LayoutItem *li);
00611     virtual void setGeometry(const Rect& r);
00612 
00613 protected:
00614     virtual void validate();
00615 };
00616 
00617 class HBoxLayout : public BoxLayout {
00618 public:
00619     HBoxLayout(Widget *parent, int margin = 0, int spacing = -1,
00620                const std::string &name = "HBoxLayout::anon") :
00621     BoxLayout(parent, LeftToRight, margin, spacing, name) {}
00622 
00623     HBoxLayout(Layout * parent_layout, int margin = 0, int spacing = -1,
00624                const std::string &name = "HBoxLayout::anon") :
00625     BoxLayout(parent_layout, LeftToRight, margin, spacing, name) {}
00626 
00627     HBoxLayout(int spacing = -1, const std::string &name = "HBoxLayout::anon") :
00628     BoxLayout(LeftToRight, spacing, name) {}
00629 
00630 private:
00631 };
00632 
00633 class VBoxLayout : public BoxLayout {
00634 public:
00635     VBoxLayout(Widget *parent, int margin = 0, int spacing = -1,
00636                const std::string &name = "VBoxLayout::anon") :
00637     BoxLayout(parent, Down, margin, spacing, name) {}
00638 
00639     VBoxLayout(Layout * parent_layout, int margin = 0, int spacing = -1,
00640                const std::string &name = "VBoxLayout::anon") :
00641     BoxLayout(parent_layout, Down, margin, spacing, name) {}
00642 
00643     VBoxLayout(int spacing = -1, const std::string &name = "VBoxLayout::anon") :
00644     BoxLayout(Down, spacing, name) {}
00645 
00646 private:
00647 };
00648 
00649 } // namespace
00650 
00651 #endif // WT_LAYOUT_H

Generated Fri Jul 28 19:23:00 2006.
Copyright © 1998-2003 by the respective authors.

This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.