1 #ifndef MULTI_GEOMETRY_WIDGET_HPP__
2 #define MULTI_GEOMETRY_WIDGET_HPP__
3 
4 #include <cstddef>
5 #include <utility>
6 #include <array>
7 
8 #include <QWidget>
9 #include <QByteArray>
10 #include <QEvent>
11 
12 //
13 // Class MultiGeometryWidget<N, Widget> - Decorate a QWidget type with
14 // 																				switchable geometries
15 //
16 // The abstract base class imbues a Qt Widget type with N alternative
17 // geometries. Sub-classes can initialise the currently selected
18 // geometry and the initial geometries using geometries. To switch
19 // geometry call select_geometry(n) which saves the current geometry
20 // and switches to the n'th saved geometry.
21 //
22 template<std::size_t N, typename Widget=QWidget>
23 class MultiGeometryWidget
24   : public Widget
25 {
26 public:
27   template<typename... Args>
MultiGeometryWidget(Args &&...args)28   explicit MultiGeometryWidget (Args&&... args)
29     : Widget {std::forward<Args> (args)...}
30     , current_geometry_ {0}
31   {
32   }
33 
34   void geometries (std::size_t current
35                    , std::array<QByteArray, N> const& the_geometries = std::array<QByteArray, N> {})
36   {
37     Q_ASSERT (current < the_geometries.size ());
38     saved_geometries_ = the_geometries;
39     current_geometry_ = current;
40     Widget::restoreGeometry (saved_geometries_[current_geometry_]);
41   }
42 
geometries() const43   std::array<QByteArray, N> const& geometries () const {return saved_geometries_;}
current()44   std::size_t current () {return current_geometry_;}
45 
46   // Call this to select a new geometry denoted by the 'n' argument,
47   // any actual layout changes should be made in the implementation of
48   // the change_layout operation below.
select_geometry(std::size_t n)49   void select_geometry (std::size_t n)
50   {
51     Q_ASSERT (n < N);
52     auto geometry = Widget::saveGeometry ();
53     change_layout (n);
54     saved_geometries_[current_geometry_] = geometry;
55     current_geometry_ = n;
56 
57     // Defer restoration of the window geometry until the layour
58     // request event has been processed, this is necessary otherwise
59     // the final geometry may be affected by widgets not shown in the
60     // new layout.
61     desired_geometry_ = saved_geometries_[n];
62   }
63 
64 protected:
~MultiGeometryWidget()65   virtual ~MultiGeometryWidget () {}
66 
67 private:
68   // Override this operation to implement any layout changes for the
69   // geometry specified by the argument 'n'.
70   virtual void change_layout (std::size_t n) = 0;
71 
event(QEvent * e)72   bool event (QEvent * e) override
73   {
74     auto ret = Widget::event (e);
75     if (QEvent::LayoutRequest == e->type ()
76         && desired_geometry_.size ())
77       {
78         // Restore the new desired geometry and flag that we have done
79         // so by clearing the desired_geometry_ member variable.
80         QByteArray geometry;
81         std::swap (geometry, desired_geometry_);
82         Widget::restoreGeometry (geometry);
83       }
84     return ret;
85   }
86 
87   std::size_t current_geometry_;
88   std::array<QByteArray, N> saved_geometries_;
89   QByteArray desired_geometry_;
90 };
91 
92 #endif
93