There's more to do. Why make this const-correct, instead of ditch it? Because whatever I replace it with has to be ready for const correctness.
924 lines
24 KiB
C++
924 lines
24 KiB
C++
#ifndef __DW_STYLE_HH__
|
|
#define __DW_STYLE_HH__
|
|
|
|
#include <stdint.h>
|
|
#include <math.h>
|
|
|
|
#ifndef __INCLUDED_FROM_DW_CORE_HH__
|
|
# error Do not include this file directly, use "core.hh" instead.
|
|
#endif
|
|
|
|
#include <limits.h>
|
|
|
|
#include "../lout/signal.hh"
|
|
#include "../lout/debug.hh"
|
|
|
|
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 from 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 BackgroundRepeat {
|
|
BACKGROUND_REPEAT,
|
|
BACKGROUND_REPEAT_X,
|
|
BACKGROUND_REPEAT_Y,
|
|
BACKGROUND_NO_REPEAT
|
|
};
|
|
|
|
enum BackgroundAttachment {
|
|
BACKGROUND_ATTACHMENT_SCROLL,
|
|
BACKGROUND_ATTACHMENT_FIXED
|
|
};
|
|
|
|
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_INLINE_BLOCK,
|
|
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 Overflow {
|
|
OVERFLOW_VISIBLE,
|
|
OVERFLOW_HIDDEN,
|
|
OVERFLOW_SCROLL,
|
|
OVERFLOW_AUTO
|
|
};
|
|
|
|
enum Position {
|
|
POSITION_STATIC,
|
|
POSITION_RELATIVE,
|
|
POSITION_ABSOLUTE,
|
|
POSITION_FIXED
|
|
};
|
|
|
|
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
|
|
};
|
|
|
|
enum FloatType {
|
|
FLOAT_NONE,
|
|
FLOAT_LEFT,
|
|
FLOAT_RIGHT
|
|
};
|
|
|
|
enum ClearType {
|
|
CLEAR_LEFT,
|
|
CLEAR_RIGHT,
|
|
CLEAR_BOTH,
|
|
CLEAR_NONE
|
|
};
|
|
|
|
enum {
|
|
/**
|
|
* \brief 'z-index' is stored as int; use this for the value 'auto'.
|
|
*
|
|
* Only some random value, which has to be checked explicitly; do
|
|
* not compare this (less or greater) to integer values of
|
|
* 'z-index'.
|
|
*/
|
|
Z_INDEX_AUTO = INT_MAX
|
|
};
|
|
|
|
/**
|
|
* \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.
|
|
*
|
|
* When possible, do not use this function directly; it may be removed
|
|
* soon. Instead, use multiplyWithPerLength or multiplyWithPerLengthRounded.
|
|
*/
|
|
inline double perLengthVal_useThisOnlyForDebugging(Length l)
|
|
{ return (double)(l & ~3) / (1 << 18); }
|
|
|
|
/** \brief Returns the value of a relative length, as a float.
|
|
*
|
|
* When possible, do not use this function directly; it may be removed
|
|
* soon.
|
|
*/
|
|
inline double relLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
|
|
|
|
/**
|
|
* \brief Multiply an int with a percentage length, returning int.
|
|
*
|
|
* Use this instead of perLengthVal, when possible.
|
|
*/
|
|
inline int multiplyWithPerLength(int x, Length l) {
|
|
return (int) round((double) x * perLengthVal_useThisOnlyForDebugging (l));
|
|
}
|
|
|
|
/**
|
|
* \brief Like multiplyWithPerLength, but rounds to nearest integer
|
|
* instead of down.
|
|
*
|
|
* (This function exists for backward compatibility.)
|
|
*/
|
|
inline int multiplyWithPerLengthRounded(int x, Length l) {
|
|
return lout::misc::roundInt (x * perLengthVal_useThisOnlyForDebugging (l));
|
|
}
|
|
|
|
inline int multiplyWithRelLength(int x, Length l) {
|
|
return x * relLengthVal(l);
|
|
}
|
|
|
|
|
|
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 (const Box *other) const {
|
|
return top == other->top &&
|
|
right == other->right &&
|
|
bottom == other->bottom &&
|
|
left == other->left;
|
|
}
|
|
inline int hashValue () {
|
|
return top + right + bottom + left;
|
|
}
|
|
};
|
|
|
|
class Tooltip;
|
|
class Font;
|
|
class Color;
|
|
class StyleImage;
|
|
|
|
/**
|
|
* \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;
|
|
StyleImage *backgroundImage;
|
|
BackgroundRepeat backgroundRepeat;
|
|
BackgroundAttachment backgroundAttachment;
|
|
Length backgroundPositionX; // "left" defined by "0%" etc. (see CSS spec)
|
|
Length backgroundPositionY; // "top" defined by "0%" etc. (see CSS spec)
|
|
|
|
TextAlignType textAlign;
|
|
VAlignType valign;
|
|
char textAlignChar; /* In future, strings will be supported. */
|
|
TextTransform textTransform;
|
|
|
|
FloatType vloat; /* "float" is a keyword. */
|
|
ClearType clear;
|
|
|
|
Overflow overflow;
|
|
|
|
Position position;
|
|
Length top, bottom, left, right;
|
|
|
|
int hBorderSpacing, vBorderSpacing, wordSpacing;
|
|
Length width, height, lineHeight, textIndent;
|
|
Length minWidth, maxWidth, minHeight, maxHeight;
|
|
|
|
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 zIndex;
|
|
|
|
int x_link;
|
|
int x_img;
|
|
Tooltip *x_tooltip;
|
|
char x_lang[2]; /* Either x_lang[0] == x_lang[1] == 0 (no language
|
|
set), or x_lang contains the RFC 1766 country
|
|
code in lower case letters. (Only two letters
|
|
allowed, currently.) */
|
|
|
|
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 || backgroundImage != NULL; }
|
|
|
|
bool equals (const lout::object::Object *other) const override;
|
|
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 (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(const lout::object::Object *other) const override;
|
|
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 () {
|
|
DBG_OBJ_CREATE ("dw::core::style::Font");
|
|
refCount = 0;
|
|
}
|
|
virtual ~Font ();
|
|
|
|
void copyAttrs (FontAttrs *attrs);
|
|
|
|
public:
|
|
int ascent, descent;
|
|
int spaceWidth;
|
|
int xHeight;
|
|
int zeroWidth;
|
|
|
|
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(const lout::object::Object *other) const override;
|
|
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) {
|
|
DBG_OBJ_CREATE ("dw::core::style::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; }
|
|
};
|
|
|
|
|
|
class StyleImage: public lout::signal::ObservedObject
|
|
{
|
|
private:
|
|
class StyleImgRenderer: public ImgRenderer
|
|
{
|
|
private:
|
|
StyleImage *image;
|
|
|
|
public:
|
|
inline StyleImgRenderer (StyleImage *image) { this->image = image; }
|
|
|
|
void setBuffer (core::Imgbuf *buffer, bool resize);
|
|
void drawRow (int row);
|
|
void finish ();
|
|
void fatal ();
|
|
};
|
|
|
|
int refCount, tilesX, tilesY;
|
|
Imgbuf *imgbufSrc, *imgbufTiled;
|
|
ImgRendererDist *imgRendererDist;
|
|
StyleImgRenderer *styleImgRenderer;
|
|
|
|
StyleImage ();
|
|
~StyleImage ();
|
|
|
|
public:
|
|
/**
|
|
* \brief Useful (but not mandatory) base class for updates of
|
|
* areas with background images.
|
|
*/
|
|
class ExternalImgRenderer: public ImgRenderer
|
|
{
|
|
public:
|
|
void setBuffer (core::Imgbuf *buffer, bool resize);
|
|
void drawRow (int row);
|
|
void finish ();
|
|
void fatal ();
|
|
|
|
/**
|
|
* \brief If this method returns false, nothing is done at all.
|
|
*/
|
|
virtual bool readyToDraw () = 0;
|
|
|
|
/**
|
|
* \brief Return the area covered by the background image.
|
|
*/
|
|
virtual void getBgArea (int *x, int *y, int *width, int *height) = 0;
|
|
|
|
/**
|
|
* \brief Return the "reference area".
|
|
*
|
|
* See comment of "drawBackground".
|
|
*/
|
|
virtual void getRefArea (int *xRef, int *yRef, int *widthRef,
|
|
int *heightRef) = 0;
|
|
|
|
virtual StyleImage *getBackgroundImage () = 0;
|
|
virtual BackgroundRepeat getBackgroundRepeat () = 0;
|
|
virtual BackgroundAttachment getBackgroundAttachment () = 0;
|
|
virtual Length getBackgroundPositionX () = 0;
|
|
virtual Length getBackgroundPositionY () = 0;
|
|
|
|
/**
|
|
* \brief Draw (or queue for drawing) an area, which is given in
|
|
* canvas coordinates.
|
|
*/
|
|
virtual void draw (int x, int y, int width, int height) = 0;
|
|
};
|
|
|
|
/**
|
|
* \brief Suitable for widgets and parts of widgets.
|
|
*/
|
|
class ExternalWidgetImgRenderer: public ExternalImgRenderer
|
|
{
|
|
public:
|
|
void getPaddingArea (int *x, int *y, int *width, int *height);
|
|
|
|
StyleImage *getBackgroundImage ();
|
|
BackgroundRepeat getBackgroundRepeat ();
|
|
BackgroundAttachment getBackgroundAttachment ();
|
|
Length getBackgroundPositionX ();
|
|
Length getBackgroundPositionY ();
|
|
|
|
/**
|
|
* \brief Return the style this background image is part of.
|
|
*/
|
|
virtual Style *getStyle () = 0;
|
|
};
|
|
|
|
static StyleImage *create () { return new StyleImage (); }
|
|
|
|
inline void ref () { refCount++; }
|
|
inline void unref ()
|
|
{ if (--refCount == 0) delete this; }
|
|
|
|
inline Imgbuf *getImgbufSrc () { return imgbufSrc; }
|
|
inline Imgbuf *getImgbufTiled (bool repeatX, bool repeatY)
|
|
{ return (imgbufTiled && repeatX && repeatY) ? imgbufTiled : imgbufSrc; }
|
|
inline int getTilesX (bool repeatX, bool repeatY)
|
|
{ return (imgbufTiled && repeatX && repeatY) ? tilesX : 1; }
|
|
inline int getTilesY (bool repeatX, bool repeatY)
|
|
{ return (imgbufTiled && repeatX && repeatY) ? tilesY : 1; }
|
|
inline ImgRenderer *getMainImgRenderer () { return imgRendererDist; }
|
|
|
|
/**
|
|
* \brief Add an additional ImgRenderer, especially used for
|
|
* drawing.
|
|
*/
|
|
inline void putExternalImgRenderer (std::unique_ptr< ImgRenderer > ir)
|
|
{ imgRendererDist->put( std::move( ir ) ); }
|
|
|
|
/**
|
|
* \brief Remove a previously added additional ImgRenderer.
|
|
*/
|
|
inline void removeExternalImgRenderer (ImgRenderer *ir)
|
|
{ imgRendererDist->remove (ir); }
|
|
};
|
|
|
|
void drawBorder (View *view, Layout *layout, Rectangle *area,
|
|
int x, int y, int width, int height,
|
|
Style *style, bool inverse);
|
|
void drawBackground (View *view, Layout *layout, Rectangle *area,
|
|
int x, int y, int width, int height,
|
|
int xRef, int yRef, int widthRef, int heightRef,
|
|
Style *style, Color *bgColor, bool inverse, bool atTop);
|
|
void drawBackgroundImage (View *view, StyleImage *backgroundImage,
|
|
BackgroundRepeat backgroundRepeat,
|
|
BackgroundAttachment backgroundAttachment,
|
|
Length backgroundPositionX,
|
|
Length backgroundPositionY,
|
|
int x, int y, int width, int height,
|
|
int xRef, int yRef, int widthRef, int heightRef);
|
|
void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType);
|
|
|
|
} // namespace style
|
|
} // namespace core
|
|
} // namespace dw
|
|
|
|
#endif // __DW_STYLE_HH__
|
|
|