signals support

This commit is contained in:
Vadim Lopatin 2014-04-16 12:26:33 +04:00
parent 3f19e21478
commit c18f9ee890
3 changed files with 290 additions and 0 deletions

View File

@ -299,10 +299,12 @@
<Folder name="src">
<Folder name="dlangui">
<Folder name="core">
<File path="src\dlangui\core\collections.d" />
<File path="src\dlangui\core\events.d" />
<File path="src\dlangui\core\i18n.d" />
<File path="src\dlangui\core\linestream.d" />
<File path="src\dlangui\core\logger.d" />
<File path="src\dlangui\core\signals.d" />
<File path="src\dlangui\core\types.d" />
</Folder>
<Folder name="graphics">

View File

@ -0,0 +1,121 @@
module dlangui.core.collections;
import std.algorithm;
/// array based collection of items
/// retains item order when during add/remove operations
struct Collection(T) {
private T[] _items;
private size_t _len;
/// returns number of items in collection
@property size_t length() { return _len; }
/// returns currently allocated capacity (may be more than length)
@property size_t size() { return _items.length; }
/// change capacity (e.g. to reserve big space to avoid multiple reallocations)
@property void size(size_t newSize) {
if (_len > newSize)
length = newSize; // shrink
_items.length = newSize;
}
/// returns number of items in collection
@property void length(size_t newSize) {
if (newSize < _len) {
// shrink
static if (is(T == class) || is(T == struct)) {
// clear items
for (size_t i = newSize; i < _len; i++)
_items[i] = T.init;
}
} else if (newSize > _len) {
// expand
if (_items.length < newSize)
_items.length = newSize;
}
_len = newSize;
}
/// access item by index
ref T opIndex(size_t index) {
assert(index < _len);
return _items[index];
}
/// insert new item in specified position
void add(T item, size_t index = size_t.max) {
if (index > _len)
index = _len;
if (_items.length >= _len) {
if (_items.length < 4)
_items.length = 4;
else
_items.length = _items.length * 2;
}
if (index < _len) {
for (size_t i = _len; i > index; i--)
_items[i] = _items[i - 1];
}
_items[index] = item;
_len++;
}
/// support for appending (~=, +=) and removing by value (-=)
ref Collection opOpAssign(string op)(T item) {
static if (op.equal("~") || op.equal("+")) {
// append item to end of collection
add(item);
return this;
} else if (op.equal("-")) {
// remove item from collection, if present
removeValue(item);
return this;
} else {
assert(false, "not supported opOpAssign " ~ op);
}
}
/// returns index of first occurence of item, size_t.max if not found
size_t indexOf(T item) {
for (size_t i = 0; i < _len; i++)
if (_items[i] == item)
return i;
return size_t.max;
}
/// remove single item, returning removed item
T remove(size_t index) {
assert(index < _len);
T result = _items[index];
for (size_t i = index; i + 1 < _len; i++)
_items[i] = _items[i + 1];
_items[_len] = T.init;
_len--;
return result;
}
/// remove single item by value - if present in collection, returning true if item was found and removed
bool removeValue(T value) {
size_t index = indexOf(value);
if (index == size_t.max)
return false;
remove(index);
return true;
}
/// support of foreach with reference
int opApply(int delegate(ref T param) op) {
int result = 0;
for (size_t i = 0; i < _len; i++) {
result = op(_items[i]);
if (result)
break;
}
return result;
}
/// remove all items
void clear() {
static if (is(T == class) || is(T == struct)) {
/// clear references
for(size_t i = 0; i < _len; i++)
_items[i] = T.init;
}
_len = 0;
_items = null;
}
~this() {
clear();
}
}

167
src/dlangui/core/signals.d Normal file
View File

@ -0,0 +1,167 @@
module dlangui.core.signals;
import std.traits;
import dlangui.core.collections;
/// parameter is interface with single method
struct Listener(T1) if (is(T1 == interface) && __traits(allMembers, T1).length == 1) {
alias return_t = ReturnType!(__traits(getMember, T1, __traits(allMembers, T1)[0]));
alias params_t = ParameterTypeTuple!(__traits(getMember, T1, __traits(allMembers, T1)[0]));
alias slot_t = return_t delegate(params_t);
private slot_t _listener;
/// returns true if listener is assigned
final bool assigned() {
return _listener !is null;
}
/// assign delegate
final void opAssign(slot_t listenerDelegate) {
_listener = listenerDelegate;
}
/// assign object implementing interface
final void opAssign(T1 listenerObject) {
_listener = &(__traits(getMember, listenerObject, __traits(allMembers, T1)[0]));
}
final return_t opCall(params_t params) {
static if (is(return_t == void)) {
if (_listener !is null)
_listener(params);
} else {
if (_listener !is null)
return _listener(params);
return return_t.init;
}
}
final slot_t get() {
return _listener;
}
alias get this;
}
/// implicitly specified return and parameter types
struct Listener(RETURN_T, T1...)
{
alias slot_t = RETURN_T delegate(T1);
private slot_t _listener;
/// returns true if listener is assigned
final bool assigned() {
return _listener !is null;
}
final void opAssign(slot_t listener) {
_listener = listener;
}
final RETURN_T opCall(T1 params) {
static if (is (RETURN_T == void)) {
if (_listener !is null)
_listener(params);
} else {
if (_listener !is null)
return _listener(params);
return RETURN_T.init;
}
}
final slot_t get() {
return _listener;
}
alias get this;
}
/// implicitly specified return and parameter types
struct Signal(T1) if (is(T1 == interface) && __traits(allMembers, T1).length == 1) {
alias return_t = ReturnType!(__traits(getMember, T1, __traits(allMembers, T1)[0]));
alias params_t = ParameterTypeTuple!(__traits(getMember, T1, __traits(allMembers, T1)[0]));
alias slot_t = return_t delegate(params_t);
private Collection!slot_t _listeners;
/// returns true if listener is assigned
final bool assigned() {
return _listeners.length > 0;
}
final void opAssign(slot_t listener) {
_listeners.clear();
_listeners ~= listener;
}
/// call all listeners; for signals having non-void return type, stop iterating when first return value is nonzero
static if (is (return_t == void)) {
// call all listeners
final return_t opCall(params_t params) {
foreach(listener; _listeners)
listener(params);
}
// call all listeners
final return_t emit(params_t params) {
foreach(listener; _listeners)
listener(params);
}
} else {
// call listeners, stop calling on first non-zero -- if (res) return res
final return_t opCall(params_t params) {
return emit(params);
}
// call listeners, stop calling on first non-zero -- if (res) return res
final return_t emit(params_t params) {
foreach(listener; _listeners) {
return_t res = listener(params);
if (res)
return res;
}
return return_t.init;
}
}
/// add listener
final void connect(slot_t listener) {
_listeners ~= listener;
}
/// remove listener
final void disconnect(slot_t listener) {
_listeners -= listener;
}
}
/// implicitly specified return and parameter types
struct Signal(RETURN_T, T1...)
{
alias slot_t = RETURN_T delegate(T1);
private Collection!slot_t _listeners;
/// returns true if listener is assigned
final bool assigned() {
return _listeners.length > 0;
}
final void opAssign(slot_t listener) {
_listeners.clear();
_listeners ~= listener;
}
/// call all listeners; for signals having non-void return type, stop iterating when first return value is nonzero
static if (is (RETURN_T == void)) {
// call all listeners
final RETURN_T opCall(T1 params) {
foreach(listener; _listeners)
listener(params);
}
// call all listeners
final RETURN_T emit(T1 params) {
foreach(listener; _listeners)
listener(params);
}
} else {
// call listeners, stop calling on first non-zero -- if (res) return res
final RETURN_T opCall(T1 params) {
return emit(params);
}
// call listeners, stop calling on first non-zero -- if (res) return res
final RETURN_T emit(T1 params) {
foreach(listener; _listeners) {
RETURN_T res = listener(params);
if (res)
return res;
}
return RETURN_T.init;
}
}
/// add listener
final void connect(slot_t listener) {
_listeners ~= listener;
}
/// remove listener
final void disconnect(slot_t listener) {
_listeners -= listener;
}
}