mirror of https://github.com/buggins/dlangui.git
signals support
This commit is contained in:
parent
3f19e21478
commit
c18f9ee890
|
@ -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">
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue