Files
flenser/dw/types.hh

328 lines
7.7 KiB
C++

#ifndef __DW_TYPES_HH__
#define __DW_TYPES_HH__
#ifndef __INCLUDED_FROM_DW_CORE_HH__
# error Do not include this file directly, use "core.hh" instead.
#endif
#include <memory>
#include <list>
namespace dw {
namespace core {
namespace style {
class Style;
}
enum HPosition
{
HPOS_LEFT,
HPOS_CENTER,
HPOS_RIGHT,
HPOS_INTO_VIEW, /* scroll only, until the content in question comes
* into view */
HPOS_NO_CHANGE
};
enum VPosition
{
VPOS_TOP,
VPOS_CENTER,
VPOS_BOTTOM,
VPOS_INTO_VIEW, /* scroll only, until the content in question comes
* into view */
VPOS_NO_CHANGE
};
enum ScrollCommand {SCREEN_UP_CMD, SCREEN_DOWN_CMD, SCREEN_LEFT_CMD,
SCREEN_RIGHT_CMD, LINE_UP_CMD, LINE_DOWN_CMD,
LEFT_CMD, RIGHT_CMD, TOP_CMD, BOTTOM_CMD, NONE_CMD};
/*
* Different "layers" may be highlighted in a widget.
*/
enum HighlightLayer
{
HIGHLIGHT_SELECTION,
HIGHLIGHT_FINDTEXT,
HIGHLIGHT_NUM_LAYERS
};
struct Point
{
int x;
int y;
};
/**
* \brief Abstract interface for different shapes.
*/
class Shape: public lout::object::Object
{
public:
virtual bool isPointWithin (int x, int y) = 0;
virtual void draw (core::View *view, core::style::Style *style, int x,
int y) = 0;
};
/**
* \brief dw::core::Shape implementation for simple rectangles.
*/
class Rectangle: public Shape
{
public:
int x;
int y;
int width;
int height;
inline Rectangle () { }
Rectangle (int x, int y, int width, int height);
void draw (core::View *view, core::style::Style *style, int x, int y);
bool intersectsWith (Rectangle *otherRect, Rectangle *dest);
bool isSubsetOf (Rectangle *otherRect);
bool isPointWithin (int x, int y);
bool isEmpty () { return width <= 0 || height <= 0; };
};
/**
* \brief dw::core::Shape implementation for simple circles.
*/
class Circle: public Shape
{
public:
int x, y, radius;
Circle (int x, int y, int radius);
void draw (core::View *view, core::style::Style *style, int x, int y);
bool isPointWithin (int x, int y);
};
/**
* \brief dw::core::Shape implementation for polygons.
*/
class Polygon: public Shape
{
private:
std::vector< Point > points;
int minx, miny, maxx, maxy;
/**
* \brief Return the z-coordinate of the vector product of two
* vectors, whose z-coordinate is 0 (so that x and y of
* the vector product is 0, too).
*/
inline int zOfVectorProduct(int x1, int y1, int x2, int y2) {
return x1 * y2 - x2 * y1;
}
bool linesCross0(int ax1, int ay1, int ax2, int ay2,
int bx1, int by1, int bx2, int by2);
bool linesCross(int ax1, int ay1, int ax2, int ay2,
int bx1, int by1, int bx2, int by2);
public:
Polygon ();
void draw (core::View *view, core::style::Style *style, int x, int y);
void addPoint (int x, int y);
bool isPointWithin (int x, int y);
};
/**
* Implementation for a point set.
* Currently represented as a set of rectangles not containing
* each other.
* It is guaranteed that the rectangles returned by rectangles ()
* cover all rectangles that were added with addRectangle ().
*/
class Region
{
private:
std::list< std::unique_ptr< Rectangle > > rectangleList;
public:
void clear () { rectangleList.clear(); }
void addRectangle (Rectangle *r);
auto begin()
{
return rectangleList.begin();
}
auto end()
{
return rectangleList.end();
}
};
/**
* \brief Represents the allocation, i.e. actual position and size of a
* dw::core::Widget.
*/
struct Allocation
{
int x;
int y;
int width;
int ascent;
int descent;
};
struct Requisition
{
int width;
int ascent;
int descent;
};
struct Extremes
{
int minWidth;
int maxWidth;
int minWidthIntrinsic;
int maxWidthIntrinsic;
int adjustmentWidth;
};
class WidgetReference: public lout::object::Object
{
public:
Widget *widget;
int parentRef;
WidgetReference (Widget *widget) { parentRef = -1; this->widget = widget; }
};
struct Content
{
enum Type {
START = 1 << 0,
END = 1 << 1,
TEXT = 1 << 2,
/** \brief widget in normal flow, so that _this_ widget
(containing this content) is both container (parent) and
generator */
WIDGET_IN_FLOW = 1 << 3,
/** \brief widget out of flow (OOF); _this_ widget (containing
this content) is only the container (parent), but _not_
generator */
WIDGET_OOF_CONT = 1 << 4,
/** \brief reference to a widget out of flow (OOF); _this_
widget (containing this content) is only the generator
(parent), but _not_ container */
WIDGET_OOF_REF = 1 << 5,
BREAK = 1 << 6,
/** \brief can be used internally, but should never be exposed,
e. g. by iterators */
INVALID = 1 << 7,
ALL = 0xff,
REAL_CONTENT = 0xff ^ (START | END),
SELECTION_CONTENT = TEXT | BREAK, // WIDGET_* must be set additionally
ANY_WIDGET = WIDGET_IN_FLOW | WIDGET_OOF_CONT | WIDGET_OOF_REF
};
/* Content is embedded in struct Word therefore we
* try to be space efficient.
*/
short type;
bool space;
union {
const char *text;
Widget *widget;
WidgetReference *widgetReference;
int breakSpace;
};
static Content::Type maskForSelection (bool followReferences);
static void intoStringBuffer(Content *content, lout::misc::StringBuffer *sb);
static void maskIntoStringBuffer(Type mask, lout::misc::StringBuffer *sb);
static void print (Content *content);
static void printMask (Type mask);
inline Widget *getWidget () {
assert (type & ANY_WIDGET);
return type == WIDGET_OOF_REF ? widgetReference->widget : widget;
}
};
/**
* \brief Base class for dw::core::DrawingContext and
* dw::core::GettingWidgetAtPointContext.
*
* Not to be confused with the *stacking context* as defined by CSS.
*/
class StackingProcessingContext
{
private:
// This hash-set "owns" a bunch of entities that are passed to it via raw pointer form.
// But the entities seem to be passed in as `this` from the object itself.
//
// I'm delaying untangling that ownership thicket.
lout::container::typed::HashSet<lout::object::TypedPointer<Widget> >
*widgetsProcessedAsInterruption;
public:
inline StackingProcessingContext () {
widgetsProcessedAsInterruption =
new lout::container::typed::HashSet<lout::object::
TypedPointer<Widget> > (true);
}
inline ~StackingProcessingContext ()
{ delete widgetsProcessedAsInterruption; }
inline bool hasWidgetBeenProcessedAsInterruption (Widget *widget) {
lout::object::TypedPointer<Widget> key (widget);
return widgetsProcessedAsInterruption->contains (&key);
}
inline void addWidgetProcessedAsInterruption (Widget *widget) {
lout::object::TypedPointer<Widget> *key =
new lout::object::TypedPointer<Widget> (widget);
return widgetsProcessedAsInterruption->put (key);
}
};
/**
* \brief Set at the top when drawing.
*
* See \ref dw-interrupted-drawing for details.
*/
class DrawingContext: public StackingProcessingContext
{
private:
Rectangle toplevelArea;
public:
inline DrawingContext (Rectangle *toplevelArea) {
this->toplevelArea = *toplevelArea;
}
inline Rectangle *getToplevelArea () { return &toplevelArea; }
};
/**
* \brief Set at the top when getting the widget at the point.
*
* Similar to dw::core::DrawingContext.
*/
class GettingWidgetAtPointContext: public StackingProcessingContext
{
};
} // namespace core
} // namespace dw
#endif // __DW_TYPES_HH__