301 lines
11 KiB
C++
301 lines
11 KiB
C++
#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; general pattern:
|
|
*
|
|
* \code
|
|
* if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) &&
|
|
* getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
|
|
* width =
|
|
* getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue);
|
|
* else {
|
|
* // ... specific implementation ...
|
|
* \endcode
|
|
*
|
|
* See also implementations of dw::Textblock and dw::Table. (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_RELATIVE, OOFM_FIXED, NUM_OOFM };
|
|
static const char *OOFM_NAME[NUM_OOFM];
|
|
enum { PARENT_REF_OOFM_BITS = 3,
|
|
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) const
|
|
{ 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) const override;
|
|
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];
|
|
core::Requisition requisitionWithoutOOF;
|
|
|
|
inline OutOfFlowMgr *searchOutOfFlowMgr (int oofmIndex)
|
|
{ return oofContainer[oofmIndex] ?
|
|
oofContainer[oofmIndex]->outOfFlowMgr[oofmIndex] : NULL; }
|
|
|
|
static int 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, int level,
|
|
core::DrawingContext *context);
|
|
void drawOOF (core::View *view, core::Rectangle *area,
|
|
core::DrawingContext *context);
|
|
|
|
Widget *getWidgetAtPoint (int x, int y,
|
|
core::GettingWidgetAtPointContext *context);
|
|
virtual Widget *getWidgetAtPointLevel (int x, int y, int level,
|
|
core::GettingWidgetAtPointContext
|
|
*context);
|
|
Widget *getWidgetOOFAtPoint (int x, int y,
|
|
core::GettingWidgetAtPointContext *context);
|
|
|
|
static bool isOOFContainer (Widget *widget, int oofmIndex);
|
|
|
|
void notifySetAsTopLevel();
|
|
void notifySetParent();
|
|
|
|
void removeChild (Widget *child);
|
|
|
|
virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
|
|
|
|
public:
|
|
enum {
|
|
SL_START, SL_BACKGROUND, SL_SC_BOTTOM, SL_IN_FLOW, SL_OOF_REF,
|
|
SL_OOF_CONT, SL_SC_TOP, SL_END };
|
|
|
|
OOFAwareWidget ();
|
|
~OOFAwareWidget ();
|
|
|
|
static const char *stackingLevelText (int level);
|
|
|
|
static inline bool testStyleFloat (core::style::Style *style)
|
|
{ return style->vloat != core::style::FLOAT_NONE; }
|
|
|
|
static inline bool testStyleAbsolutelyPositioned (core::style::Style *style)
|
|
{ return IMPL_POS && style->position == core::style::POSITION_ABSOLUTE; }
|
|
static inline bool testStyleFixedlyPositioned (core::style::Style *style)
|
|
{ return IMPL_POS && style->position == core::style::POSITION_FIXED; }
|
|
static inline bool testStyleRelativelyPositioned (core::style::Style *style)
|
|
{ return IMPL_POS && 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)
|
|
{ // Second part is equivalent to testStylePositioned(), but we still keep
|
|
// the two separately.
|
|
return testStyleFloat (style) || testStyleAbsolutelyPositioned (style)
|
|
|| testStyleRelativelyPositioned (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 ()); }
|
|
|
|
inline core::Requisition *getRequisitionWithoutOOF ()
|
|
{ return &requisitionWithoutOOF; }
|
|
|
|
bool doesWidgetOOFInterruptDrawing (Widget *widget);
|
|
|
|
void draw (core::View *view, core::Rectangle *area,
|
|
core::DrawingContext *context);
|
|
|
|
/**
|
|
* Update content in flow, down from `ref`. Uses e. g. when floats sizes have
|
|
* changed.
|
|
*/
|
|
virtual void updateReference (int ref);
|
|
|
|
/**
|
|
* Called by an implementation of dw::oof::OutOfFlowMgr (actually only
|
|
* OOFPosRelMgr) for the generator of a widget out of flow, when the
|
|
* reference size has changed. (The size of the reference is 0 * 0 for all
|
|
* other implementations of dw::oof::OutOfFlowMgr.)
|
|
*/
|
|
virtual void widgetRefSizeChanged (int externalIndex);
|
|
|
|
/**
|
|
* Called by an implementation of dw::oof::OutOfFlowMgr when the size of the
|
|
* container has changed, typically in sizeAllocateEnd.
|
|
*/
|
|
virtual void oofSizeChanged (bool extremesChanged);
|
|
|
|
/**
|
|
* Return position relative to container, not regarding
|
|
* margin/border/padding, Called by OOFFloatsMgr to position floats.
|
|
*/
|
|
virtual int getGeneratorX (int oofmIndex);
|
|
|
|
/**
|
|
* Return position relative to container, not regarding
|
|
* margin/border/padding, Called by OOFFloatsMgr to position floats.
|
|
*/
|
|
virtual int getGeneratorY (int oofmIndex);
|
|
|
|
/**
|
|
* Return width including margin/border/padding Called by OOFFloatsMgr to
|
|
* position floats.
|
|
*/
|
|
virtual int getGeneratorWidth ();
|
|
|
|
virtual int getMaxGeneratorWidth ();
|
|
|
|
virtual bool usesMaxGeneratorWidth ();
|
|
|
|
virtual bool isPossibleOOFContainer (int oofmIndex);
|
|
|
|
virtual bool isPossibleOOFContainerParent (int oofmIndex);
|
|
};
|
|
|
|
} // namespace oof
|
|
|
|
} // namespace dw
|
|
|
|
#endif // __DW_OOFAWAREWIDGET_HH__
|