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="src">
|
||||||
<Folder name="dlangui">
|
<Folder name="dlangui">
|
||||||
<Folder name="core">
|
<Folder name="core">
|
||||||
|
<File path="src\dlangui\core\collections.d" />
|
||||||
<File path="src\dlangui\core\events.d" />
|
<File path="src\dlangui\core\events.d" />
|
||||||
<File path="src\dlangui\core\i18n.d" />
|
<File path="src\dlangui\core\i18n.d" />
|
||||||
<File path="src\dlangui\core\linestream.d" />
|
<File path="src\dlangui\core\linestream.d" />
|
||||||
<File path="src\dlangui\core\logger.d" />
|
<File path="src\dlangui\core\logger.d" />
|
||||||
|
<File path="src\dlangui\core\signals.d" />
|
||||||
<File path="src\dlangui\core\types.d" />
|
<File path="src\dlangui\core\types.d" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder name="graphics">
|
<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