mirror of https://github.com/buggins/dlangui.git
focus rectangle support added
This commit is contained in:
parent
c532ca84e6
commit
c815bdbffe
|
@ -4,6 +4,7 @@
|
||||||
backgroundImageId="btn_background"
|
backgroundImageId="btn_background"
|
||||||
align="Center"
|
align="Center"
|
||||||
margins="5,5,5,5"
|
margins="5,5,5,5"
|
||||||
|
focusRectColors="#000"
|
||||||
/>
|
/>
|
||||||
<style id="BUTTON_TRANSPARENT"
|
<style id="BUTTON_TRANSPARENT"
|
||||||
backgroundImageId="btn_background_transparent"
|
backgroundImageId="btn_background_transparent"
|
||||||
|
|
|
@ -411,6 +411,32 @@ class DrawBuf : RefCountedObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// draw focus rectangle; vertical gradient supported - colors[0] is top color, colors[1] is bottom color
|
||||||
|
void drawFocusRect(Rect rc, const uint[] colors) {
|
||||||
|
// override for faster performance when using OpenGL
|
||||||
|
if (colors.length < 1)
|
||||||
|
return;
|
||||||
|
uint color1 = colors[0];
|
||||||
|
uint color2 = colors.length > 1 ? colors[1] : color1;
|
||||||
|
if (isFullyTransparentColor(color1) && isFullyTransparentColor(color2))
|
||||||
|
return;
|
||||||
|
// draw horizontal lines
|
||||||
|
for (int x = rc.left; x < rc.right; x++) {
|
||||||
|
if ((x ^ rc.top) & 1)
|
||||||
|
fillRect(Rect(x, rc.top, x + 1, rc.top + 1), color1);
|
||||||
|
if ((x ^ (rc.bottom - 1)) & 1)
|
||||||
|
fillRect(Rect(x, rc.bottom - 1, x + 1, rc.bottom), color2);
|
||||||
|
}
|
||||||
|
// draw vertical lines
|
||||||
|
for (int y = rc.top + 1; y < rc.bottom - 1; y++) {
|
||||||
|
uint color = color1 == color2 ? color1 : blendARGB(color2, color1, 255 / (rc.bottom - rc.top));
|
||||||
|
if ((y ^ rc.left) & 1)
|
||||||
|
fillRect(Rect(rc.left, y, rc.left + 1, y + 1), color);
|
||||||
|
if ((y ^ (rc.right - 1)) & 1)
|
||||||
|
fillRect(Rect(rc.right - 1, y, rc.right, y + 1), color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// create drawbuf with copy of current buffer with changed colors (returns this if not supported)
|
/// create drawbuf with copy of current buffer with changed colors (returns this if not supported)
|
||||||
DrawBuf transformColors(ref ColorTransform transform) {
|
DrawBuf transformColors(ref ColorTransform transform) {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -150,6 +150,8 @@ class Style {
|
||||||
protected int _layoutHeight = SIZE_UNSPECIFIED;
|
protected int _layoutHeight = SIZE_UNSPECIFIED;
|
||||||
protected int _layoutWeight = WEIGHT_UNSPECIFIED;
|
protected int _layoutWeight = WEIGHT_UNSPECIFIED;
|
||||||
|
|
||||||
|
protected uint[] _focusRectColors;
|
||||||
|
|
||||||
protected Style[] _substates;
|
protected Style[] _substates;
|
||||||
protected Style[] _children;
|
protected Style[] _children;
|
||||||
|
|
||||||
|
@ -550,6 +552,19 @@ class Style {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns colors to draw focus rectangle (one for solid, two for vertical gradient) or null if no focus rect should be drawn for style
|
||||||
|
@property const(uint[]) focusRectColors() const {
|
||||||
|
if (_focusRectColors)
|
||||||
|
return cast(const)_focusRectColors;
|
||||||
|
return parentStyle.focusRectColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// sets colors to draw focus rectangle or null if no focus rect should be drawn for style
|
||||||
|
@property Style focusRectColors(uint[] colors) {
|
||||||
|
_focusRectColors = colors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
Style setPadding(int left, int top, int right, int bottom) {
|
Style setPadding(int left, int top, int right, int bottom) {
|
||||||
_padding.left = left;
|
_padding.left = left;
|
||||||
_padding.top = top;
|
_padding.top = top;
|
||||||
|
@ -634,7 +649,7 @@ class Theme : Style {
|
||||||
this(string id) {
|
this(string id) {
|
||||||
super(this, id);
|
super(this, id);
|
||||||
_parentStyle = null;
|
_parentStyle = null;
|
||||||
_backgroundColor = 0xFFFFFFFF; // transparent
|
_backgroundColor = COLOR_TRANSPARENT; // transparent
|
||||||
_textColor = 0x000000; // black
|
_textColor = 0x000000; // black
|
||||||
_align = Align.TopLeft;
|
_align = Align.TopLeft;
|
||||||
_fontSize = 14; // TODO: from settings or screen properties / DPI
|
_fontSize = 14; // TODO: from settings or screen properties / DPI
|
||||||
|
@ -711,7 +726,14 @@ class Theme : Style {
|
||||||
override uint customColor(string id) {
|
override uint customColor(string id) {
|
||||||
if (id in _customColors)
|
if (id in _customColors)
|
||||||
return _customColors[id];
|
return _customColors[id];
|
||||||
return 0xFFFFFFFF;
|
return COLOR_TRANSPARENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns colors to draw focus rectangle or null if no focus rect should be drawn for style
|
||||||
|
@property override const(uint[]) focusRectColors() const {
|
||||||
|
if (_focusRectColors)
|
||||||
|
return _focusRectColors;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// create new named style or get existing
|
/// create new named style or get existing
|
||||||
|
@ -794,7 +816,7 @@ Theme createDefaultTheme() {
|
||||||
scrollbar.backgroundColor(0xC0808080);
|
scrollbar.backgroundColor(0xC0808080);
|
||||||
Style scrollbarButton = button.createSubstyle("SCROLLBAR_BUTTON");
|
Style scrollbarButton = button.createSubstyle("SCROLLBAR_BUTTON");
|
||||||
Style scrollbarSlider = res.createSubstyle("SLIDER");
|
Style scrollbarSlider = res.createSubstyle("SLIDER");
|
||||||
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF);
|
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(COLOR_TRANSPARENT);
|
||||||
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
||||||
scrollbarPage.createState(State.Hovered, State.Hovered).backgroundColor(0xF0404080);
|
scrollbarPage.createState(State.Hovered, State.Hovered).backgroundColor(0xF0404080);
|
||||||
|
|
||||||
|
@ -896,6 +918,29 @@ uint decodeHexDigit(char ch) {
|
||||||
|
|
||||||
/// supported formats: #RGB #ARGB #RRGGBB #AARRGGBB
|
/// supported formats: #RGB #ARGB #RRGGBB #AARRGGBB
|
||||||
uint decodeColor(string s, uint defValue) {
|
uint decodeColor(string s, uint defValue) {
|
||||||
|
s = strip(s);
|
||||||
|
switch (s) {
|
||||||
|
case "@null":
|
||||||
|
case "transparent":
|
||||||
|
return COLOR_TRANSPARENT;
|
||||||
|
case "black":
|
||||||
|
return 0x000000;
|
||||||
|
case "white":
|
||||||
|
return 0xFFFFFF;
|
||||||
|
case "red":
|
||||||
|
return 0xFF0000;
|
||||||
|
case "green":
|
||||||
|
return 0x00FF00;
|
||||||
|
case "blue":
|
||||||
|
return 0x0000FF;
|
||||||
|
case "gray":
|
||||||
|
return 0x808080;
|
||||||
|
case "lightgray":
|
||||||
|
case "silver":
|
||||||
|
return 0xC0C0C0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (s.length != 4 && s.length != 5 && s.length != 7 && s.length != 9)
|
if (s.length != 4 && s.length != 5 && s.length != 7 && s.length != 9)
|
||||||
return defValue;
|
return defValue;
|
||||||
if (s[0] != '#')
|
if (s[0] != '#')
|
||||||
|
@ -912,6 +957,23 @@ uint decodeColor(string s, uint defValue) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private import std.array : split;
|
||||||
|
|
||||||
|
/// Decode color list attribute, e.g.: "#84A, #99FFFF" -> [0x8844aa, 0x99ffff]
|
||||||
|
uint[] decodeFocusRectColors(string s) {
|
||||||
|
string[] colors = split(s, ",");
|
||||||
|
if (colors.length < 1)
|
||||||
|
return null;
|
||||||
|
uint[] res = new uint[colors.length];
|
||||||
|
for (int i = 0; i < colors.length; i++) {
|
||||||
|
uint cl = decodeColor(colors[i], COLOR_UNSPECIFIED);
|
||||||
|
if (cl == COLOR_UNSPECIFIED)
|
||||||
|
return null;
|
||||||
|
res[i] = cl;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/// parses string like "Left|VCenter" to bit set of Align flags
|
/// parses string like "Left|VCenter" to bit set of Align flags
|
||||||
ubyte decodeAlignment(string s) {
|
ubyte decodeAlignment(string s) {
|
||||||
ubyte res = 0;
|
ubyte res = 0;
|
||||||
|
@ -1037,6 +1099,8 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
||||||
style.alpha = decodeDimension(elem.tag.attr["alpha"]);
|
style.alpha = decodeDimension(elem.tag.attr["alpha"]);
|
||||||
if ("textFlags" in elem.tag.attr)
|
if ("textFlags" in elem.tag.attr)
|
||||||
style.textFlags = decodeTextFlags(elem.tag.attr["textFlags"]);
|
style.textFlags = decodeTextFlags(elem.tag.attr["textFlags"]);
|
||||||
|
if ("focusRectColors" in elem.tag.attr)
|
||||||
|
style.focusRectColors = decodeFocusRectColors(elem.tag.attr["focusRectColors"]);
|
||||||
foreach(item; elem.elements) {
|
foreach(item; elem.elements) {
|
||||||
if (allowStates && item.tag.name.equal("state")) {
|
if (allowStates && item.tag.name.equal("state")) {
|
||||||
uint stateMask = 0;
|
uint stateMask = 0;
|
||||||
|
@ -1056,7 +1120,7 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
||||||
// <color id="buttons_panel_color" value="#303080"/>
|
// <color id="buttons_panel_color" value="#303080"/>
|
||||||
string colorid = attrValue(item, "id");
|
string colorid = attrValue(item, "id");
|
||||||
string colorvalue = attrValue(item, "value");
|
string colorvalue = attrValue(item, "value");
|
||||||
uint color = decodeColor(colorvalue, 0xFFFFFFFF);
|
uint color = decodeColor(colorvalue, COLOR_TRANSPARENT);
|
||||||
if (colorid)
|
if (colorid)
|
||||||
style.setCustomColor(colorid, color);
|
style.setCustomColor(colorid, color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,6 +316,7 @@ class Widget {
|
||||||
requestLayout();
|
requestLayout();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
immutable static int FOCUS_RECT_PADDING = 2;
|
||||||
/// get padding (between background bounds and content of widget)
|
/// get padding (between background bounds and content of widget)
|
||||||
@property Rect padding() const {
|
@property Rect padding() const {
|
||||||
// get max padding from style padding and background drawable padding
|
// get max padding from style padding and background drawable padding
|
||||||
|
@ -332,6 +333,10 @@ class Widget {
|
||||||
if (p.bottom < dp.bottom)
|
if (p.bottom < dp.bottom)
|
||||||
p.bottom = dp.bottom;
|
p.bottom = dp.bottom;
|
||||||
}
|
}
|
||||||
|
if (focusable && focusRectColors) {
|
||||||
|
// add two pixels to padding when focus rect is required - one pixel for focus rect, one for additional space
|
||||||
|
p.offset(FOCUS_RECT_PADDING, FOCUS_RECT_PADDING);
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
/// set padding for widget - override one from style
|
/// set padding for widget - override one from style
|
||||||
|
@ -360,6 +365,11 @@ class Widget {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns colors to draw focus rectangle (one for solid, two for vertical gradient) or null if no focus rect should be drawn for style
|
||||||
|
@property const(uint[]) focusRectColors() const {
|
||||||
|
return style.focusRectColors;
|
||||||
|
}
|
||||||
|
|
||||||
/// background drawable
|
/// background drawable
|
||||||
@property DrawableRef backgroundDrawable() const {
|
@property DrawableRef backgroundDrawable() const {
|
||||||
return stateStyle.backgroundDrawable;
|
return stateStyle.backgroundDrawable;
|
||||||
|
@ -1108,6 +1118,14 @@ class Widget {
|
||||||
_needLayout = false;
|
_needLayout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// draws focus rectangle, if enabled in styles
|
||||||
|
void drawFocusRect(DrawBuf buf, Rect rc) {
|
||||||
|
const uint[] colors = focusRectColors;
|
||||||
|
if (colors) {
|
||||||
|
buf.drawFocusRect(rc, colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw widget at its position to buffer
|
/// Draw widget at its position to buffer
|
||||||
void onDraw(DrawBuf buf) {
|
void onDraw(DrawBuf buf) {
|
||||||
if (visibility != Visibility.Visible)
|
if (visibility != Visibility.Visible)
|
||||||
|
@ -1120,6 +1138,10 @@ class Widget {
|
||||||
bg.drawTo(buf, rc, state);
|
bg.drawTo(buf, rc, state);
|
||||||
}
|
}
|
||||||
applyPadding(rc);
|
applyPadding(rc);
|
||||||
|
if ((state & State.Focused) && focusable) {
|
||||||
|
rc.expand(FOCUS_RECT_PADDING, FOCUS_RECT_PADDING);
|
||||||
|
drawFocusRect(buf, rc);
|
||||||
|
}
|
||||||
_needDraw = false;
|
_needDraw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue