changeset 83:3cfc83a99cbc

Add List.opIndexAssign and switch to one callback for change notification. Also, update controls to work with the new API.
author Jordan Miner <jminer7@gmail.com>
date Sun, 18 Jul 2010 22:20:50 -0500
parents e52546f41851
children 7653269724db
files dynamin/core/list.d dynamin/gui/container.d dynamin/gui/list_box.d dynamin/gui/notebook.d
diffstat 4 files changed, 92 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- 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);
 }
 
--- 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;
--- 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;
--- 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() {