XCB version working - except libPNG version issue

This commit is contained in:
Vadim Lopatin 2014-03-14 17:39:56 +04:00
parent bf57f2f26f
commit a3d195fb8b
1 changed files with 424 additions and 419 deletions

View File

@ -1,419 +1,424 @@
module dlangui.widgets.widget; module dlangui.widgets.widget;
public import dlangui.core.types; public import dlangui.core.types;
public import dlangui.widgets.styles; public import dlangui.widgets.styles;
public import dlangui.graphics.drawbuf; public import dlangui.graphics.drawbuf;
public import dlangui.graphics.images; public import dlangui.graphics.images;
public import dlangui.graphics.fonts; public import dlangui.graphics.fonts;
import dlangui.platforms.common.platform; import dlangui.platforms.common.platform;
import std.algorithm; import std.algorithm;
/// Visibility (see Android View Visibility) /// Visibility (see Android View Visibility)
enum Visibility : ubyte { enum Visibility : ubyte {
/// Visible on screen (default) /// Visible on screen (default)
Visible, Visible,
/// Not visible, but occupies a space in layout /// Not visible, but occupies a space in layout
Invisible, Invisible,
/// Completely hidden, as not has been added /// Completely hidden, as not has been added
Gone Gone
} }
class Widget { class Widget {
/// widget id /// widget id
protected string _id; protected string _id;
/// current widget position, set by layout() /// current widget position, set by layout()
protected Rect _pos; protected Rect _pos;
/// widget visibility: either Visible, Invisible, Gone /// widget visibility: either Visible, Invisible, Gone
protected Visibility _visibility = Visibility.Visible; // visible by default protected Visibility _visibility = Visibility.Visible; // visible by default
/// style id to lookup style in theme /// style id to lookup style in theme
protected string _styleId; protected string _styleId;
/// own copy of style - to override some of style properties, null of no properties overriden /// own copy of style - to override some of style properties, null of no properties overriden
protected Style _ownStyle; protected Style _ownStyle;
/// width measured by measure() /// width measured by measure()
protected int _measuredWidth; protected int _measuredWidth;
/// height measured by measure() /// height measured by measure()
protected int _measuredHeight; protected int _measuredHeight;
/// true to force layout /// true to force layout
protected bool _needLayout = true; protected bool _needLayout = true;
/// true to force redraw /// true to force redraw
protected bool _needDraw = true; protected bool _needDraw = true;
/// parent widget /// parent widget
protected Widget _parent; protected Widget _parent;
/// window (to be used for top level widgets only!) /// window (to be used for top level widgets only!)
protected Window _window; protected Window _window;
this(string ID = null) { this(string ID = null) {
_id = id; _id = id;
} }
/// 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() const { protected @property const (Style) style() const {
if (_ownStyle !is null) if (_ownStyle !is null)
return _ownStyle; return _ownStyle;
return currentTheme.get(_styleId); return currentTheme.get(_styleId);
} }
/// enforces widget's own style - allows override some of style properties /// enforces widget's own style - allows override some of style properties
protected @property Style ownStyle() { protected @property Style ownStyle() {
if (_ownStyle is null) if (_ownStyle is null)
_ownStyle = currentTheme.modifyStyle(_styleId); _ownStyle = currentTheme.modifyStyle(_styleId);
return _ownStyle; return _ownStyle;
} }
/// returns widget id, null if not set /// returns widget id, null if not set
@property string id() const { return _styleId; } @property string id() const { return _styleId; }
/// set widget id /// set widget id
@property void id(string id) { _id = id; } @property void id(string id) { _id = id; }
/// compare widget id with specified value, returs true if matches /// compare widget id with specified value, returs true if matches
bool compareId(string id) { return (_id !is null) && id.equal(_id); } bool compareId(string id) { return (_id !is null) && id.equal(_id); }
//====================================================== //======================================================
// Style related properties // Style related properties
/// returns widget style id, null if not set /// returns widget style id, null if not set
@property string styleId() const { return _styleId; } @property string styleId() const { return _styleId; }
/// set widget style id /// set widget style id
@property void styleId(string id) { _styleId = id; } @property void styleId(string id) { _styleId = id; }
/// get margins (between widget bounds and its background) /// get margins (between widget bounds and its background)
@property Rect margins() const { return style.margins; } @property Rect margins() const { return style.margins; }
/// set margins for widget - override one from style /// set margins for widget - override one from style
@property Widget margins(Rect rc) { ownStyle.margins = rc; return this; } @property Widget margins(Rect rc) { ownStyle.margins = rc; return this; }
/// 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
Rect p = style.padding; Rect p = style.padding;
Rect dp = style.backgroundDrawable.padding; DrawableRef d = style.backgroundDrawable;
if (p.left < dp.left) if (!d.isNull) {
p.left = dp.left; Rect dp = style.backgroundDrawable.padding;
if (p.right < dp.right) if (p.left < dp.left)
p.right = dp.right; p.left = dp.left;
if (p.top < dp.top) if (p.right < dp.right)
p.top = dp.top; p.right = dp.right;
if (p.bottom < dp.bottom) if (p.top < dp.top)
p.bottom = dp.bottom; p.top = dp.top;
return p; if (p.bottom < dp.bottom)
} p.bottom = dp.bottom;
/// set padding for widget - override one from style }
@property Widget padding(Rect rc) { ownStyle.padding = rc; return this; } return p;
/// returns background color }
@property uint backgroundColor() const { return style.backgroundColor; } /// set padding for widget - override one from style
/// set background color for widget - override one from style @property Widget padding(Rect rc) { ownStyle.padding = rc; return this; }
@property Widget backgroundColor(uint color) { ownStyle.backgroundColor = color; return this; } /// returns background color
/// get text color (ARGB 32 bit value) @property uint backgroundColor() const { return style.backgroundColor; }
@property uint textColor() const { return style.textColor; } /// set background color for widget - override one from style
/// set text color (ARGB 32 bit value) @property Widget backgroundColor(uint color) { ownStyle.backgroundColor = color; return this; }
@property Widget textColor(uint value) { ownStyle.textColor = value; return this; } /// get text color (ARGB 32 bit value)
/// returns font face @property uint textColor() const { return style.textColor; }
@property string fontFace() const { return style.fontFace; } /// set text color (ARGB 32 bit value)
/// set font face for widget - override one from style @property Widget textColor(uint value) { ownStyle.textColor = value; return this; }
@property Widget fontFace(string face) { ownStyle.fontFace = face; return this; } /// returns font face
/// returns font style (italic/normal) @property string fontFace() const { return style.fontFace; }
@property bool fontItalic() const { return style.fontItalic; } /// set font face for widget - override one from style
/// set font style (italic/normal) for widget - override one from style @property Widget fontFace(string face) { ownStyle.fontFace = face; return this; }
@property Widget fontItalic(bool italic) { ownStyle.fontStyle = italic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL; return this; } /// returns font style (italic/normal)
/// returns font weight @property bool fontItalic() const { return style.fontItalic; }
@property ushort fontWeight() const { return style.fontWeight; } /// set font style (italic/normal) for widget - override one from style
/// set font weight for widget - override one from style @property Widget fontItalic(bool italic) { ownStyle.fontStyle = italic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL; return this; }
@property Widget fontWeight(ushort weight) { ownStyle.fontWeight = weight; return this; } /// returns font weight
/// returns font size in pixels @property ushort fontWeight() const { return style.fontWeight; }
@property ushort fontSize() const { return style.fontSize; } /// set font weight for widget - override one from style
/// set font size for widget - override one from style @property Widget fontWeight(ushort weight) { ownStyle.fontWeight = weight; return this; }
@property Widget fontSize(ushort size) { ownStyle.fontSize = size; return this; } /// returns font size in pixels
/// returns font family @property ushort fontSize() const { return style.fontSize; }
@property FontFamily fontFamily() const { return style.fontFamily; } /// set font size for widget - override one from style
/// set font family for widget - override one from style @property Widget fontSize(ushort size) { ownStyle.fontSize = size; return this; }
@property Widget fontFamily(FontFamily family) { ownStyle.fontFamily = family; return this; } /// returns font family
/// returns alignment (combined vertical and horizontal) @property FontFamily fontFamily() const { return style.fontFamily; }
@property ubyte alignment() const { return style.alignment; } /// set font family for widget - override one from style
/// sets alignment (combined vertical and horizontal) @property Widget fontFamily(FontFamily family) { ownStyle.fontFamily = family; return this; }
@property Widget alignment(ubyte value) { ownStyle.alignment = value; return this; } /// returns alignment (combined vertical and horizontal)
/// returns horizontal alignment @property ubyte alignment() const { return style.alignment; }
@property Align valign() { return cast(Align)(alignment & Align.VCenter); } /// sets alignment (combined vertical and horizontal)
/// returns vertical alignment @property Widget alignment(ubyte value) { ownStyle.alignment = value; return this; }
@property Align halign() { return cast(Align)(alignment & Align.HCenter); } /// returns horizontal alignment
/// returns font set for widget using style or set manually @property Align valign() { return cast(Align)(alignment & Align.VCenter); }
@property FontRef font() const { return style.font; } /// returns vertical alignment
@property Align halign() { return cast(Align)(alignment & Align.HCenter); }
/// returns widget content text (override to support this) /// returns font set for widget using style or set manually
@property dstring text() { return ""; } @property FontRef font() const { return style.font; }
/// sets widget content text (override to support this)
@property Widget text(dstring s) { return this; } /// returns widget content text (override to support this)
@property dstring text() { return ""; }
//================================================================== /// sets widget content text (override to support this)
// Layout and drawing related methods @property Widget text(dstring s) { return this; }
/// returns true if layout is required for widget and its children //==================================================================
@property bool needLayout() { return _needLayout; } // Layout and drawing related methods
/// returns true if redraw is required for widget and its children
@property bool needDraw() { return _needDraw; } /// returns true if layout is required for widget and its children
/// returns measured width (calculated during measure() call) @property bool needLayout() { return _needLayout; }
@property measuredWidth() { return _measuredWidth; } /// returns true if redraw is required for widget and its children
/// returns measured height (calculated during measure() call) @property bool needDraw() { return _needDraw; }
@property measuredHeight() { return _measuredHeight; } /// returns measured width (calculated during measure() call)
/// returns current width of widget in pixels @property measuredWidth() { return _measuredWidth; }
@property int width() { return _pos.width; } /// returns measured height (calculated during measure() call)
/// returns current height of widget in pixels @property measuredHeight() { return _measuredHeight; }
@property int height() { return _pos.height; } /// returns current width of widget in pixels
/// returns min width constraint @property int width() { return _pos.width; }
@property int minWidth() { return style.minWidth; } /// returns current height of widget in pixels
/// returns max width constraint (SIZE_UNSPECIFIED if no constraint set) @property int height() { return _pos.height; }
@property int maxWidth() { return style.maxWidth; } /// returns min width constraint
/// returns min height constraint @property int minWidth() { return style.minWidth; }
@property int minHeight() { return style.minHeight; } /// returns max width constraint (SIZE_UNSPECIFIED if no constraint set)
/// returns max height constraint (SIZE_UNSPECIFIED if no constraint set) @property int maxWidth() { return style.maxWidth; }
@property int maxHeight() { return style.maxHeight; } /// returns min height constraint
@property int minHeight() { return style.minHeight; }
/// set max width constraint (SIZE_UNSPECIFIED for no constraint) /// returns max height constraint (SIZE_UNSPECIFIED if no constraint set)
@property Widget maxWidth(int value) { ownStyle.maxWidth = value; return this; } @property int maxHeight() { return style.maxHeight; }
/// set max width constraint (0 for no constraint)
@property Widget minWidth(int value) { ownStyle.minWidth = value; return this; } /// set max width constraint (SIZE_UNSPECIFIED for no constraint)
/// set max height constraint (SIZE_UNSPECIFIED for no constraint) @property Widget maxWidth(int value) { ownStyle.maxWidth = value; return this; }
@property Widget maxHeight(int value) { ownStyle.maxHeight = value; return this; } /// set max width constraint (0 for no constraint)
/// set max height constraint (0 for no constraint) @property Widget minWidth(int value) { ownStyle.minWidth = value; return this; }
@property Widget minHeight(int value) { ownStyle.minHeight = value; return this; } /// set max height constraint (SIZE_UNSPECIFIED for no constraint)
@property Widget maxHeight(int value) { ownStyle.maxHeight = value; return this; }
/// returns layout width options (WRAP_CONTENT, FILL_PARENT, or some constant value) /// set max height constraint (0 for no constraint)
@property int layoutWidth() { return style.layoutWidth; } @property Widget minHeight(int value) { ownStyle.minHeight = value; return this; }
/// returns layout height options (WRAP_CONTENT, FILL_PARENT, or some constant value)
@property int layoutHeight() { return style.layoutHeight; } /// returns layout width options (WRAP_CONTENT, FILL_PARENT, or some constant value)
/// returns layout weight (while resizing to fill parent, widget will be resized proportionally to this value) @property int layoutWidth() { return style.layoutWidth; }
@property int layoutWeight() { return style.layoutWeight; } /// returns layout height options (WRAP_CONTENT, FILL_PARENT, or some constant value)
@property int layoutHeight() { return style.layoutHeight; }
/// sets layout width options (WRAP_CONTENT, FILL_PARENT, or some constant value) /// returns layout weight (while resizing to fill parent, widget will be resized proportionally to this value)
@property Widget layoutWidth(int value) { ownStyle.layoutWidth = value; return this; } @property int layoutWeight() { return style.layoutWeight; }
/// sets layout height options (WRAP_CONTENT, FILL_PARENT, or some constant value)
@property Widget layoutHeight(int value) { ownStyle.layoutHeight = value; return this; } /// sets layout width options (WRAP_CONTENT, FILL_PARENT, or some constant value)
/// sets layout weight (while resizing to fill parent, widget will be resized proportionally to this value) @property Widget layoutWidth(int value) { ownStyle.layoutWidth = value; return this; }
@property Widget layoutWeight(int value) { ownStyle.layoutWeight = value; return this; } /// sets layout height options (WRAP_CONTENT, FILL_PARENT, or some constant value)
@property Widget layoutHeight(int value) { ownStyle.layoutHeight = value; return this; }
/// returns widget visibility (Visible, Invisible, Gone) /// sets layout weight (while resizing to fill parent, widget will be resized proportionally to this value)
@property Visibility visibility() { return _visibility; } @property Widget layoutWeight(int value) { ownStyle.layoutWeight = value; return this; }
/// sets widget visibility (Visible, Invisible, Gone)
@property Widget visibility(Visibility visible) { /// returns widget visibility (Visible, Invisible, Gone)
_visibility = visible; @property Visibility visibility() { return _visibility; }
requestLayout(); /// sets widget visibility (Visible, Invisible, Gone)
return this; @property Widget visibility(Visibility visible) {
} _visibility = visible;
requestLayout();
/// request relayout of widget and its children return this;
void requestLayout() { }
_needLayout = true;
} /// request relayout of widget and its children
/// request redraw void requestLayout() {
void invalidate() { _needLayout = true;
_needDraw = true; }
} /// request redraw
void invalidate() {
/// helper function for implement measure() when widget's content dimensions are known _needDraw = true;
protected void measuredContent(int parentWidth, int parentHeight, int contentWidth, int contentHeight) { }
if (visibility == Visibility.Gone) {
_measuredWidth = _measuredHeight = 0; /// helper function for implement measure() when widget's content dimensions are known
return; protected void measuredContent(int parentWidth, int parentHeight, int contentWidth, int contentHeight) {
} if (visibility == Visibility.Gone) {
Rect m = margins; _measuredWidth = _measuredHeight = 0;
Rect p = padding; return;
// summarize margins, padding, and content size }
int dx = m.left + m.right + p.left + p.right + contentWidth; Rect m = margins;
int dy = m.top + m.bottom + p.top + p.bottom + contentHeight; Rect p = padding;
// apply min/max width and height constraints // summarize margins, padding, and content size
int minw = minWidth; int dx = m.left + m.right + p.left + p.right + contentWidth;
int maxw = maxWidth; int dy = m.top + m.bottom + p.top + p.bottom + contentHeight;
int minh = minHeight; // apply min/max width and height constraints
int maxh = maxHeight; int minw = minWidth;
if (dx < minw) int maxw = maxWidth;
dx = minw; int minh = minHeight;
if (dy < minh) int maxh = maxHeight;
dy = minh; if (dx < minw)
if (maxw != SIZE_UNSPECIFIED && dx > maxw) dx = minw;
dx = maxw; if (dy < minh)
if (maxh != SIZE_UNSPECIFIED && dy > maxh) dy = minh;
dy = maxh; if (maxw != SIZE_UNSPECIFIED && dx > maxw)
// apply max parent size constraint dx = maxw;
if (parentWidth != SIZE_UNSPECIFIED && dx > parentWidth) if (maxh != SIZE_UNSPECIFIED && dy > maxh)
dx = parentWidth; dy = maxh;
if (parentHeight != SIZE_UNSPECIFIED && dy > parentHeight) // apply max parent size constraint
dy = parentHeight; if (parentWidth != SIZE_UNSPECIFIED && dx > parentWidth)
_measuredWidth = dx; dx = parentWidth;
_measuredHeight = dy; if (parentHeight != SIZE_UNSPECIFIED && dy > parentHeight)
} dy = parentHeight;
_measuredWidth = dx;
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). _measuredHeight = dy;
void measure(int parentWidth, int parentHeight) { }
measuredContent(parentWidth, parentHeight, 0, 0);
} /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
void measure(int parentWidth, int parentHeight) {
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). measuredContent(parentWidth, parentHeight, 0, 0);
void layout(Rect rc) { }
if (visibility == Visibility.Gone) {
return; /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
} void layout(Rect rc) {
_pos = rc; if (visibility == Visibility.Gone) {
_needLayout = false; return;
} }
/// Draw widget at its position to buffer _pos = rc;
void onDraw(DrawBuf buf) { _needLayout = false;
if (visibility != Visibility.Visible) }
return; /// Draw widget at its position to buffer
Rect rc = _pos; void onDraw(DrawBuf buf) {
applyMargins(rc); if (visibility != Visibility.Visible)
DrawableRef bg = style.backgroundDrawable; return;
bg.drawTo(buf, rc); Rect rc = _pos;
applyPadding(rc); applyMargins(rc);
_needDraw = false; DrawableRef bg = style.backgroundDrawable;
} if (!bg.isNull) {
bg.drawTo(buf, rc);
/// Helper function: applies margins to rectangle }
void applyMargins(ref Rect rc) { applyPadding(rc);
Rect m = margins; _needDraw = false;
rc.left += m.left; }
rc.top += m.top;
rc.bottom -= m.bottom; /// Helper function: applies margins to rectangle
rc.right -= m.right; void applyMargins(ref Rect rc) {
} Rect m = margins;
/// Helper function: applies padding to rectangle rc.left += m.left;
void applyPadding(ref Rect rc) { rc.top += m.top;
Rect m = padding; rc.bottom -= m.bottom;
rc.left += m.left; rc.right -= m.right;
rc.top += m.top; }
rc.bottom -= m.bottom; /// Helper function: applies padding to rectangle
rc.right -= m.right; void applyPadding(ref Rect rc) {
} Rect m = padding;
/// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc. rc.left += m.left;
void applyAlign(ref Rect rc, Point sz) { rc.top += m.top;
Align va = valign; rc.bottom -= m.bottom;
Align ha = halign; rc.right -= m.right;
if (va == Align.Bottom) { }
rc.top = rc.bottom - sz.y; /// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc.
} else if (va == Align.VCenter) { void applyAlign(ref Rect rc, Point sz) {
int dy = (rc.height - sz.y) / 2; Align va = valign;
rc.top += dy; Align ha = halign;
rc.bottom = rc.top + sz.y; if (va == Align.Bottom) {
} else { rc.top = rc.bottom - sz.y;
rc.bottom = rc.top + sz.y; } else if (va == Align.VCenter) {
} int dy = (rc.height - sz.y) / 2;
if (ha == Align.Right) { rc.top += dy;
rc.left = rc.right - sz.x; rc.bottom = rc.top + sz.y;
} else if (ha == Align.HCenter) { } else {
int dx = (rc.width - sz.x) / 2; rc.bottom = rc.top + sz.y;
rc.left += dx; }
rc.right = rc.left + sz.x; if (ha == Align.Right) {
} else { rc.left = rc.right - sz.x;
rc.right = rc.left + sz.x; } else if (ha == Align.HCenter) {
} int dx = (rc.width - sz.x) / 2;
} rc.left += dx;
rc.right = rc.left + sz.x;
// =========================================================== } else {
// Widget hierarhy methods rc.right = rc.left + sz.x;
}
/// returns number of children of this widget }
@property int childCount() { return 0; }
/// returns child by index // ===========================================================
Widget child(int index) { return null; } // Widget hierarhy methods
/// adds child, returns added item
Widget addChild(Widget item) { assert(false, "children not suported for this widget type"); } /// returns number of children of this widget
/// removes child, returns added item @property int childCount() { return 0; }
Widget removeChild(int index) { assert(false, "children not suported for this widget type"); } /// returns child by index
/// returns index of widget in child list, -1 if passed widget is not a child of this widget Widget child(int index) { return null; }
int childIndex(Widget item) { return -1; } /// adds child, returns added item
Widget addChild(Widget item) { assert(false, "children not suported for this widget type"); }
/// find child by id, returns null if not found /// removes child, returns added item
Widget childById(string id) { Widget removeChild(int index) { assert(false, "children not suported for this widget type"); }
if (compareId(id)) /// returns index of widget in child list, -1 if passed widget is not a child of this widget
return this; int childIndex(Widget item) { return -1; }
// lookup children
for (int i = childCount - 1; i >= 0; i--) { /// find child by id, returns null if not found
Widget res = child(i).childById(id); Widget childById(string id) {
if (res !is null) if (compareId(id))
return res; return this;
} // lookup children
// not found for (int i = childCount - 1; i >= 0; i--) {
return null; Widget res = child(i).childById(id);
} if (res !is null)
/// returns parent widget, null for top level widget return res;
@property Widget parent() { return _parent; } }
/// sets parent for widget // not found
@property void parent(Widget parent) { _parent = parent; } return null;
/// returns window (if widget or its parent is attached to window) }
@property Window window() { /// returns parent widget, null for top level widget
Widget p = this; @property Widget parent() { return _parent; }
while (p !is null) { /// sets parent for widget
if (p._window !is null) @property void parent(Widget parent) { _parent = parent; }
return p._window; /// returns window (if widget or its parent is attached to window)
p = p.parent; @property Window window() {
} Widget p = this;
return null; while (p !is null) {
} if (p._window !is null)
/// sets window (to be used for top level widget from Window implementation). TODO: hide it from API? return p._window;
@property void window(Window window) { _window = window; } p = p.parent;
}
} return null;
}
/// widget list holder /// sets window (to be used for top level widget from Window implementation). TODO: hide it from API?
struct WidgetList { @property void window(Window window) { _window = window; }
protected Widget[] _list;
protected int _count; }
/// returns count of items
@property int count() { return _count; } /// widget list holder
/// get item by index struct WidgetList {
Widget get(int index) { protected Widget[] _list;
assert(index >= 0 && index < _count, "child index out of range"); protected int _count;
return _list[index]; /// returns count of items
} @property int count() { return _count; }
/// add item to list /// get item by index
Widget add(Widget item) { Widget get(int index) {
if (_list.length <= _count) // resize assert(index >= 0 && index < _count, "child index out of range");
_list.length = _list.length < 4 ? 4 : _list.length * 2; return _list[index];
_list[_count++] = item; }
return item; /// add item to list
} Widget add(Widget item) {
/// find child index for item, return -1 if not found if (_list.length <= _count) // resize
int indexOf(Widget item) { _list.length = _list.length < 4 ? 4 : _list.length * 2;
for (int i = 0; i < _count; i++) _list[_count++] = item;
if (_list[i] == item) return item;
return i; }
return -1; /// find child index for item, return -1 if not found
} int indexOf(Widget item) {
/// remove item from list, return removed item for (int i = 0; i < _count; i++)
Widget remove(int index) { if (_list[i] == item)
assert(index >= 0 && index < _count, "child index out of range"); return i;
Widget item = _list[index]; return -1;
for (int i = index; i < _count - 1; i++) }
_list[i] = _list[i + 1]; /// remove item from list, return removed item
_count--; Widget remove(int index) {
return item; assert(index >= 0 && index < _count, "child index out of range");
} Widget item = _list[index];
/// remove and destroy all items for (int i = index; i < _count - 1; i++)
void clear() { _list[i] = _list[i + 1];
for (int i = 0; i < _count; i++) { _count--;
destroy(_list[i]); return item;
_list[i] = null; }
} /// remove and destroy all items
_count = 0; void clear() {
} for (int i = 0; i < _count; i++) {
~this() { destroy(_list[i]);
clear(); _list[i] = null;
} }
} _count = 0;
}
/// base class for widgets which have children ~this() {
class WidgetGroup : Widget { clear();
}
this(string ID = null) { }
super(ID);
} /// base class for widgets which have children
class WidgetGroup : Widget {
protected WidgetList _children;
this(string ID = null) {
/// returns number of children of this widget super(ID);
@property override int childCount() { return _children.count; } }
/// returns child by index
override Widget child(int index) { return _children.get(index); } protected WidgetList _children;
/// adds child, returns added item
override Widget addChild(Widget item) { return _children.add(item); } /// returns number of children of this widget
/// removes child, returns added item @property override int childCount() { return _children.count; }
override Widget removeChild(int index) { return _children.remove(index); } /// returns child by index
/// returns index of widget in child list, -1 if passed widget is not a child of this widget override Widget child(int index) { return _children.get(index); }
override int childIndex(Widget item) { return _children.indexOf(item); } /// adds child, returns added item
} override Widget addChild(Widget item) { return _children.add(item); }
/// removes child, returns added item
override Widget removeChild(int index) { return _children.remove(index); }
/// returns index of widget in child list, -1 if passed widget is not a child of this widget
override int childIndex(Widget item) { return _children.indexOf(item); }
}