borders for widgets - initial working implementation

This commit is contained in:
gazer 2017-10-12 20:16:48 +03:00
parent b5eb939a46
commit e8f11036c9
2 changed files with 106 additions and 40 deletions

View File

@ -334,6 +334,7 @@ class GradientDrawable : Drawable {
protected uint _color2; // bottom left
protected uint _color3; // top right
protected uint _color4; // bottom right
this(uint angle, uint color1, uint color2) {
// rotate a gradient; angle goes clockwise
import std.math;
@ -370,35 +371,42 @@ class GradientDrawable : Drawable {
}
}
}
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
buf.fillGradientRect(rc, _color1, _color2, _color3, _color4);
}
@property override int width() { return 1; }
@property override int height() { return 1; }
}
/// solid borders (may be of different width) and, optionally, solid inner area
class FrameDrawable : Drawable {
protected uint _frameColor; // frame color
protected Rect _frameWidths; // left, top, right, bottom border widths, in pixels
class BorderDrawable : Drawable {
protected uint _borderColor;
protected Rect _borderWidths; // left, top, right, bottom border widths, in pixels
protected uint _middleColor; // middle area color (may be transparent)
this(uint frameColor, Rect borderWidths, uint innerAreaColor = 0xFFFFFFFF) {
_frameColor = frameColor;
_frameWidths = borderWidths;
this(uint borderColor, Rect borderWidths, uint innerAreaColor = 0xFFFFFFFF) {
_borderColor = borderColor;
_borderWidths = borderWidths;
_middleColor = innerAreaColor;
}
this(uint frameColor, int borderWidth, uint innerAreaColor = 0xFFFFFFFF) {
_frameColor = frameColor;
_frameWidths = Rect(borderWidth, borderWidth, borderWidth, borderWidth);
this(uint borderColor, int borderWidth, uint innerAreaColor = 0xFFFFFFFF) {
_borderColor = borderColor;
_borderWidths = Rect(borderWidth, borderWidth, borderWidth, borderWidth);
_middleColor = innerAreaColor;
}
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
buf.drawFrame(rc, _frameColor, _frameWidths, _middleColor);
buf.drawFrame(rc, _borderColor, _borderWidths, _middleColor);
}
@property override int width() { return 1 + _frameWidths.left + _frameWidths.right; }
@property override int height() { return 1 + _frameWidths.top + _frameWidths.bottom; }
@property override Rect padding() { return _frameWidths; }
@property override int width() { return 1 + _borderWidths.left + _borderWidths.right; }
@property override int height() { return 1 + _borderWidths.top + _borderWidths.bottom; }
@property override Rect padding() { return _borderWidths; }
}
deprecated alias FrameDrawable = BorderDrawable;
enum DimensionUnits {
pixels,
@ -480,18 +488,18 @@ static if (BACKEND_CONSOLE) {
}
}
/// decode solid color / gradient / frame drawable from string like #AARRGGBB, e.g. #5599AA
/// decode solid color / gradient / border drawable from string like #AARRGGBB, e.g. #5599AA
///
/// SolidFillDrawable: #AARRGGBB - e.g. #8090A0 or #80ffffff
/// GradientDrawable: #linear,Ndeg,#firstColor,#secondColor
/// FrameDrawable: #frameColor,frameWidth[,#middleColor]
/// or #frameColor,leftBorderWidth,topBorderWidth,rightBorderWidth,bottomBorderWidth[,#middleColor]
/// e.g. #000000,2,#C0FFFFFF - black frame of width 2 with 75% transparent white middle
/// e.g. #0000FF,2,3,4,5,#FFFFFF - blue frame with left,top,right,bottom borders of width 2,3,4,5 and white inner area
/// BorderDrawable: #borderColor,borderWidth[,#middleColor]
/// or #borderColor,leftBorderWidth,topBorderWidth,rightBorderWidth,bottomBorderWidth[,#middleColor]
/// e.g. #000000,2,#C0FFFFFF - black border of width 2 with 75% transparent white middle
/// e.g. #0000FF,2,3,4,5,#FFFFFF - blue border with left,top,right,bottom borders of width 2,3,4,5 and white inner area
static Drawable createColorDrawable(string s) {
Log.d("creating color drawable ", s);
enum DrawableType { SolidColor, LinearGradient, Frame }
enum DrawableType { SolidColor, LinearGradient, Border }
auto type = DrawableType.SolidColor;
string[] items = s.split(',');
@ -505,7 +513,7 @@ static Drawable createColorDrawable(string s) {
values ~= decodeAngle(item);
else {
values ~= decodeDimension(item);
type = DrawableType.Frame;
type = DrawableType.Border;
}
if (i >= 6)
break;
@ -515,15 +523,15 @@ static Drawable createColorDrawable(string s) {
return new SolidFillDrawable(values[0]);
else if (type == DrawableType.LinearGradient && values.length == 3) // angle and two gradient colors
return new GradientDrawable(values[0], values[1], values[2]);
else if (type == DrawableType.Frame) {
if (values.length == 2) // frame color and frame width, with transparent inner area - #AARRGGBB,NN
return new FrameDrawable(values[0], values[1]);
else if (values.length == 3) // frame color, frame width, inner area color - #AARRGGBB,NN,#AARRGGBB
return new FrameDrawable(values[0], values[1], values[2]);
else if (values.length == 5) // frame color, frame widths for left,top,right,bottom and transparent inner area - #AARRGGBB,NNleft,NNtop,NNright,NNbottom
return new FrameDrawable(values[0], Rect(values[1], values[2], values[3], values[4]));
else if (values.length == 6) // frame color, frame widths for left,top,right,bottom, inner area color - #AARRGGBB,NNleft,NNtop,NNright,NNbottom,#AARRGGBB
return new FrameDrawable(values[0], Rect(values[1], values[2], values[3], values[4]), values[5]);
else if (type == DrawableType.Border) {
if (values.length == 2) // border color and border width, with transparent inner area - #AARRGGBB,NN
return new BorderDrawable(values[0], values[1]);
else if (values.length == 3) // border color, border width, inner area color - #AARRGGBB,NN,#AARRGGBB
return new BorderDrawable(values[0], values[1], values[2]);
else if (values.length == 5) // border color, border widths for left,top,right,bottom and transparent inner area - #AARRGGBB,NNleft,NNtop,NNright,NNbottom
return new BorderDrawable(values[0], Rect(values[1], values[2], values[3], values[4]));
else if (values.length == 6) // border color, border widths for left,top,right,bottom, inner area color - #AARRGGBB,NNleft,NNtop,NNright,NNbottom,#AARRGGBB
return new BorderDrawable(values[0], Rect(values[1], values[2], values[3], values[4]), values[5]);
}
Log.e("Invalid drawable string format: ", s);
return new EmptyDrawable(); // invalid format - just return empty drawable
@ -1122,6 +1130,44 @@ class StateDrawable : Drawable {
}
}
/// Drawable which allows to combine together background image, gradient, borders, box shadows, etc.
class CombinedDrawable : Drawable {
DrawableRef background;
Drawable border;
this(string backgroundImageId, string borderDescription) {
background = backgroundImageId !is null ? drawableCache.get(backgroundImageId) : new EmptyDrawable;
border = borderDescription !is null ? createColorDrawable(borderDescription) : new EmptyDrawable;
}
~this() {
destroy(background);
destroy(border);
background = null;
border = null;
}
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
// make background image smaller to fit borders
Rect backrc = rc;
backrc.left += border.padding.left;
backrc.top += border.padding.top;
backrc.right -= border.padding.right;
backrc.bottom -= border.padding.bottom;
background.drawTo(buf, backrc, state, tilex0, tiley0);
border.drawTo(buf, rc, state, tilex0, tiley0);
}
@property override int width() { return background.width + border.padding.left + border.padding.right; }
@property override int height() { return background.height + border.padding.top + border.padding.bottom; }
@property override Rect padding() {
return Rect(background.padding.left + border.padding.left, background.padding.top + border.padding.top,
background.padding.right + border.padding.right, background.padding.bottom + border.padding.bottom);
}
}
alias DrawableRef = Ref!Drawable;
@ -1336,7 +1382,7 @@ class DrawableCache {
if (!_drawable)
_error = true;
} else if (_filename.startsWith("#")) {
// color reference #AARRGGBB, e.g. #5599AA, or FrameDrawable description string #frameColor,frameSize,#innerColor
// color reference #AARRGGBB, e.g. #5599AA, or a gradient, or BorderDrawable description
_drawable = createColorDrawable(_filename);
} else if (_filename.startsWith("{")) {
// json in {} with text drawable description

View File

@ -324,6 +324,7 @@ protected:
uint _alpha;
string _fontFace;
string _backgroundImageId;
string _border;
Rect _padding;
Rect _margins;
int _minWidth = SIZE_UNSPECIFIED;
@ -411,7 +412,9 @@ public:
if (!(cast(Style)this)._backgroundDrawable.isNull)
return (cast(Style)this)._backgroundDrawable;
string image = backgroundImageId;
if (image !is null) {
if (border !is null) {
(cast(Style)this)._backgroundDrawable = new CombinedDrawable(image, border);
} else if (image !is null) {
(cast(Style)this)._backgroundDrawable = drawableCache.get(image);
} else {
uint color = backgroundColor;
@ -527,6 +530,15 @@ public:
return parentStyle.fontSize;
}
/// border
@property string border() const {
if (_border !is null)
return _border;
else {
return parentStyle.border;
}
}
//===================================================
// layout parameters: margins / padding
@ -587,7 +599,7 @@ public:
return parentStyle.backgroundColor;
}
/// font size
/// background image id
@property string backgroundImageId() const {
if (_backgroundImageId == COLOR_DRAWABLE)
return null;
@ -779,6 +791,12 @@ public:
return this;
}
@property Style border(string s) {
_border = s;
_backgroundDrawable.clear();
return this;
}
@property Style margins(Rect rc) {
_margins = rc;
return this;
@ -890,6 +908,7 @@ public:
res._alpha = _alpha;
res._fontFace = _fontFace;
res._backgroundImageId = _backgroundImageId;
res._border = _border;
res._padding = _padding;
res._margins = _margins;
res._minWidth = _minWidth;
@ -1019,6 +1038,10 @@ class Theme : Style {
@property override string backgroundImageId() const {
return _backgroundImageId;
}
/// border
@property override string border() const {
return _border;
}
/// minimal width constraint, 0 if limit is not set
@property override uint minWidth() const {
return _minWidth;
@ -1483,19 +1506,16 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
//Log.d("Theme: loadStyleAttributes ", style.id, " ", elem.tag.attr);
if ("backgroundImageId" in elem.tag.attr)
style.backgroundImageId = elem.tag.attr["backgroundImageId"];
if ("backgroundColor" in elem.tag.attr) {
uint col = decodeHexColor(elem.tag.attr["backgroundColor"]);
style.backgroundColor = col;
//Log.d(" background color=", col);
} else {
//Log.d(" no background color attr");
}
if ("backgroundColor" in elem.tag.attr)
style.backgroundColor = decodeHexColor(elem.tag.attr["backgroundColor"]);
if ("textColor" in elem.tag.attr)
style.textColor = decodeHexColor(elem.tag.attr["textColor"]);
if ("margins" in elem.tag.attr)
style.margins = decodeRect(elem.tag.attr["margins"]);
if ("padding" in elem.tag.attr)
style.padding = decodeRect(elem.tag.attr["padding"]);
if ("border" in elem.tag.attr)
style.border = elem.tag.attr["border"];
if ("align" in elem.tag.attr)
style.alignment = decodeAlignment(elem.tag.attr["align"]);
if ("minWidth" in elem.tag.attr)
@ -1549,7 +1569,7 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
if (colorid)
style.setCustomColor(colorid, color);
} else if (item.tag.name.equal("length")) {
// <color id="buttons_panel_color" value="#303080"/>
// <length id="overlap" value="2"/>
string lenid = attrValue(item, "id");
string lenvalue = attrValue(item, "value");
uint len = decodeDimension(lenvalue);