# HG changeset patch # User Jordan Miner # Date 1279509650 18000 # Node ID 3cfc83a99cbc2f6c4b62a9fc81ccf4728ac77b13 # Parent e52546f41851947acd890669e1fe2a8e82d40028 Add List.opIndexAssign and switch to one callback for change notification. Also, update controls to work with the new API. diff -r e52546f41851 -r 3cfc83a99cbc dynamin/core/list.d --- a/dynamin/core/list.d Sat Jul 17 16:54:09 2010 -0500 +++ b/dynamin/core/list.d Sun Jul 18 22:20:50 2010 -0500 @@ -37,29 +37,34 @@ // TODO: QuickSort() // TODO: HeapSort() // TODO: Sort() - calls HeapSort() so stable sort is default -class List(T, bool hasDelegates = false) { + +/// Represents the ways items can be changed in a list. +enum ListChangeType { + /// An item was added to the list. + Added, + /// An item was removed from the list. + Removed, + /// An item was replaced with another item. + Replaced +} + +class List(T, bool changeNotification = false) { protected: T[] _data; uint _count; - static if(hasDelegates) { - void delegate(T, int) whenAdded; - void delegate(T, int) whenRemoved; - } + static if(changeNotification) + void delegate(ListChangeType, T, T, uint) whenChanged; const int DefaultCapacity = 16; public: - static if(hasDelegates) { - /// whenAdded or whenRemoved is called right after an item is added - /// or removed - this(void delegate(T, int) whenAdded, - void delegate(T, int) whenRemoved) { - this(DefaultCapacity, whenAdded, whenRemoved); + static if(changeNotification) { + /// whenChanged is called right after an item is added, removed, or replaced + this(void delegate(ListChangeType, T, T, uint) whenChanged) { + this(DefaultCapacity, whenChanged); } this(uint capacity, - void delegate(T, int) whenAdded, - void delegate(T, int) whenRemoved) { + void delegate(ListChangeType, T, T, uint) whenChanged) { _data = new T[capacity]; - this.whenAdded = whenAdded; - this.whenRemoved = whenRemoved; + this.whenChanged = whenChanged; } } else { this() { @@ -106,6 +111,12 @@ T opIndex(uint index) { return _data[0.._count][index]; } + void opIndexAssign(T item, uint index) { + T oldItem = _data[0.._count][index]; + _data[0.._count][index] = item; + static if(changeNotification) + whenChanged(ListChangeType.Replaced, oldItem, item, index); + } void push(T item) { add(item); } @@ -117,8 +128,8 @@ static if(is(T == class) || is(T == interface)) _data[_count-1] = cast(T)null; --_count; - static if(hasDelegates) - whenRemoved(item, _count); + static if(changeNotification) + whenChanged(ListChangeType.Removed, item, T.init, _count); return item; } void add(T item) { @@ -140,21 +151,21 @@ _data[_count-1] = cast(T)null; --_count; - static if(hasDelegates) - whenRemoved(item, index); + static if(changeNotification) + whenChanged(ListChangeType.Removed, item, T.init, index); } void insert(T item, uint index) { maybeEnlarge(_count+1); arrayCopy!(T)(_data, index, _data, index+1, _count - index); _data[index] = item; ++_count; - static if(hasDelegates) - whenAdded(item, index); + static if(changeNotification) + whenChanged(ListChangeType.Added, T.init, item, index); } void clear() { for(; _count > 0; --_count) { - static if(hasDelegates) - whenRemoved(_data[_count-1], _count-1); + static if(changeNotification) + whenChanged(ListChangeType.Removed, _data[_count-1], T.init, _count-1); // must null out to allow to be collected static if(is(T == class) || is(T == interface)) data[_count-1] = cast(T)null; @@ -210,20 +221,40 @@ list.clear(); assert(list.data == ""); - int a = 0, r = 0; - void added(string, int) { a++; }; - void removed(string, int) { r++; }; - auto list2 = new List!(string, true)(&added, &removed); - assert(a == 0 && r == 0); + int a = 0, r = 0, r2 = 0; + void changed(ListChangeType t, string o, string n, uint) { + if(t == ListChangeType.Added) { + a++; + assert(o == "" && n != ""); + } + if(t == ListChangeType.Removed) { + r++; + assert(n == "" && o != ""); + } + if(t == ListChangeType.Replaced) { + r2++; + } + }; + auto list2 = new List!(string, true)(&changed); + assert(a == 0 && r == 0 && r2 == 0); list2.add("hello"); - assert(a == 1 && r == 0); + assert(a == 1 && r == 0 && r2 == 0); assert(list2.pop() == "hello"); - assert(a == 1 && r == 1); + assert(a == 1 && r == 1 && r2 == 0); list2.add("Hi"); - list2.add("Jacob!"); - assert(a == 3 && r == 1); + list2.add("Jacob"); + assert(a == 3 && r == 1 && r2 == 0); + list2[1] = "Matt"; + assert(a == 3 && r == 1 && r2 == 1); + list2.insert("John", 1); + list2.insert("Pete", 3); + assert(list2.data == ["Hi", "John", "Matt", "Pete"]); + assert(a == 5 && r == 1 && r2 == 1); + list2.removeAt(0); + assert(list2.data == ["John", "Matt", "Pete"]); + assert(a == 5 && r == 2 && r2 == 1); list2.clear(); - assert(a == 3 && r == 3); + assert(a == 5 && r == 5 && r2 == 1); } diff -r e52546f41851 -r 3cfc83a99cbc dynamin/gui/container.d --- a/dynamin/gui/container.d Sat Jul 17 16:54:09 2010 -0500 +++ b/dynamin/gui/container.d Sun Jul 18 22:20:50 2010 -0500 @@ -88,31 +88,33 @@ } // not an event - void whenChildAdded(Control child, int) { - if(child.parent) - child.parent.remove(child); - child.parent = this; - repaint(); + void whenChildrenChanged(ListChangeType, Control oldChild, Control newChild, uint) { + if(oldChild) { + oldChild.parent = null; + repaint(); - void callAdded(Control ctrl) { - scope e = new HierarchyEventArgs(ctrl); - descendantAdded(e); + scope e = new HierarchyEventArgs(oldChild); + descendantRemoved(e); + } - if(auto cntr = cast(Container)ctrl) { - foreach(c; cntr._children) - callAdded(c); - } - } - callAdded(child); - } + if(newChild) { + if(newChild.parent) + newChild.parent.remove(newChild); + newChild.parent = this; + repaint(); - // not an event - void whenChildRemoved(Control child, int) { - child.parent = null; - repaint(); + void callAdded(Control ctrl) { + scope e = new HierarchyEventArgs(ctrl); + descendantAdded(e); - scope e = new HierarchyEventArgs(child); - descendantRemoved(e); + if(auto cntr = cast(Container)ctrl) { + foreach(c; cntr._children) + callAdded(c); + } + } + callAdded(newChild); + } + } void dispatchDescendantAdded(HierarchyEventArgs e) { @@ -169,7 +171,7 @@ descendantRemoved.setUp(&whenDescendantRemoved, &dispatchDescendantRemoved); - _children = new ControlList(&whenChildAdded, &whenChildRemoved); + _children = new ControlList(&whenChildrenChanged); elasticX = true; elasticY = true; diff -r e52546f41851 -r 3cfc83a99cbc dynamin/gui/list_box.d --- a/dynamin/gui/list_box.d Sat Jul 17 16:54:09 2010 -0500 +++ b/dynamin/gui/list_box.d Sun Jul 18 22:20:50 2010 -0500 @@ -83,7 +83,7 @@ /// This event occurs after the selection has changed. Event!(whenSelectionChanged) selectionChanged; - void whenListItemsChanged(string, int) { + void whenListItemsChanged(ListChangeType, string, string, uint) { super.layout(); repaint(); } @@ -91,7 +91,7 @@ /// this() { selectionChanged.setUp(&whenSelectionChanged); - _items = new List!(string, true)(&whenListItemsChanged, &whenListItemsChanged); + _items = new List!(string, true)(&whenListItemsChanged); super(); _focusable = true; diff -r e52546f41851 -r 3cfc83a99cbc dynamin/gui/notebook.d --- a/dynamin/gui/notebook.d Sat Jul 17 16:54:09 2010 -0500 +++ b/dynamin/gui/notebook.d Sun Jul 18 22:20:50 2010 -0500 @@ -91,7 +91,7 @@ } Theme.current.Tab_paint(selectedTabPage, this, e.graphics); } - void whenTabPagesChanged(TabPage page, int) { + void whenTabPagesChanged(ListChangeType, TabPage oldPage, TabPage newPage, uint) { if(_tabPages.count == 0) selectedIndex = -1; else if(selectedIndex == -1) @@ -116,7 +116,7 @@ this() { selectionChanged.setUp(&whenSelectionChanged); - _tabPages = new List!(TabPage, true)(&whenTabPagesChanged, &whenTabPagesChanged); + _tabPages = new List!(TabPage, true)(&whenTabPagesChanged); _focusable = true; } override void layout() {