#ifndef __DW_STYLE_HH__
#define __DW_STYLE_HH__
#include <stdint.h>
#ifndef __INCLUDED_FROM_DW_CORE_HH__
# error Do not include this file directly, use "core.hh" instead.
#endif
namespace dw {
namespace core {
/**
* \brief Anything related to Dillo %Widget styles is defined here.
*
* <h3>Overview</h3>
*
* dw::core::style::Style provides some resources and attributes for
* drawing widgets, as well as for parts of a widget (e.g., dw::Textblock
* uses styles for its words). Creating a style is done by filling a
* dw::core::style::StyleAttrs with the attributes and calling
* dw::core::style::Style::create:
*
* \code
* dw::core::style::Style styleAttrs;
* dw::core::style::Style *style;
* dw::core::Layout *layout;
*
* // ...
*
* styleAttrs.foo = bar;
* // etc.
* style = dw::core::style::Style::create (&styleAttrs, layout);
* // do something with style
* \endcode
*
* After this, the attributes of a dw::core::style::Style should not be
* changed anymore, since styles are often shared between different
* widgets etc. (see below). Most times, you simply copy the attributes
* of another style (possible, since dw::core::style::Style is a sub
* class of dw::core::style::StyleAttrs), modify them and create a new
* style:
*
* \code
* styleAttrs = *anotherStyle;
* styleAttrs.foo = baz;
* style = dw::core::style::Style::create (&styleAttrs, layout);
* \endcode
*
* The dw::core::style::Font structure can be created by
* dw::core::style::Font::create, in a similar, with
* dw::core::style::FontAttrs, and colors by
* dw::core::style::Color::create, passing 0xrrggbb as an
* argument. Furthermore, there is dw::core::style::Tooltip, created by
* dw::core::style::Tooltip::create.
*
* Notice that fonts, colors and tooltips are only intended to be used in
* conjunction with dw::core::style::Style.
*
*
* <h3>Naming</h3>
*
* dw::core::style::Style will become important for CSS, each CSS
* attribute, which is supported by dillo, will refer to an attribute in
* dw::core::style::Style. For this reason, the attributes in
* dw::core::style::Style get the names from the CSS attributes, with
* "camelCase" instead of hyphens (e.g. "background-color" becomes
* "backgroundColor").
*
* However, dw::core::style::Style will be extended by some more
* attributes, which are not defined by CSS. To distinguish them, they
* get the prefix "x_", e.g. dw::core::style::Style::x_link.
*
*
* <h3>Lengths and Percentages</h3>
*
* dw::core::style::Length is a simple data type for lengths and
* percentages:
*
* <ul>
* <li> A length refers to an absolute measurement. It is used to
* represent the HTML type %Pixels; and the CSS type \<length\>.
*
* For CSS lengths, there are two units: (i) pixels and absolute
* units, which have to be converted to pixels (a pixel is, unlike
* in the CSS specification, treated as absolute unit), and (ii) the
* relative units "em" and "ex" (see below).
*
* <li> A percentage refers to a value relative to another value. It is
* used for the HTML type %Length; (except %Pixels;), and the CSS
* type \<percentage\>.
*
* <li> A relative length can be used in lists of HTML MultiLengths.
* </ul>
*
* Since many values in CSS may be either lengths or percentages, a
* single type is very useful.
*
* <h4>Useful Functions</h4>
*
* Creating lengths:
*
* <ul>
* <li> dw::core::style::createAbsLength
* <li> dw::core::style::createPerLength
* <li> dw::core::style::createRelLength
* </ul>
*
* Examine lengths:
*
* <ul>
* <li> dw::core::style::isAbsLength
* <li> dw::core::style::isPerLength
* <li> dw::core::style::isRelLength
* <li> dw::core::style::absLengthVal
* <li> dw::core::style::perLengthVal
* <li> dw::core::style::relLengthVal
* </ul>
*
*
* <h3>Boxes</h3>
*
* <h4>The CSS %Box Model</h4>
*
* For borders, margins etc., the box model defined by CSS2 is
* used. dw::core::style::Style contains some members defining these
* attributes. A dw::core::Widget must use these values for any
* calculation of sizes. There are some helper functions (see
* dw/style.hh). A dw::core::style::Style box looks quite similar to a
* CSS box:
*
* \image html dw-style-box-model.png
*
* <h4>Background colors</h4>
*
* The background color is stored in
* dw::core::style::Style::backgroundColor, which may be NULL (the
* background color of the parent widget is shining through).
*
* For toplevel widgets, this color is set as the background color of the
* views (dw::core::View::setBgColor), for other widgets, a filled
* rectangle is drawn, covering the content and padding. (This is
* compliant with CSS2, the background color of the toplevel element
* covers the whole canvas.)
*
* <h4>Drawing</h4>
*
* The following methods may be useful:
*
* <ul>
* <li> dw::core::Widget::drawWidgetBox for drawing the box of a widget
* (typically at the beginning of the implementation of
* dw::core::Widget::draw), and
*
* <li> dw::core::Widget::drawBox, for drawing parts of a widget (e.g.
* dw::Textblock::Word, which has its own dw::Textblock::Word::style).
* </ul>
*
*
* <h3>Notes on Memory Management</h3>
*
* Memory management is done by reference counting,
* dw::core::style::Style::create returns a pointer to
* dw::core::style::Style with an increased reference counter, so you
* should care about calling dw::core::style::Style::unref if it is not
* used anymore. You do \em not need to care about the reference counters
* of fonts and styles.
*
* In detail:
*
* <ul>
* <li> dw::core::style::Style::ref is called in
*
* <ul>
* <li> dw::core::Widget::setStyle to assign a style to a widget,
* <li> dw::Textblock::addText, dw::Textblock::addWidget,
* dw::Textblock::addAnchor, dw::Textblock::addSpace,
* dw::Textblock::addParbreak and dw::Textblock::addLinebreak,
* to assign a style to a dw::Textblock::Word, and
* <li> by the HTML parser, when pushing an element on the stack.
* </ul>
*
* <li> dw::core::style::Style::unref is called in
*
* <ul>
* <li> dw::core::Widget::~Widget, dw::Textblock::~Textblock, by the
* HTML parser, when popping an element fom the stack, and
* <li> dw::core::Widget::setStyle, dw::Textblock::addText etc.,
* these methods overwrite an existing style.
* </ul>
* </ul>
*/
namespace style {
enum Cursor {
CURSOR_CROSSHAIR,
CURSOR_DEFAULT,
CURSOR_POINTER,
CURSOR_MOVE,
CURSOR_E_RESIZE,
CURSOR_NE_RESIZE,
CURSOR_NW_RESIZE,
CURSOR_N_RESIZE,
CURSOR_SE_RESIZE,
CURSOR_SW_RESIZE,
CURSOR_S_RESIZE,
CURSOR_W_RESIZE,
CURSOR_TEXT,
CURSOR_WAIT,
CURSOR_HELP
};
enum BorderCollapse {
BORDER_MODEL_SEPARATE,
BORDER_MODEL_COLLAPSE
};
enum BorderStyle {
BORDER_NONE,
BORDER_HIDDEN,
BORDER_DOTTED,
BORDER_DASHED,
BORDER_SOLID,
BORDER_DOUBLE,
BORDER_GROOVE,
BORDER_RIDGE,
BORDER_INSET,
BORDER_OUTSET
};
enum TextAlignType {
TEXT_ALIGN_LEFT,
TEXT_ALIGN_RIGHT,
TEXT_ALIGN_CENTER,
TEXT_ALIGN_JUSTIFY,
TEXT_ALIGN_STRING
};
enum VAlignType {
VALIGN_TOP,
VALIGN_BOTTOM,
VALIGN_MIDDLE,
VALIGN_BASELINE,
VALIGN_SUB,
VALIGN_SUPER,
VALIGN_TEXT_TOP,
VALIGN_TEXT_BOTTOM,
};
enum TextTransform {
TEXT_TRANSFORM_NONE,
TEXT_TRANSFORM_CAPITALIZE,
TEXT_TRANSFORM_UPPERCASE,
TEXT_TRANSFORM_LOWERCASE,
};
/**
* \todo Incomplete. Has to be completed for a CSS implementation.
*/
enum DisplayType {
DISPLAY_BLOCK,
DISPLAY_INLINE,
DISPLAY_LIST_ITEM,
DISPLAY_NONE,
DISPLAY_TABLE,
DISPLAY_TABLE_ROW_GROUP,
DISPLAY_TABLE_HEADER_GROUP,
DISPLAY_TABLE_FOOTER_GROUP,
DISPLAY_TABLE_ROW,
DISPLAY_TABLE_CELL
};
enum LineType {
LINE_NORMAL,
LINE_DOTTED,
LINE_DASHED
};
enum ListStylePosition {
LIST_STYLE_POSITION_INSIDE,
LIST_STYLE_POSITION_OUTSIDE
};
enum ListStyleType {
LIST_STYLE_TYPE_DISC,
LIST_STYLE_TYPE_CIRCLE,
LIST_STYLE_TYPE_SQUARE,
LIST_STYLE_TYPE_DECIMAL,
LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO,
LIST_STYLE_TYPE_LOWER_ROMAN,
LIST_STYLE_TYPE_UPPER_ROMAN,
LIST_STYLE_TYPE_LOWER_GREEK,
LIST_STYLE_TYPE_LOWER_ALPHA,
LIST_STYLE_TYPE_LOWER_LATIN,
LIST_STYLE_TYPE_UPPER_ALPHA,
LIST_STYLE_TYPE_UPPER_LATIN,
LIST_STYLE_TYPE_HEBREW,
LIST_STYLE_TYPE_ARMENIAN,
LIST_STYLE_TYPE_GEORGIAN,
LIST_STYLE_TYPE_CJK_IDEOGRAPHIC,
LIST_STYLE_TYPE_HIRAGANA,
LIST_STYLE_TYPE_KATAKANA,
LIST_STYLE_TYPE_HIRAGANA_IROHA,
LIST_STYLE_TYPE_KATAKANA_IROHA,
LIST_STYLE_TYPE_NONE
};
enum FontStyle {
FONT_STYLE_NORMAL,
FONT_STYLE_ITALIC,
FONT_STYLE_OBLIQUE
};
enum FontVariant {
FONT_VARIANT_NORMAL,
FONT_VARIANT_SMALL_CAPS
};
enum TextDecoration {
TEXT_DECORATION_NONE = 0,
TEXT_DECORATION_UNDERLINE = 1 << 0,
TEXT_DECORATION_OVERLINE = 1 << 1,
TEXT_DECORATION_LINE_THROUGH = 1 << 2,
TEXT_DECORATION_BLINK = 1 << 3
};
enum WhiteSpace {
WHITE_SPACE_NORMAL,
WHITE_SPACE_PRE,
WHITE_SPACE_NOWRAP,
WHITE_SPACE_PRE_WRAP,
WHITE_SPACE_PRE_LINE,
};
/**
* \brief Type for representing all lengths within dw::core::style.
*
* Lengths are int's. Absolute lengths are represented in the following way:
*
* \image html dw-style-length-absolute.png
*
* Percentages:
*
* \image html dw-style-length-percentage.png
*
* Relative lengths (only used in HTML):
*
* \image html dw-style-length-relative.png
*
* This is an implementation detail, use one of the following functions:
*
* Creating lengths:
*
* <ul>
* <li> dw::core::style::createAbsLength
* <li> dw::core::style::createPerLength
* <li> dw::core::style::createRelLength
* </ul>
*
* Examine lengths:
*
* <ul>
* <li> dw::core::style::isAbsLength
* <li> dw::core::style::isPerLength
* <li> dw::core::style::isRelLength
* <li> dw::core::style::absLengthVal
* <li> dw::core::style::perLengthVal
* <li> dw::core::style::relLengthVal
* </ul>
*
* "auto" lengths are represented as dw::core::style::LENGTH_AUTO.
*/
typedef int Length;
/** \brief Returns a length of \em n pixels. */
inline Length createAbsLength(int n) { return (n << 2) | 1; }
/** \brief Returns a percentage, \em v is relative to 1, not to 100. */
inline Length createPerLength(double v) {
return ((int)(v * (1 << 18)) & ~3) | 2; }
/** \brief Returns a relative length. */
inline Length createRelLength(double v) {
return ((int)(v * (1 << 18)) & ~3) | 3; }
/** \brief Returns true if \em l is an absolute length. */
inline bool isAbsLength(Length l) { return (l & 3) == 1; }
/** \brief Returns true if \em l is a percentage. */
inline bool isPerLength(Length l) { return (l & 3) == 2; }
/** \brief Returns true if \em l is a relative length. */
inline bool isRelLength(Length l) { return (l & 3) == 3; }
/** \brief Returns the value of a length in pixels, as an integer. */
inline int absLengthVal(Length l) { return l >> 2; }
/** \brief Returns the value of a percentage, relative to 1, as a double. */
inline double perLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
/** \brief Returns the value of a relative length, as a float. */
inline double relLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
enum {
/** \brief Represents "auto" lengths. */
LENGTH_AUTO = 0
};
/**
* \brief Represents a dimension box according to the CSS box model.
*
* Used for dw::core::style::Style::margin,
* dw::core::style::Style::borderWidth, and dw::core::style::Style::padding.
*/
class Box
{
public:
/* in future also percentages */
int top, right, bottom, left;
inline void setVal(int val) { top = right = bottom = left = val; }
inline bool equals (Box *other) {
return top == other->top &&
right == other->right &&
bottom == other->bottom &&
left == other->left;
}
inline int hashValue () {
return top + right + bottom + left;
}
};
class Font;
class Color;
class Tooltip;
/**
* \sa dw::core::style
*/
class StyleAttrs : public lout::object::Object
{
public:
Font *font;
int textDecoration; /* No TextDecoration because of problems converting
* TextDecoration <-> int */
Color *color, *backgroundColor;
TextAlignType textAlign;
VAlignType valign;
char textAlignChar; /* In future, strings will be supported. */
TextTransform textTransform;
int hBorderSpacing, vBorderSpacing, wordSpacing;
Length width, height, lineHeight, textIndent;
Box margin, borderWidth, padding;
BorderCollapse borderCollapse;
struct { Color *top, *right, *bottom, *left; } borderColor;
struct { BorderStyle top, right, bottom, left; } borderStyle;
DisplayType display;
WhiteSpace whiteSpace;
ListStylePosition listStylePosition;
ListStyleType listStyleType;
Cursor cursor;
int x_link;
int x_img;
Tooltip *x_tooltip;
void initValues ();
void resetValues ();
bool sizeDiffs (StyleAttrs *otherStyleAttrs);
inline void setBorderColor(Color *val) {
borderColor.top = borderColor.right = borderColor.bottom
= borderColor.left = val; }
inline void setBorderStyle(BorderStyle val) {
borderStyle.top = borderStyle.right = borderStyle.bottom
= borderStyle.left = val; }
inline int boxOffsetX ()
{
return margin.left + borderWidth.left + padding.left;
}
inline int boxRestWidth ()
{
return margin.right + borderWidth.right + padding.right;
}
inline int boxDiffWidth () { return boxOffsetX () + boxRestWidth (); }
inline int boxOffsetY ()
{
return margin.top + borderWidth.top + padding.top;
}
inline int boxRestHeight ()
{
return margin.bottom + borderWidth.bottom + padding.bottom;
}
inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
inline bool hasBackground () { return backgroundColor != NULL; }
bool equals (lout::object::Object *other);
int hashValue ();
};
/**
* \sa dw::core::style
*/
class Style: public StyleAttrs
{
private:
static int totalRef;
int refCount;
static lout::container::typed::HashTable <StyleAttrs, Style> *styleTable;
Style (StyleAttrs *attrs);
protected:
~Style();
void copyAttrs (StyleAttrs *attrs);
public:
inline static Style *create (Layout *layout, StyleAttrs *attrs)
{
Style *style = styleTable->get (attrs);
if (style) {
style->ref ();
} else {
style = new Style (attrs);
styleTable->put(style, style);
}
return style;
}
inline void ref () { refCount++; }
inline void unref () { if (--refCount == 0) delete this; }
};
/**
* \sa dw::core::style
*/
class TooltipAttrs: public lout::object::String
{
public:
TooltipAttrs(const char *text): lout::object::String(text) { }
};
/**
* \sa dw::core::style
*/
class Tooltip: public TooltipAttrs
{
private:
int refCount;
protected:
Tooltip (const char *text): TooltipAttrs(text) { refCount = 0; }
public:
static Tooltip *create (dw::core::Layout *layout, const char *text);
inline void ref () { refCount++; }
inline void unref ()
{ if (--refCount == 0) delete this; }
inline virtual void onEnter () { }
inline virtual void onLeave () { }
inline virtual void onMotion () { }
};
/**
* \sa dw::core::style
*/
class FontAttrs: public lout::object::Object
{
public:
const char *name;
int size;
int weight;
int letterSpacing;
FontVariant fontVariant;
FontStyle style;
bool equals(lout::object::Object *other);
int hashValue();
};
/**
* \sa dw::core::style
*/
class Font: public FontAttrs
{
private:
int refCount;
static Font *create0 (Layout *layout, FontAttrs *attrs, bool tryEverything);
protected:
inline Font () { refCount = 0; }
virtual ~Font ();
void copyAttrs (FontAttrs *attrs);
public:
int ascent, descent;
int spaceWidth;
int xHeight;
static Font *create (Layout *layout, FontAttrs *attrs);
static bool exists (Layout *layout, const char *name);
inline void ref () { refCount++; }
inline void unref () { if (--refCount == 0) delete this; }
};
/**
* \sa dw::core::style
*/
class ColorAttrs: public lout::object::Object
{
protected:
int color;
public:
inline ColorAttrs(int color)
{
this->color = color;
}
inline int getColor () { return color; }
bool equals(lout::object::Object *other);
int hashValue();
};
/**
* \sa dw::core::style
*/
class Color: public ColorAttrs
{
private:
int refCount;
void remove(dw::core::Layout *layout);
int shadeColor (int color, int d);
protected:
inline Color (int color): ColorAttrs (color) {
refCount = 0; }
virtual ~Color ();
public:
enum Shading { SHADING_NORMAL, SHADING_INVERSE, SHADING_DARK, SHADING_LIGHT,
SHADING_NUM };
protected:
int shadeColor (int color, Shading shading);
public:
static Color *create (Layout *layout, int color);
inline void ref () { refCount++; }
inline void unref ()
{ if (--refCount == 0) delete this; }
};
void drawBorder (View *view, Rectangle *area,
int x, int y, int width, int height,
Style *style, bool inverse);
void drawBackground (View *view, Rectangle *area,
int x, int y, int width, int height,
Style *style, bool inverse);
void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType);
} // namespace style
} // namespace dw
} // namespace core
#endif // __DW_STYLE_HH__