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() {
|
||||
//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 height();
|
||||
@property Rect padding() { return Rect(0,0,0,0); }
|
||||
}
|
||||
|
||||
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 height() { return 0; }
|
||||
|
@ -705,7 +705,7 @@ class SolidFillDrawable : Drawable {
|
|||
this(uint 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
|
||||
buf.fillRect(rc, _color);
|
||||
}
|
||||
|
@ -755,7 +755,7 @@ class ImageDrawable : Drawable {
|
|||
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)
|
||||
return;
|
||||
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;
|
||||
|
|
|
@ -341,15 +341,15 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
|||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Move && trackHover) {
|
||||
if (!(state & State.Hover)) {
|
||||
if (!(state & State.Hovered)) {
|
||||
Log.d("Hover ", id);
|
||||
setState(State.Hover);
|
||||
setState(State.Hovered);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((event.action == MouseAction.Leave || event.action == MouseAction.Cancel) && trackHover) {
|
||||
Log.d("Leave ", id);
|
||||
resetState(State.Hover);
|
||||
resetState(State.Hovered);
|
||||
return true;
|
||||
}
|
||||
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 WEIGHT_UNSPECIFIED = -1;
|
||||
|
||||
/// widget state flags - bits
|
||||
enum State : uint {
|
||||
/// state not specified / normal
|
||||
Normal = 0,
|
||||
Pressed = 1,
|
||||
Focused = 2,
|
||||
Disabled = 4,
|
||||
Hover = 8, // mouse pointer is over control, buttons not pressed
|
||||
Enabled = 4,
|
||||
Hovered = 8, // mouse pointer is over control, buttons not pressed
|
||||
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 {
|
||||
|
@ -621,11 +627,11 @@ Theme createDefaultTheme() {
|
|||
res.fontSize(14);
|
||||
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));
|
||||
button.createState(State.Disabled | State.Focused, State.Disabled | 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 | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
|
||||
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.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_DOWN, "scrollbar_btn_down");
|
||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_LEFT, "scrollbar_btn_left");
|
||||
|
@ -639,7 +645,7 @@ Theme createDefaultTheme() {
|
|||
Style scrollbarSlider = res.createSubstyle("SLIDER");
|
||||
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF);
|
||||
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");
|
||||
tabUp.backgroundImageId("tab_up_background");
|
||||
|
@ -650,13 +656,13 @@ Theme createDefaultTheme() {
|
|||
tabUpButtonText.createState(State.Selected, State.Selected).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.Hover, State.Hover).textColor(0xFFE0E0);
|
||||
tabUpButtonText.createState(State.Hovered, State.Hovered).textColor(0xFFE0E0);
|
||||
Style tabUpButton = res.createSubstyle("TAB_UP_BUTTON");
|
||||
tabUpButton.backgroundImageId("tab_btn_up_normal");
|
||||
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.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");
|
||||
tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
||||
tabHost.backgroundColor(0xF0F0F0);
|
||||
|
|
|
@ -317,7 +317,7 @@ class Widget {
|
|||
}
|
||||
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
||||
resetState(State.Pressed);
|
||||
resetState(State.Hover);
|
||||
resetState(State.Hovered);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusIn) {
|
||||
|
@ -325,15 +325,15 @@ class Widget {
|
|||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Move && trackHover) {
|
||||
if (!(state & State.Hover)) {
|
||||
if (!(state & State.Hovered)) {
|
||||
Log.d("Hover ", id);
|
||||
setState(State.Hover);
|
||||
setState(State.Hovered);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Leave && trackHover) {
|
||||
Log.d("Leave ", id);
|
||||
resetState(State.Hover);
|
||||
resetState(State.Hovered);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue