mirror of https://github.com/buggins/dlangui.git
state drawables
This commit is contained in:
parent
7c47c542cc
commit
f3c0197837
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:constantSize="true"
|
||||||
|
android:dither="false"
|
||||||
|
android:variablePadding="false"
|
||||||
|
<item
|
||||||
|
android:drawable="tab_btn_up_hover"
|
||||||
|
android:state_hovered="true" />
|
||||||
|
<item
|
||||||
|
android:drawable="tab_btn_up_selected"
|
||||||
|
android:state_selected="true" />
|
||||||
|
<item
|
||||||
|
android:drawable="tab_btn_up_normal" />
|
||||||
|
</selector>
|
|
@ -687,14 +687,14 @@ class Drawable : RefCountedObject {
|
||||||
~this() {
|
~this() {
|
||||||
//Log.d("Destroyed drawable, count=", --_instanceCount);
|
//Log.d("Destroyed drawable, count=", --_instanceCount);
|
||||||
}
|
}
|
||||||
abstract void drawTo(DrawBuf buf, Rect rc, int tilex0 = 0, int tiley0 = 0);
|
abstract void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0);
|
||||||
@property abstract int width();
|
@property abstract int width();
|
||||||
@property abstract int height();
|
@property abstract int height();
|
||||||
@property Rect padding() { return Rect(0,0,0,0); }
|
@property Rect padding() { return Rect(0,0,0,0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptyDrawable : Drawable {
|
class EmptyDrawable : Drawable {
|
||||||
override void drawTo(DrawBuf buf, Rect rc, int tilex0 = 0, int tiley0 = 0) {
|
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
|
||||||
}
|
}
|
||||||
@property override int width() { return 0; }
|
@property override int width() { return 0; }
|
||||||
@property override int height() { return 0; }
|
@property override int height() { return 0; }
|
||||||
|
@ -705,7 +705,7 @@ class SolidFillDrawable : Drawable {
|
||||||
this(uint color) {
|
this(uint color) {
|
||||||
_color = color;
|
_color = color;
|
||||||
}
|
}
|
||||||
override void drawTo(DrawBuf buf, Rect rc, 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 >> 24) != 0xFF) // not fully transparent
|
||||||
buf.fillRect(rc, _color);
|
buf.fillRect(rc, _color);
|
||||||
}
|
}
|
||||||
|
@ -755,7 +755,7 @@ class ImageDrawable : Drawable {
|
||||||
n3 = n4 = n3 + middledist;
|
n3 = n4 = n3 + middledist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override void drawTo(DrawBuf buf, Rect rc, int tilex0 = 0, int tiley0 = 0) {
|
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
|
||||||
if (_image.isNull)
|
if (_image.isNull)
|
||||||
return;
|
return;
|
||||||
if (_image.hasNinePatch) {
|
if (_image.hasNinePatch) {
|
||||||
|
@ -833,4 +833,138 @@ class ImageDrawable : Drawable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import std.xml;
|
||||||
|
import std.algorithm;
|
||||||
|
import dlangui.widgets.styles;
|
||||||
|
|
||||||
|
void extractStateFlag(ref string[string] attr, string attrName, State state, ref uint stateMask, ref uint stateValue) {
|
||||||
|
if (attrName in attr) {
|
||||||
|
string value = attr[attrName];
|
||||||
|
if (value.equal("true"))
|
||||||
|
stateValue |= state;
|
||||||
|
stateMask |= state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// converts XML attribute name to State (see http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList)
|
||||||
|
void extractStateFlags(ref string[string] attr, ref uint stateMask, ref uint stateValue) {
|
||||||
|
extractStateFlag(attr, "state_pressed", State.Pressed, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_focused", State.Focused, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_hovered", State.Hovered, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_selected", State.Selected, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_checkable", State.Checkable, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_checked", State.Checked, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_enabled", State.Enabled, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_activated", State.Activated, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_window_focused", State.WindowFocused, stateMask, stateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
sample:
|
||||||
|
(prefix android: is optional)
|
||||||
|
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:constantSize=["true" | "false"]
|
||||||
|
android:dither=["true" | "false"]
|
||||||
|
android:variablePadding=["true" | "false"] >
|
||||||
|
<item
|
||||||
|
android:drawable="@[package:]drawable/drawable_resource"
|
||||||
|
android:state_pressed=["true" | "false"]
|
||||||
|
android:state_focused=["true" | "false"]
|
||||||
|
android:state_hovered=["true" | "false"]
|
||||||
|
android:state_selected=["true" | "false"]
|
||||||
|
android:state_checkable=["true" | "false"]
|
||||||
|
android:state_checked=["true" | "false"]
|
||||||
|
android:state_enabled=["true" | "false"]
|
||||||
|
android:state_activated=["true" | "false"]
|
||||||
|
android:state_window_focused=["true" | "false"] />
|
||||||
|
</selector>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Drawable which is drawn depending on state (see http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList)
|
||||||
|
class StateDrawable : Drawable {
|
||||||
|
|
||||||
|
static struct StateItem {
|
||||||
|
uint stateMask;
|
||||||
|
uint stateValue;
|
||||||
|
DrawableRef drawable;
|
||||||
|
@property bool matchState(uint state) {
|
||||||
|
return (stateMask & state) == stateValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected StateItem[] _stateList;
|
||||||
|
|
||||||
|
void addState(uint stateMask, uint stateValue, string resourceId) {
|
||||||
|
StateItem item;
|
||||||
|
item.stateMask = stateMask;
|
||||||
|
item.stateValue = stateValue;
|
||||||
|
item.drawable = dlangui.graphics.images.drawableCache.get(resourceId);
|
||||||
|
_stateList ~= item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addState(uint stateMask, uint stateValue, DrawableRef drawable) {
|
||||||
|
StateItem item;
|
||||||
|
item.stateMask = stateMask;
|
||||||
|
item.stateValue = stateValue;
|
||||||
|
item.drawable = drawable;
|
||||||
|
_stateList ~= item;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(Element element) {
|
||||||
|
foreach(item; element.elements) {
|
||||||
|
if (item.tag.name.equal("item")) {
|
||||||
|
if ("drawable" in item.tag.attr) {
|
||||||
|
string drawableId = item.tag.attr["drawable"];
|
||||||
|
uint stateMask, stateValue;
|
||||||
|
extractStateFlags(item.tag.attr, stateMask, stateValue);
|
||||||
|
if (drawableId !is null) {
|
||||||
|
addState(stateMask, stateValue, drawableId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _stateList.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// load from XML file
|
||||||
|
bool load(string filename) {
|
||||||
|
import std.file;
|
||||||
|
import std.string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
string s = cast(string)std.file.read(filename);
|
||||||
|
|
||||||
|
// Check for well-formedness
|
||||||
|
check(s);
|
||||||
|
|
||||||
|
// Make a DOM tree
|
||||||
|
auto doc = new Document(s);
|
||||||
|
|
||||||
|
return load(doc);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Cannot read drawable resource from file ", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
|
||||||
|
foreach(ref item; _stateList)
|
||||||
|
if (item.matchState(state)) {
|
||||||
|
item.drawable.drawTo(buf, rc, state, tilex0, tiley0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property override int width() {
|
||||||
|
return (_stateList.length > 0) ? _stateList[0].drawable.width : 0;
|
||||||
|
}
|
||||||
|
@property override int height() {
|
||||||
|
return (_stateList.length > 0) ? _stateList[0].drawable.height : 0;
|
||||||
|
}
|
||||||
|
@property override Rect padding() {
|
||||||
|
return (_stateList.length > 0) ? _stateList[0].drawable.padding : Rect(0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
alias DrawableRef = Ref!Drawable;
|
alias DrawableRef = Ref!Drawable;
|
||||||
|
|
|
@ -341,15 +341,15 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (event.action == MouseAction.Move && trackHover) {
|
if (event.action == MouseAction.Move && trackHover) {
|
||||||
if (!(state & State.Hover)) {
|
if (!(state & State.Hovered)) {
|
||||||
Log.d("Hover ", id);
|
Log.d("Hover ", id);
|
||||||
setState(State.Hover);
|
setState(State.Hovered);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((event.action == MouseAction.Leave || event.action == MouseAction.Cancel) && trackHover) {
|
if ((event.action == MouseAction.Leave || event.action == MouseAction.Cancel) && trackHover) {
|
||||||
Log.d("Leave ", id);
|
Log.d("Leave ", id);
|
||||||
resetState(State.Hover);
|
resetState(State.Hovered);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (event.action == MouseAction.Cancel) {
|
if (event.action == MouseAction.Cancel) {
|
||||||
|
|
|
@ -20,14 +20,20 @@ immutable int FILL_PARENT = int.max - 1;
|
||||||
immutable int WRAP_CONTENT = int.max - 2;
|
immutable int WRAP_CONTENT = int.max - 2;
|
||||||
immutable int WEIGHT_UNSPECIFIED = -1;
|
immutable int WEIGHT_UNSPECIFIED = -1;
|
||||||
|
|
||||||
|
/// widget state flags - bits
|
||||||
enum State : uint {
|
enum State : uint {
|
||||||
|
/// state not specified / normal
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
Pressed = 1,
|
Pressed = 1,
|
||||||
Focused = 2,
|
Focused = 2,
|
||||||
Disabled = 4,
|
Enabled = 4,
|
||||||
Hover = 8, // mouse pointer is over control, buttons not pressed
|
Hovered = 8, // mouse pointer is over control, buttons not pressed
|
||||||
Selected = 16,
|
Selected = 16,
|
||||||
Parent = 128, // use parent's state
|
Checkable = 32,
|
||||||
|
Checked = 64,
|
||||||
|
Activated = 128,
|
||||||
|
WindowFocused = 256,
|
||||||
|
Parent = 0x10000, // use parent's state
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Align : ubyte {
|
enum Align : ubyte {
|
||||||
|
@ -621,11 +627,11 @@ Theme createDefaultTheme() {
|
||||||
res.fontSize(14);
|
res.fontSize(14);
|
||||||
Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small_normal").alignment(Align.Center);
|
Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small_normal").alignment(Align.Center);
|
||||||
Style text = res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1));
|
Style text = res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1));
|
||||||
button.createState(State.Disabled | State.Focused, State.Disabled | State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
|
button.createState(State.Enabled | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
|
||||||
button.createState(State.Disabled, State.Disabled).backgroundImageId("btn_default_small_normal_disable");
|
button.createState(State.Enabled, 0).backgroundImageId("btn_default_small_normal_disable");
|
||||||
button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
|
button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
|
||||||
button.createState(State.Focused, State.Focused).backgroundImageId("btn_default_small_selected");
|
button.createState(State.Focused, State.Focused).backgroundImageId("btn_default_small_selected");
|
||||||
button.createState(State.Hover, State.Hover).backgroundImageId("btn_default_small_normal_hover");
|
button.createState(State.Hovered, State.Hovered).backgroundImageId("btn_default_small_normal_hover");
|
||||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_UP, "scrollbar_btn_up");
|
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_UP, "scrollbar_btn_up");
|
||||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_DOWN, "scrollbar_btn_down");
|
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_DOWN, "scrollbar_btn_down");
|
||||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_LEFT, "scrollbar_btn_left");
|
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_LEFT, "scrollbar_btn_left");
|
||||||
|
@ -639,7 +645,7 @@ Theme createDefaultTheme() {
|
||||||
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(0xFFFFFFFF);
|
||||||
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
||||||
scrollbarPage.createState(State.Hover, State.Hover).backgroundColor(0xF0404080);
|
scrollbarPage.createState(State.Hovered, State.Hovered).backgroundColor(0xF0404080);
|
||||||
|
|
||||||
Style tabUp = res.createSubstyle("TAB_UP");
|
Style tabUp = res.createSubstyle("TAB_UP");
|
||||||
tabUp.backgroundImageId("tab_up_background");
|
tabUp.backgroundImageId("tab_up_background");
|
||||||
|
@ -650,13 +656,13 @@ Theme createDefaultTheme() {
|
||||||
tabUpButtonText.createState(State.Selected, State.Selected).textColor(0x000000);
|
tabUpButtonText.createState(State.Selected, State.Selected).textColor(0x000000);
|
||||||
tabUpButtonText.createState(State.Selected|State.Focused, State.Selected|State.Focused).textColor(0x000000);
|
tabUpButtonText.createState(State.Selected|State.Focused, State.Selected|State.Focused).textColor(0x000000);
|
||||||
tabUpButtonText.createState(State.Focused, State.Focused).textColor(0x000000);
|
tabUpButtonText.createState(State.Focused, State.Focused).textColor(0x000000);
|
||||||
tabUpButtonText.createState(State.Hover, State.Hover).textColor(0xFFE0E0);
|
tabUpButtonText.createState(State.Hovered, State.Hovered).textColor(0xFFE0E0);
|
||||||
Style tabUpButton = res.createSubstyle("TAB_UP_BUTTON");
|
Style tabUpButton = res.createSubstyle("TAB_UP_BUTTON");
|
||||||
tabUpButton.backgroundImageId("tab_btn_up_normal");
|
tabUpButton.backgroundImageId("tab_btn_up_normal");
|
||||||
tabUpButton.createState(State.Selected, State.Selected).backgroundImageId("tab_btn_up_selected");
|
tabUpButton.createState(State.Selected, State.Selected).backgroundImageId("tab_btn_up_selected");
|
||||||
tabUpButton.createState(State.Selected|State.Focused, State.Selected|State.Focused).backgroundImageId("tab_btn_up_focused_selected");
|
tabUpButton.createState(State.Selected|State.Focused, State.Selected|State.Focused).backgroundImageId("tab_btn_up_focused_selected");
|
||||||
tabUpButton.createState(State.Focused, State.Focused).backgroundImageId("tab_btn_up_focused");
|
tabUpButton.createState(State.Focused, State.Focused).backgroundImageId("tab_btn_up_focused");
|
||||||
tabUpButton.createState(State.Hover, State.Hover).backgroundImageId("tab_btn_up_hover");
|
tabUpButton.createState(State.Hovered, State.Hovered).backgroundImageId("tab_btn_up_hover");
|
||||||
Style tabHost = res.createSubstyle("TAB_HOST");
|
Style tabHost = res.createSubstyle("TAB_HOST");
|
||||||
tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
||||||
tabHost.backgroundColor(0xF0F0F0);
|
tabHost.backgroundColor(0xF0F0F0);
|
||||||
|
|
|
@ -317,7 +317,7 @@ class Widget {
|
||||||
}
|
}
|
||||||
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
||||||
resetState(State.Pressed);
|
resetState(State.Pressed);
|
||||||
resetState(State.Hover);
|
resetState(State.Hovered);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (event.action == MouseAction.FocusIn) {
|
if (event.action == MouseAction.FocusIn) {
|
||||||
|
@ -325,15 +325,15 @@ class Widget {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (event.action == MouseAction.Move && trackHover) {
|
if (event.action == MouseAction.Move && trackHover) {
|
||||||
if (!(state & State.Hover)) {
|
if (!(state & State.Hovered)) {
|
||||||
Log.d("Hover ", id);
|
Log.d("Hover ", id);
|
||||||
setState(State.Hover);
|
setState(State.Hovered);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (event.action == MouseAction.Leave && trackHover) {
|
if (event.action == MouseAction.Leave && trackHover) {
|
||||||
Log.d("Leave ", id);
|
Log.d("Leave ", id);
|
||||||
resetState(State.Hover);
|
resetState(State.Hovered);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue