fix lists

This commit is contained in:
Vadim Lopatin 2014-04-16 15:28:19 +04:00
parent 716027aab4
commit dd687b4433
5 changed files with 72 additions and 27 deletions

View File

@ -139,6 +139,11 @@ extern (C) int UIAppMain(string[] args) {
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
listAdapter.widgets.add((new TextWidget()).text("List item "d ~ to!dstring(i)).styleId("LIST_ITEM")); listAdapter.widgets.add((new TextWidget()).text("List item "d ~ to!dstring(i)).styleId("LIST_ITEM"));
list.ownAdapter = listAdapter; list.ownAdapter = listAdapter;
listAdapter.resetItemState(5, State.Enabled);
listAdapter.resetItemState(7, State.Enabled);
listAdapter.resetItemState(12, State.Enabled);
assert(list.itemEnabled(5) == false);
assert(list.itemEnabled(6) == true);
list.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); list.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
tabs.addTab(list, "Long List"d); tabs.addTab(list, "Long List"d);
} }

View File

@ -230,7 +230,7 @@ wstring fromWStringz(const(wchar[]) s) {
/// widget state flags - bits /// widget state flags - bits
enum State : uint { enum State : uint {
/// state not specified / normal /// state not specified / normal
Normal = 0, Normal = 4, // Normal is Enabled
Pressed = 1, Pressed = 1,
Focused = 2, Focused = 2,
Enabled = 4, Enabled = 4,

View File

@ -92,6 +92,8 @@ class ListWidget : WidgetGroup, OnScrollHandler {
/// returns rectangle for item (not scrolled, first item starts at 0,0) /// returns rectangle for item (not scrolled, first item starts at 0,0)
Rect itemRectNoScroll(int index) { Rect itemRectNoScroll(int index) {
if (index < 0 || index >= _itemRects.length)
return Rect.init;
Rect res; Rect res;
res = _itemRects[index]; res = _itemRects[index];
return res; return res;
@ -99,6 +101,8 @@ class ListWidget : WidgetGroup, OnScrollHandler {
/// returns rectangle for item (scrolled) /// returns rectangle for item (scrolled)
Rect itemRect(int index) { Rect itemRect(int index) {
if (index < 0 || index >= _itemRects.length)
return Rect.init;
Rect res = itemRectNoScroll(index); Rect res = itemRectNoScroll(index);
if (_orientation == Orientation.Horizontal) { if (_orientation == Orientation.Horizontal) {
res.left -= _scrollPosition; res.left -= _scrollPosition;
@ -154,6 +158,13 @@ class ListWidget : WidgetGroup, OnScrollHandler {
return null; return null;
} }
/// returns true if item with corresponding index is enabled
bool itemEnabled(int index) {
if (_adapter !is null && index >= 0 && index < itemCount)
return (_adapter.itemState(index) & State.Enabled) != 0;
return false;
}
void onAdapterChanged() { void onAdapterChanged() {
requestLayout(); requestLayout();
} }
@ -243,32 +254,44 @@ class ListWidget : WidgetGroup, OnScrollHandler {
} }
/// move selection /// move selection
void moveSelection(int direction, bool wrapAround = true) { bool moveSelection(int direction, bool wrapAround = true) {
if (itemCount <= 0) if (itemCount <= 0)
return; return false;
if (_selectedItemIndex < 0) { int maxAttempts = itemCount - 1;
int index = _selectedItemIndex;
for (int i = 0; i < maxAttempts; i++) {
int newIndex = 0;
if (index < 0) {
// no previous selection // no previous selection
if (direction > 0) if (direction > 0)
selectItem(wrapAround ? 0 : itemCount - 1); newIndex = wrapAround ? 0 : itemCount - 1;
else else
selectItem(wrapAround ? itemCount - 1 : 0); newIndex = wrapAround ? itemCount - 1 : 0;
return; } else {
// step
newIndex = index + direction;
} }
int newIndex = _selectedItemIndex + direction;
if (newIndex < 0) if (newIndex < 0)
newIndex = wrapAround ? itemCount - 1 : 0; newIndex = wrapAround ? itemCount - 1 : 0;
else if (newIndex >= itemCount) else if (newIndex >= itemCount)
newIndex = wrapAround ? 0 : itemCount - 1; newIndex = wrapAround ? 0 : itemCount - 1;
if (newIndex != _selectedItemIndex) if (newIndex != index) {
selectItem(newIndex); if (selectItem(newIndex))
return true;
index = newIndex;
}
}
return true;
} }
protected void selectItem(int index) { protected bool selectItem(int index) {
if (_selectedItemIndex == index) { if (_selectedItemIndex == index) {
updateSelectedItemFocus(); updateSelectedItemFocus();
makeSelectionVisible(); makeSelectionVisible();
return; return true;
} }
if (index != -1 && !itemEnabled(index))
return false;
if (_selectedItemIndex != -1) { if (_selectedItemIndex != -1) {
_adapter.resetItemState(_selectedItemIndex, State.Selected | State.Focused); _adapter.resetItemState(_selectedItemIndex, State.Selected | State.Focused);
invalidate(); invalidate();
@ -279,6 +302,7 @@ class ListWidget : WidgetGroup, OnScrollHandler {
_adapter.setItemState(_selectedItemIndex, State.Selected | (state & State.Focused)); _adapter.setItemState(_selectedItemIndex, State.Selected | (state & State.Focused));
invalidate(); invalidate();
} }
return true;
} }
~this() { ~this() {
@ -567,6 +591,17 @@ class ListWidget : WidgetGroup, OnScrollHandler {
moveSelection(navigationDelta); moveSelection(navigationDelta);
return true; return true;
} }
if (event.action == KeyAction.KeyDown) {
if (event.keyCode == KeyCode.HOME) {
// select first item on HOME key
selectItem(0);
return true;
} else if (event.keyCode == KeyCode.END) {
// select last item on END key
selectItem(itemCount - 1);
return true;
}
}
return false; return false;
//if (_selectedItemIndex != -1 && event.action == KeyAction.KeyUp && (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN)) { //if (_selectedItemIndex != -1 && event.action == KeyAction.KeyUp && (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN)) {
// itemClicked(_selectedItemIndex); // itemClicked(_selectedItemIndex);
@ -624,19 +659,23 @@ class ListWidget : WidgetGroup, OnScrollHandler {
itemrc.bottom += rc.top - scrollOffset.y; itemrc.bottom += rc.top - scrollOffset.y;
if (itemrc.isPointInside(Point(event.x, event.y))) { if (itemrc.isPointInside(Point(event.x, event.y))) {
if ((event.flags & (MouseFlag.LButton || MouseFlag.RButton)) || _selectOnHover) { if ((event.flags & (MouseFlag.LButton || MouseFlag.RButton)) || _selectOnHover) {
if (_selectedItemIndex != i) { if (_selectedItemIndex != i && itemEnabled(i)) {
int prevSelection = _selectedItemIndex; int prevSelection = _selectedItemIndex;
selectItem(i); selectItem(i);
setHoverItem(-1); setHoverItem(-1);
selectionChanged(_selectedItemIndex, prevSelection); selectionChanged(_selectedItemIndex, prevSelection);
} }
} else } else {
if (itemEnabled(i))
setHoverItem(i); setHoverItem(i);
}
if ((event.button == MouseFlag.LButton || event.button == MouseFlag.RButton)) { if ((event.button == MouseFlag.LButton || event.button == MouseFlag.RButton)) {
if ((_clickOnButtonDown && event.action == MouseAction.ButtonDown) || (!_clickOnButtonDown && event.action == MouseAction.ButtonUp)) { if ((_clickOnButtonDown && event.action == MouseAction.ButtonDown) || (!_clickOnButtonDown && event.action == MouseAction.ButtonUp)) {
if (itemEnabled(i)) {
itemClicked(i); itemClicked(i);
if (_clickOnButtonDown) if (_clickOnButtonDown)
event.doNotTrackButtonDown = true; event.doNotTrackButtonDown = true;
}
} }
} }
return true; return true;

View File

@ -479,7 +479,7 @@ class Style {
/// find substyle based on widget state (e.g. focused, pressed, ...) /// find substyle based on widget state (e.g. focused, pressed, ...)
const(Style) forState(uint state) const { const(Style) forState(uint state) const {
if (state == 0) if (state == State.Normal)
return this; return this;
//Log.d("forState ", state, " styleId=", _id, " substates=", _substates.length); //Log.d("forState ", state, " styleId=", _id, " substates=", _substates.length);
if (parentStyle !is null && _substates.length == 0 && parentStyle._substates.length > 0) //id is null && if (parentStyle !is null && _substates.length == 0 && parentStyle._substates.length > 0) //id is null &&
@ -676,6 +676,7 @@ Theme createDefaultTheme() {
Style listItem = res.createSubstyle("LIST_ITEM"); Style listItem = res.createSubstyle("LIST_ITEM");
listItem.createState(State.Selected, State.Selected).backgroundColor(0xC04040FF).textColor(0x000000); listItem.createState(State.Selected, State.Selected).backgroundColor(0xC04040FF).textColor(0x000000);
listItem.createState(State.Enabled, 0).textColor(0x80000000); // half transparent text for disabled item
return res; return res;
} }

View File

@ -97,7 +97,7 @@ class Widget {
/// accessor to style - by lookup in theme by styleId (if style id is not set, theme base style will be used). /// accessor to style - by lookup in theme by styleId (if style id is not set, theme base style will be used).
protected @property const (Style) style(uint stateFlags) const { protected @property const (Style) style(uint stateFlags) const {
const (Style) normalStyle = style(); const (Style) normalStyle = style();
if (!stateFlags) // state is normal if (stateFlags == State.Normal) // state is normal
return normalStyle; return normalStyle;
const (Style) stateStyle = normalStyle.forState(stateFlags); const (Style) stateStyle = normalStyle.forState(stateFlags);
if (stateStyle !is normalStyle) if (stateStyle !is normalStyle)