mirror of https://github.com/buggins/dlangui.git
Merge pull request #481 from dayllenger/work
Linear gradients as background
This commit is contained in:
commit
8a0da9f8db
|
@ -195,7 +195,7 @@ uint blendARGB(uint dst, uint src, uint alpha) pure nothrow {
|
||||||
uint dstr = (dst >> 16) & 0xFF;
|
uint dstr = (dst >> 16) & 0xFF;
|
||||||
uint dstg = (dst >> 8) & 0xFF;
|
uint dstg = (dst >> 8) & 0xFF;
|
||||||
uint dstb = (dst >> 0) & 0xFF;
|
uint dstb = (dst >> 0) & 0xFF;
|
||||||
uint ialpha = 256 - alpha;
|
uint ialpha = 255 - alpha;
|
||||||
uint r = ((srcr * ialpha + dstr * alpha) >> 8) & 0xFF;
|
uint r = ((srcr * ialpha + dstr * alpha) >> 8) & 0xFF;
|
||||||
uint g = ((srcg * ialpha + dstg * alpha) >> 8) & 0xFF;
|
uint g = ((srcg * ialpha + dstg * alpha) >> 8) & 0xFF;
|
||||||
uint b = ((srcb * ialpha + dstb * alpha) >> 8) & 0xFF;
|
uint b = ((srcb * ialpha + dstb * alpha) >> 8) & 0xFF;
|
||||||
|
|
|
@ -288,6 +288,8 @@ class DrawBuf : RefCountedObject {
|
||||||
abstract void fill(uint color);
|
abstract void fill(uint color);
|
||||||
/// fill rectangle with solid color (clipping is applied)
|
/// fill rectangle with solid color (clipping is applied)
|
||||||
abstract void fillRect(Rect rc, uint color);
|
abstract void fillRect(Rect rc, uint color);
|
||||||
|
/// fill rectangle with a gradient (clipping is applied)
|
||||||
|
abstract void fillGradientRect(Rect rc, uint color1, uint color2, uint color3, uint color4);
|
||||||
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
||||||
void fillRectPattern(Rect rc, uint color, int pattern) {
|
void fillRectPattern(Rect rc, uint color, int pattern) {
|
||||||
// default implementation: does not support patterns
|
// default implementation: does not support patterns
|
||||||
|
@ -1161,6 +1163,11 @@ class ColorDrawBufBase : DrawBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void fillGradientRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||||
|
// TODO
|
||||||
|
fillRect(rc, color1);
|
||||||
|
}
|
||||||
|
|
||||||
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
||||||
override void fillRectPattern(Rect rc, uint color, int pattern) {
|
override void fillRectPattern(Rect rc, uint color, int pattern) {
|
||||||
uint alpha = color >> 24;
|
uint alpha = color >> 24;
|
||||||
|
@ -1406,6 +1413,11 @@ class GrayDrawBuf : DrawBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void fillGradientRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||||
|
// TODO
|
||||||
|
fillRect(rc, color1);
|
||||||
|
}
|
||||||
|
|
||||||
/// draw pixel at (x, y) with specified color
|
/// draw pixel at (x, y) with specified color
|
||||||
override void drawPixel(int x, int y, uint color) {
|
override void drawPixel(int x, int y, uint color) {
|
||||||
if (!_clipRect.isPointInside(x, y))
|
if (!_clipRect.isPointInside(x, y))
|
||||||
|
|
|
@ -114,6 +114,17 @@ class GLDrawBuf : DrawBuf, GLConfigCallback {
|
||||||
_scene.add(new SolidRectSceneItem(rc, color));
|
_scene.add(new SolidRectSceneItem(rc, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// fill rectangle with a gradient (clipping is applied)
|
||||||
|
override void fillGradientRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||||
|
assert(_scene !is null);
|
||||||
|
color1 = applyAlpha(color1);
|
||||||
|
color2 = applyAlpha(color2);
|
||||||
|
color3 = applyAlpha(color3);
|
||||||
|
color4 = applyAlpha(color4);
|
||||||
|
if (!(isFullyTransparentColor(color1) && isFullyTransparentColor(color3)) && applyClipping(rc))
|
||||||
|
_scene.add(new GradientRectSceneItem(rc, color1, color2, color3, color4));
|
||||||
|
}
|
||||||
|
|
||||||
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
||||||
override void fillRectPattern(Rect rc, uint color, int pattern) {
|
override void fillRectPattern(Rect rc, uint color, int pattern) {
|
||||||
if (pattern == PatternType.solid)
|
if (pattern == PatternType.solid)
|
||||||
|
@ -749,6 +760,27 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class GradientRectSceneItem : SceneItem {
|
||||||
|
private:
|
||||||
|
Rect _rc;
|
||||||
|
uint _color1;
|
||||||
|
uint _color2;
|
||||||
|
uint _color3;
|
||||||
|
uint _color4;
|
||||||
|
|
||||||
|
public:
|
||||||
|
this(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||||
|
_rc = rc;
|
||||||
|
_color1 = color1;
|
||||||
|
_color2 = color2;
|
||||||
|
_color3 = color3;
|
||||||
|
_color4 = color4;
|
||||||
|
}
|
||||||
|
override void draw() {
|
||||||
|
glSupport.queue.addGradientRect(_rc, _color1, _color2, _color3, _color4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class PatternRectSceneItem : SceneItem {
|
private class PatternRectSceneItem : SceneItem {
|
||||||
private:
|
private:
|
||||||
Rect _rc;
|
Rect _rc;
|
||||||
|
|
|
@ -322,13 +322,61 @@ class SolidFillDrawable : Drawable {
|
||||||
_color = color;
|
_color = color;
|
||||||
}
|
}
|
||||||
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
|
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
|
||||||
if ((_color >> 24) != 0xFF) // not fully transparent
|
if (!_color.isFullyTransparentColor)
|
||||||
buf.fillRect(rc, _color);
|
buf.fillRect(rc, _color);
|
||||||
}
|
}
|
||||||
@property override int width() { return 1; }
|
@property override int width() { return 1; }
|
||||||
@property override int height() { return 1; }
|
@property override int height() { return 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GradientDrawable : Drawable {
|
||||||
|
protected uint _color1; // top left
|
||||||
|
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;
|
||||||
|
float radians = angle * PI / 180;
|
||||||
|
float c = cos(radians);
|
||||||
|
float s = sin(radians);
|
||||||
|
if (s >= 0) {
|
||||||
|
if (c >= 0) {
|
||||||
|
// 0-90 degrees
|
||||||
|
_color1 = blendARGB(color1, color2, cast(uint)(255 * c));
|
||||||
|
_color2 = color2;
|
||||||
|
_color3 = color1;
|
||||||
|
_color4 = blendARGB(color1, color2, cast(uint)(255 * s));
|
||||||
|
} else {
|
||||||
|
// 90-180 degrees
|
||||||
|
_color1 = color2;
|
||||||
|
_color2 = blendARGB(color1, color2, cast(uint)(255 * -c));
|
||||||
|
_color3 = blendARGB(color1, color2, cast(uint)(255 * s));
|
||||||
|
_color4 = color1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (c < 0) {
|
||||||
|
// 180-270 degrees
|
||||||
|
_color1 = blendARGB(color1, color2, cast(uint)(255 * -s));
|
||||||
|
_color2 = color1;
|
||||||
|
_color3 = color2;
|
||||||
|
_color4 = blendARGB(color1, color2, cast(uint)(255 * -c));
|
||||||
|
} else {
|
||||||
|
// 270-360 degrees
|
||||||
|
_color1 = color1;
|
||||||
|
_color2 = blendARGB(color1, color2, cast(uint)(255 * -s));
|
||||||
|
_color3 = blendARGB(color1, color2, cast(uint)(255 * c));
|
||||||
|
_color4 = color2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
/// solid borders (may be of different width) and, optionally, solid inner area
|
||||||
class FrameDrawable : Drawable {
|
class FrameDrawable : Drawable {
|
||||||
protected uint _frameColor; // frame color
|
protected uint _frameColor; // frame color
|
||||||
|
@ -399,6 +447,18 @@ static uint decodeDimension(string s) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// decode angle; only Ndeg format for now
|
||||||
|
static uint decodeAngle(string s) {
|
||||||
|
int angle;
|
||||||
|
if (s.endsWith("deg"))
|
||||||
|
angle = to!int(s[0 .. $ - 3]);
|
||||||
|
else
|
||||||
|
Log.e("Invalid angle format: ", s);
|
||||||
|
|
||||||
|
// transform the angle to [0, 360)
|
||||||
|
return ((angle % 360) + 360) % 360;
|
||||||
|
}
|
||||||
|
|
||||||
static if (BACKEND_CONSOLE) {
|
static if (BACKEND_CONSOLE) {
|
||||||
/**
|
/**
|
||||||
Sample format:
|
Sample format:
|
||||||
|
@ -423,39 +483,48 @@ static if (BACKEND_CONSOLE) {
|
||||||
/// decode solid color / gradient / frame drawable from string like #AARRGGBB, e.g. #5599AA
|
/// decode solid color / gradient / frame drawable from string like #AARRGGBB, e.g. #5599AA
|
||||||
///
|
///
|
||||||
/// SolidFillDrawable: #AARRGGBB - e.g. #8090A0 or #80ffffff
|
/// SolidFillDrawable: #AARRGGBB - e.g. #8090A0 or #80ffffff
|
||||||
|
/// GradientDrawable: #linear,Ndeg,#firstColor,#secondColor
|
||||||
/// FrameDrawable: #frameColor,frameWidth[,#middleColor]
|
/// FrameDrawable: #frameColor,frameWidth[,#middleColor]
|
||||||
/// or #frameColor,leftBorderWidth,topBorderWidth,rightBorderWidth,bottomBorderWidth[,#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. #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
|
/// 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
|
||||||
static Drawable createColorDrawable(string s) {
|
static Drawable createColorDrawable(string s) {
|
||||||
Log.d("creating color drawable ", s);
|
Log.d("creating color drawable ", s);
|
||||||
uint[6] values;
|
|
||||||
int valueCount = 0;
|
enum DrawableType { SolidColor, LinearGradient, Frame }
|
||||||
int start = 0;
|
auto type = DrawableType.SolidColor;
|
||||||
for (int i = 0; i <= s.length; i++) {
|
|
||||||
if (i == s.length || s[i] == ',') {
|
string[] items = s.split(',');
|
||||||
if (i > start) {
|
uint[] values;
|
||||||
string item = s[start .. i];
|
foreach (i, item; items) {
|
||||||
if (item.startsWith("#"))
|
if (item == "#linear")
|
||||||
values[valueCount++] = decodeHexColor(item);
|
type = DrawableType.LinearGradient;
|
||||||
else
|
else if (item.startsWith("#"))
|
||||||
values[valueCount++] = decodeDimension(item);
|
values ~= decodeHexColor(item);
|
||||||
if (valueCount >= 6)
|
else if (item.endsWith("deg"))
|
||||||
|
values ~= decodeAngle(item);
|
||||||
|
else {
|
||||||
|
values ~= decodeDimension(item);
|
||||||
|
type = DrawableType.Frame;
|
||||||
|
}
|
||||||
|
if (i >= 6)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
start = i + 1;
|
|
||||||
}
|
if (type == DrawableType.SolidColor && values.length == 1) // only color #AARRGGBB
|
||||||
}
|
|
||||||
if (valueCount == 1) // only color #AARRGGBB
|
|
||||||
return new SolidFillDrawable(values[0]);
|
return new SolidFillDrawable(values[0]);
|
||||||
else if (valueCount == 2) // frame color and frame width, with transparent inner area - #AARRGGBB,NN
|
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]);
|
return new FrameDrawable(values[0], values[1]);
|
||||||
else if (valueCount == 3) // frame color, frame width, inner area color - #AARRGGBB,NN,#AARRGGBB
|
else if (values.length == 3) // frame color, frame width, inner area color - #AARRGGBB,NN,#AARRGGBB
|
||||||
return new FrameDrawable(values[0], values[1], values[2]);
|
return new FrameDrawable(values[0], values[1], values[2]);
|
||||||
else if (valueCount == 5) // frame color, frame widths for left,top,right,bottom and transparent inner area - #AARRGGBB,NNleft,NNtop,NNright,NNbottom
|
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]));
|
return new FrameDrawable(values[0], Rect(values[1], values[2], values[3], values[4]));
|
||||||
else if (valueCount == 6) // frame color, frame widths for left,top,right,bottom, inner area color - #AARRGGBB,NNleft,NNtop,NNright,NNbottom,#AARRGGBB
|
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]);
|
return new FrameDrawable(values[0], Rect(values[1], values[2], values[3], values[4]), values[5]);
|
||||||
|
}
|
||||||
Log.e("Invalid drawable string format: ", s);
|
Log.e("Invalid drawable string format: ", s);
|
||||||
return new EmptyDrawable(); // invalid format - just return empty drawable
|
return new EmptyDrawable(); // invalid format - just return empty drawable
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,6 +406,11 @@ class ConsoleDrawBuf : DrawBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void fillGradientRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||||
|
// TODO
|
||||||
|
fillRect(rc, color1);
|
||||||
|
}
|
||||||
|
|
||||||
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
/// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
|
||||||
override void fillRectPattern(Rect rc, uint color, int pattern) {
|
override void fillRectPattern(Rect rc, uint color, int pattern) {
|
||||||
// default implementation: does not support patterns
|
// default implementation: does not support patterns
|
||||||
|
|
Loading…
Reference in New Issue