aboutsummaryrefslogtreecommitdiff
path: root/dw/oofawarewidget.hh
blob: 17123910f1ab4a6d1b19930293ce2176686128ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#ifndef __DW_OOFAWAREWIDGET_HH__
#define __DW_OOFAWAREWIDGET_HH__

#include "core.hh"
#include "outofflowmgr.hh"

namespace dw {

namespace oof {

/**
 * \brief Base class for widgets which can act as container and
 *     generator for widgets out of flow.
 *
 * (Perhaps it should be diffenciated between the two roles, container
 * and generator, but this would make multiple inheritance necessary.)
 *
 * See \ref dw-out-of-flow for an overview.
 *
 * Requirements for sub classes (in most cases refer to dw::Textblock
 * as a good example):
 *
 * - A sub class should at least take care to call these methods at the
 *   respective points:
 *
 *   - dw::oof::OOFAwareWidget::correctRequisitionByOOF (from
 *     dw::core::Widget::getExtremesImpl)
 *   - dw::oof::OOFAwareWidget::correctExtremesByOOF (from
 *     dw::core::Widget::sizeRequestImpl)
 *   - dw::oof::OOFAwareWidget::sizeAllocateStart
 *   - dw::oof::OOFAwareWidget::sizeAllocateEnd (latter two from
 *     dw::core::Widget::sizeAllocateImpl)
 *   - dw::oof::OOFAwareWidget::containerSizeChangedForChildrenOOF
 *     (from dw::core::Widget::containerSizeChangedForChildren)
 *   - dw::oof::OOFAwareWidget::drawOOF (from dw::core::Widget::draw)
 *   - dw::oof::OOFAwareWidget::getWidgetOOFAtPoint (from
 *     dw::core::Widget::getWidgetAtPoint)
 *
 * - Implementations of dw::core::Widget::getAvailWidthOfChild and
 *   dw::core::Widget::getAvailHeightOfChild have to distinguish
 *   between widgets in flow and out of flow; see implementations of
 *   dw::oof::OOFAwareWidget. (Open issue: What about
 *   dw::core::Widget::correctRequisitionOfChild and
 *   dw::core::Widget::correctExtremesOfChild? Currently, all widgets
 *   are used the default implementation.)
 *
 * - Iterators have to consider widgets out of flow;
 *   dw::oof::OOFAwareWidget::OOFAwareWidgetIterator is recommended as
 *   base class.
 *
 * - dw::core::Widget::parentRef has to be set for widgets in flow; if
 *   not used further, a simple *makeParentRefInFlow(0)* is sufficient
 *   (as dw::Table::addCell does). Widgets which are only containers,
 *   but not generators, do not have to care about widgets out of
 *   flow in this regard.
 *
 * For both generators and containers of floats (which is only
 * implemented by dw::Textblock) it gets a bit more complicated.
 *
 * \todo Currently, on the level of dw::oof::OOFAwareWidget, nothing
 * is done about dw::core::Widget::markSizeChange and
 * dw::core::Widget::markExtremesChange. This does not matter, though:
 * dw::Textblock takes care of these, and dw::Table is only connected
 * to subclasses of dw::oof::OOFPositionedMgr, which do care about
 * these. However, this should be considered for completeness.
 */
class OOFAwareWidget: public core::Widget
{
protected:
   enum { OOFM_FLOATS, OOFM_ABSOLUTE, OOFM_FIXED, NUM_OOFM };
   static const char *OOFM_NAME[NUM_OOFM];
   enum { PARENT_REF_OOFM_BITS = 2,
          PARENT_REF_OOFM_MASK = (1 << PARENT_REF_OOFM_BITS) - 1 };

   class OOFAwareWidgetIterator: public core::Iterator
   {
   private:
      enum { NUM_SECTIONS = NUM_OOFM + 1 };
      int sectionIndex; // 0 means in flow, otherwise OOFM index + 1
      int index;

      int numParts (int sectionIndex, int numContentsInFlow = -1);
      void getPart (int sectionIndex, int index, core::Content *content);

   protected:
      virtual int numContentsInFlow () = 0;
      virtual void getContentInFlow (int index, core::Content *content) = 0;

      void setValues (int sectionIndex, int index);
      inline void cloneValues (OOFAwareWidgetIterator *other)
      { other->setValues (sectionIndex, index); }         

      inline bool inFlow () { return sectionIndex == 0; }
      inline int getInFlowIndex () { assert (inFlow ()); return index; }
      void highlightOOF (int start, int end, core::HighlightLayer layer);
      void unhighlightOOF (int direction, core::HighlightLayer layer);
      void getAllocationOOF (int start, int end, core::Allocation *allocation);

   public:
      OOFAwareWidgetIterator (OOFAwareWidget *widget, core::Content::Type mask,
                              bool atEnd, int numContentsInFlow);

      void intoStringBuffer(lout::misc::StringBuffer *sb);
      int compareTo(lout::object::Comparable *other);

      bool next ();
      bool prev ();
   };

   inline bool isParentRefOOF (int parentRef)
   { return parentRef != -1 && (parentRef & PARENT_REF_OOFM_MASK); }

   inline int makeParentRefInFlow (int inFlowSubRef)
   { return (inFlowSubRef << PARENT_REF_OOFM_BITS); }
   inline int getParentRefInFlowSubRef (int parentRef)
   { assert (!isParentRefOOF (parentRef));
      return parentRef >> PARENT_REF_OOFM_BITS; }

   inline int makeParentRefOOF (int oofmIndex, int oofmSubRef)
   { return (oofmSubRef << PARENT_REF_OOFM_BITS) | (oofmIndex + 1); }
   inline int getParentRefOOFSubRef (int parentRef)
   { assert (isParentRefOOF (parentRef));
      return parentRef >> PARENT_REF_OOFM_BITS; }
   inline int getParentRefOOFIndex (int parentRef)
   { assert (isParentRefOOF (parentRef));
      return (parentRef & PARENT_REF_OOFM_MASK) - 1; }
   inline oof::OutOfFlowMgr *getParentRefOutOfFlowMgr (int parentRef)
   { return outOfFlowMgr[getParentRefOOFIndex (parentRef)]; }

   inline bool isWidgetOOF (Widget *widget)
   { return isParentRefOOF (widget->parentRef); }

   inline int getWidgetInFlowSubRef (Widget *widget)
   { return getParentRefInFlowSubRef (widget->parentRef); }

   inline int getWidgetOOFSubRef (Widget *widget)
   { return getParentRefOOFSubRef (widget->parentRef); }
   inline int getWidgetOOFIndex (Widget *widget)
   { return getParentRefOOFIndex (widget->parentRef); }
   inline oof::OutOfFlowMgr *getWidgetOutOfFlowMgr (Widget *widget)
   { return getParentRefOutOfFlowMgr (widget->parentRef); }

   OOFAwareWidget *oofContainer[NUM_OOFM];
   OutOfFlowMgr *outOfFlowMgr[NUM_OOFM];

   inline OutOfFlowMgr *searchOutOfFlowMgr (int oofmIndex)
   { return oofContainer[oofmIndex] ?
         oofContainer[oofmIndex]->outOfFlowMgr[oofmIndex] : NULL; }

   static bool getOOFMIndex (Widget *widget);

   void initOutOfFlowMgrs ();
   void correctRequisitionByOOF (core::Requisition *requisition,
                                 void (*splitHeightFun) (int, int*, int*));
   void correctExtremesByOOF (core::Extremes *extremes);
   void sizeAllocateStart (core::Allocation *allocation);
   void sizeAllocateEnd ();
   void containerSizeChangedForChildrenOOF ();

   virtual void drawLevel (core::View *view, core::Rectangle *area,
                           core::StackingIteratorStack *iteratorStack,
                           Widget **interruptedWidget, int majorLevel);
   void drawOOF (core::View *view, core::Rectangle *area,
                 core::StackingIteratorStack *iteratorStack,
                 Widget **interruptedWidget);

   Widget *getWidgetAtPoint (int x, int y,
                             core::StackingIteratorStack *iteratorStack,
                             Widget **interruptedWidget);
   virtual Widget *getWidgetAtPointLevel (int x, int y,
                                          core::StackingIteratorStack
                                          *iteratorStack,
                                          Widget **interruptedWidget,
                                          int majorLevel);
   Widget *getWidgetOOFAtPoint (int x, int y,
                                core::StackingIteratorStack *iteratorStack,
                                Widget **interruptedWidget);

   virtual int getLastMinorLevel (int majorLevel);
   virtual int getLastLevelIndex (int majorLevel, int minorLevel);

   static bool isOOFContainer (Widget *widget, int oofmIndex);

   void notifySetAsTopLevel();
   void notifySetParent();

   int getAvailWidthOfChild (Widget *child, bool forceValue);
   int getAvailHeightOfChild (Widget *child, bool forceValue);

   void removeChild (Widget *child);


public:
   static int CLASS_ID;

   class OOFStackingIterator: public lout::object::Object
   {
   private:
      lout::container::typed::HashSet<lout::object::TypedPointer<Widget> >
         *widgetsDrawnAfterInterruption;

   public:
      enum { START, BACKGROUND, SC_BOTTOM, IN_FLOW, OOF_REF, OOF_CONT, SC_TOP,
             END } ;
      int majorLevel, minorLevel, index;

      static const char *majorLevelText (int majorLevel);

      OOFStackingIterator (OOFAwareWidget *widget, bool atEnd);
      ~OOFStackingIterator ();

      void intoStringBuffer(lout::misc::StringBuffer *sb);

      void registerWidgetDrawnAfterInterruption (Widget *widget);
      bool hasWidgetBeenDrawnAfterInterruption (Widget *widget);
   };

   OOFAwareWidget ();
   ~OOFAwareWidget ();

   static inline bool testStyleFloat (core::style::Style *style)
   { return style->vloat != core::style::FLOAT_NONE; }

   static inline bool testStyleAbsolutelyPositioned (core::style::Style *style)
   { return style->position == core::style::POSITION_ABSOLUTE; }
   static inline bool testStyleFixedlyPositioned (core::style::Style *style)
   { return style->position == core::style::POSITION_FIXED; }
   static inline bool testStyleRelativelyPositioned (core::style::Style *style)
   { return style->position == core::style::POSITION_RELATIVE; }

   static inline bool testStylePositioned (core::style::Style *style)
   { return testStyleAbsolutelyPositioned (style) ||
         testStyleRelativelyPositioned (style) ||
         testStyleFixedlyPositioned (style); }

   static inline bool testStyleOutOfFlow (core::style::Style *style)
   { return testStyleFloat (style) || testStyleAbsolutelyPositioned (style)
         || testStyleFixedlyPositioned (style); }

   static inline bool testWidgetFloat (Widget *widget)
   { return testStyleFloat (widget->getStyle ()); }

   static inline bool testWidgetAbsolutelyPositioned (Widget *widget)
   { return testStyleAbsolutelyPositioned (widget->getStyle ()); }
   static inline bool testWidgetFixedlyPositioned (Widget *widget)
   { return testStyleFixedlyPositioned (widget->getStyle ()); }
   static inline bool testWidgetRelativelyPositioned (Widget *widget)
   { return testStyleRelativelyPositioned (widget->getStyle ()); }

   static inline bool testWidgetPositioned (Widget *widget)
   { return testStylePositioned (widget->getStyle ()); }

   static inline bool testWidgetOutOfFlow (Widget *widget)
   { return testStyleOutOfFlow (widget->getStyle ()); }

   bool doesWidgetOOFInterruptDrawing (Widget *widget);

   void draw (core::View *view, core::Rectangle *area,
              core::StackingIteratorStack *iteratorStack,
              Widget **interruptedWidget);
   lout::object::Object *stackingIterator (bool atEnd);

   virtual void borderChanged (int y, core::Widget *vloat);
   virtual void clearPositionChanged ();
   virtual void oofSizeChanged (bool extremesChanged);
   virtual int getLineBreakWidth (); // Should perhaps be renamed.
   virtual bool isPossibleContainer (int oofmIndex);
   virtual bool isPossibleContainerParent (int oofmIndex);
   virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
};

} // namespace oof

} // namespace dw

#endif // __DW_OOFAWAREWIDGET_HH__