diff --git a/src/dlangui/graphics/resources.d b/src/dlangui/graphics/resources.d
index bd29ea3b..30713bd3 100644
--- a/src/dlangui/graphics/resources.d
+++ b/src/dlangui/graphics/resources.d
@@ -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
diff --git a/src/dlangui/widgets/styles.d b/src/dlangui/widgets/styles.d
index 2cc99952..a96bf9f0 100644
--- a/src/dlangui/widgets/styles.d
+++ b/src/dlangui/widgets/styles.d
@@ -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")) {
- //
+ //
string lenid = attrValue(item, "id");
string lenvalue = attrValue(item, "value");
uint len = decodeDimension(lenvalue);