Initial size handling
This commit is contained in:
parent
9f9dcd5882
commit
0b73f8037b
28 changed files with 543 additions and 135 deletions
|
|
@ -17,7 +17,7 @@ Item buff[size];
|
||||||
int main() {
|
int main() {
|
||||||
AvlTree<AvlNumericKey<alni>, alni> tree;
|
AvlTree<AvlNumericKey<alni>, alni> tree;
|
||||||
|
|
||||||
for (auto i : Range(size)) {
|
for (auto i : IterRange(size)) {
|
||||||
buff[i].data = i;
|
buff[i].data = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ SUITE(Buffer) {
|
||||||
TEST(Simple1) {
|
TEST(Simple1) {
|
||||||
Buffer<TestClass, TestAllocator> buff;
|
Buffer<TestClass, TestAllocator> buff;
|
||||||
CHECK(buff.size() == 0);
|
CHECK(buff.size() == 0);
|
||||||
for (auto i : Range(size * 10)) {
|
for (auto i : IterRange(size * 10)) {
|
||||||
buff.append(TestClass(i));
|
buff.append(TestClass(i));
|
||||||
}
|
}
|
||||||
CHECK(buff.size() == size * 10);
|
CHECK(buff.size() == size * 10);
|
||||||
|
|
@ -21,7 +21,7 @@ SUITE(Buffer) {
|
||||||
TEST(Simple2) {
|
TEST(Simple2) {
|
||||||
Buffer<TestClass, TestAllocator> buff(size);
|
Buffer<TestClass, TestAllocator> buff(size);
|
||||||
CHECK(buff.size() == size);
|
CHECK(buff.size() == size);
|
||||||
for (auto i : Range(size * 10))
|
for (auto i : IterRange(size * 10))
|
||||||
buff.append(TestClass(i));
|
buff.append(TestClass(i));
|
||||||
CHECK(buff.size() == size + size * 10);
|
CHECK(buff.size() == size + size * 10);
|
||||||
while (buff.size())
|
while (buff.size())
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ SUITE(IntervalTree) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// initialize
|
// initialize
|
||||||
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
|
for (auto i : IterRange<ualni>(NUM_TEST_INTERVALS)) {
|
||||||
auto interval = Interval();
|
auto interval = Interval();
|
||||||
interval.random(SPAN);
|
interval.random(SPAN);
|
||||||
|
|
||||||
|
|
@ -114,7 +114,7 @@ SUITE(IntervalTree) {
|
||||||
test();
|
test();
|
||||||
|
|
||||||
// remove some
|
// remove some
|
||||||
for (auto i : Range<ualni>(NUM_TEST_INTERVALS / 2)) {
|
for (auto i : IterRange<ualni>(NUM_TEST_INTERVALS / 2)) {
|
||||||
auto idx = ualni(randomFloat() * (alnf) pool.size());
|
auto idx = ualni(randomFloat() * (alnf) pool.size());
|
||||||
pool[idx].ignore = true;
|
pool[idx].ignore = true;
|
||||||
intervalTree.remove({ pool[idx].start, pool[idx].end });
|
intervalTree.remove({ pool[idx].start, pool[idx].end });
|
||||||
|
|
@ -139,18 +139,18 @@ SUITE(IntervalTree) {
|
||||||
Buffer<Interval> testIntervals;
|
Buffer<Interval> testIntervals;
|
||||||
|
|
||||||
auto WOBBLE = SPAN * 0;
|
auto WOBBLE = SPAN * 0;
|
||||||
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
|
for (auto i : IterRange<ualni>(NUM_TEST_INTERVALS)) {
|
||||||
auto interval = Interval();
|
auto interval = Interval();
|
||||||
interval.randomSized(SPAN, SCALE, WOBBLE);
|
interval.randomSized(SPAN, SCALE, WOBBLE);
|
||||||
intervalTree.insert({ interval.start, interval.end }, i);
|
intervalTree.insert({ interval.start, interval.end }, i);
|
||||||
// WOBBLE -= 1.f;
|
// WOBBLE -= 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(0))
|
for (auto i : IterRange(0))
|
||||||
intervalTree.insert({ (halnf) i * 0.01f, SPAN }, 0);
|
intervalTree.insert({ (halnf) i * 0.01f, SPAN }, 0);
|
||||||
|
|
||||||
WOBBLE = 0;
|
WOBBLE = 0;
|
||||||
for (auto i : Range<ualni>(NUM_CHECKS)) {
|
for (auto i : IterRange<ualni>(NUM_CHECKS)) {
|
||||||
auto interval = Interval();
|
auto interval = Interval();
|
||||||
interval.randomSized(SPAN, SCALE, WOBBLE);
|
interval.randomSized(SPAN, SCALE, WOBBLE);
|
||||||
testIntervals.append(interval);
|
testIntervals.append(interval);
|
||||||
|
|
@ -200,7 +200,7 @@ SUITE(IntervalTree) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Buffer<Stat> stats;
|
Buffer<Stat> stats;
|
||||||
for (auto i : Range(2, 5)) {
|
for (auto i : IterRange(2, 5)) {
|
||||||
Stat stat = test(pow(10, i), 100);
|
Stat stat = test(pow(10, i), 100);
|
||||||
stats.append(stat);
|
stats.append(stat);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,26 +8,26 @@ SUITE(HashTable) {
|
||||||
TEST(SimpleReference) {
|
TEST(SimpleReference) {
|
||||||
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(1000, 100000)) {
|
for (auto i : IterRange(1000, 100000)) {
|
||||||
map.put(i, TestClass(i));
|
map.put(i, TestClass(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(1000, 100000)) {
|
for (auto i : IterRange(1000, 100000)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
|
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(1000, 100000)) {
|
for (auto i : IterRange(1000, 100000)) {
|
||||||
map.put(i, TestClass(i));
|
map.put(i, TestClass(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(1000, 2000)) {
|
for (auto i : IterRange(1000, 2000)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
map.remove(i);
|
map.remove(i);
|
||||||
CHECK(!map.presents(i));
|
CHECK(!map.presents(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(2000, 100000)) {
|
for (auto i : IterRange(2000, 100000)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
|
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
|
||||||
}
|
}
|
||||||
|
|
@ -42,29 +42,29 @@ SUITE(HashTable) {
|
||||||
TEST(SimplePointer) {
|
TEST(SimplePointer) {
|
||||||
tp::Map<tp::ualni, TestClass*, TestAllocator> map;
|
tp::Map<tp::ualni, TestClass*, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(1000)) {
|
for (auto i : IterRange(1000)) {
|
||||||
map.put(i, new TestClass(i));
|
map.put(i, new TestClass(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(1000)) {
|
for (auto i : IterRange(1000)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
|
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(1000)) {
|
for (auto i : IterRange(1000)) {
|
||||||
auto del = map.get(i);
|
auto del = map.get(i);
|
||||||
map.put(i, new TestClass(i));
|
map.put(i, new TestClass(i));
|
||||||
delete del;
|
delete del;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(900, 1000)) {
|
for (auto i : IterRange(900, 1000)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
delete map.get(i);
|
delete map.get(i);
|
||||||
map.remove(i);
|
map.remove(i);
|
||||||
CHECK(!map.presents(i));
|
CHECK(!map.presents(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : Range(900)) {
|
for (auto i : IterRange(900)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
|
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ SUITE(HashTable) {
|
||||||
TEST(Copy) {
|
TEST(Copy) {
|
||||||
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(10)) {
|
for (auto i : IterRange(10)) {
|
||||||
map.put(i, TestClass(i));
|
map.put(i, TestClass(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ SUITE(HashTable) {
|
||||||
TEST(SaveLoad) {
|
TEST(SaveLoad) {
|
||||||
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(10)) {
|
for (auto i : IterRange(10)) {
|
||||||
map.put(i, TestClass(i));
|
map.put(i, TestClass(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,7 +114,7 @@ SUITE(HashTable) {
|
||||||
|
|
||||||
CHECK(map.size() == 10);
|
CHECK(map.size() == 10);
|
||||||
|
|
||||||
for (auto i : Range(10)) {
|
for (auto i : IterRange(10)) {
|
||||||
CHECK(map.presents(i));
|
CHECK(map.presents(i));
|
||||||
CHECK_EQUAL(map.get(i).getVal(), i);
|
CHECK_EQUAL(map.get(i).getVal(), i);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ SUITE(AvlTree) {
|
||||||
|
|
||||||
Item buff[size];
|
Item buff[size];
|
||||||
|
|
||||||
for (auto i : Range(size)) {
|
for (auto i : IterRange(size)) {
|
||||||
buff[i].data.setVal(i);
|
buff[i].data.setVal(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ void loadImage(Buffer<halnf>& output, const char* name) {
|
||||||
|
|
||||||
output.reserve(x * y);
|
output.reserve(x * y);
|
||||||
|
|
||||||
for (auto i : Range(output.size())) {
|
for (auto i : IterRange(output.size())) {
|
||||||
output[i] = loadedImage[i * 4] / 255.f;
|
output[i] = loadedImage[i * 4] / 255.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ bool loadDataset(Dataset& out, const std::string& location) {
|
||||||
out.labels.reserve(out.length);
|
out.labels.reserve(out.length);
|
||||||
out.images.reserve(out.length);
|
out.images.reserve(out.length);
|
||||||
|
|
||||||
for (auto i : Range(out.length)) {
|
for (auto i : IterRange(out.length)) {
|
||||||
auto& image = out.images[i];
|
auto& image = out.images[i];
|
||||||
image.reserve(sizeX * sizeY);
|
image.reserve(sizeX * sizeY);
|
||||||
dataset.readBytes((LocalConnection::Byte*) image.getBuff(), sizeX * sizeY);
|
dataset.readBytes((LocalConnection::Byte*) image.getBuff(), sizeX * sizeY);
|
||||||
|
|
@ -89,7 +89,7 @@ struct NumberRec {
|
||||||
}
|
}
|
||||||
|
|
||||||
mTestcases.reserve(dataset.images.size());
|
mTestcases.reserve(dataset.images.size());
|
||||||
for (auto i : Range(dataset.images.size())) {
|
for (auto i : IterRange(dataset.images.size())) {
|
||||||
auto& image = dataset.images[i];
|
auto& image = dataset.images[i];
|
||||||
auto label = dataset.labels[i];
|
auto label = dataset.labels[i];
|
||||||
|
|
||||||
|
|
@ -97,13 +97,13 @@ struct NumberRec {
|
||||||
|
|
||||||
testcase.output.reserve(10);
|
testcase.output.reserve(10);
|
||||||
|
|
||||||
for (auto dig : Range(10)) {
|
for (auto dig : IterRange(10)) {
|
||||||
testcase.output[dig] = label == dig ? 1 : 0;
|
testcase.output[dig] = label == dig ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
testcase.input.reserve(image.size());
|
testcase.input.reserve(image.size());
|
||||||
|
|
||||||
for (auto pxl : Range(image.size())) {
|
for (auto pxl : IterRange(image.size())) {
|
||||||
testcase.input[pxl] = (halnf) image[pxl] / 255.f;
|
testcase.input[pxl] = (halnf) image[pxl] / 255.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +137,7 @@ struct NumberRec {
|
||||||
|
|
||||||
static halni getMaxIdx(const Buffer<halnf>& in) {
|
static halni getMaxIdx(const Buffer<halnf>& in) {
|
||||||
halni out = 0;
|
halni out = 0;
|
||||||
for (auto i : Range(in.size())) {
|
for (auto i : IterRange(in.size())) {
|
||||||
if (in[i] > in[out]) {
|
if (in[i] > in[out]) {
|
||||||
out = i;
|
out = i;
|
||||||
}
|
}
|
||||||
|
|
@ -165,15 +165,15 @@ struct NumberRec {
|
||||||
void displayImage(ualni idx) {
|
void displayImage(ualni idx) {
|
||||||
auto& testcase = mTestcases[idx];
|
auto& testcase = mTestcases[idx];
|
||||||
printf("Image : %i\n", int(getMaxIdx(testcase.output)));
|
printf("Image : %i\n", int(getMaxIdx(testcase.output)));
|
||||||
for (auto i : Range(28)) {
|
for (auto i : IterRange(28)) {
|
||||||
for (auto j : Range(28)) {
|
for (auto j : IterRange(28)) {
|
||||||
printf("%c", char(testcase.input[j * 28 + i] * 255));
|
printf("%c", char(testcase.input[j * 28 + i] * 255));
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
halnf test(const Range<halni>& range) {
|
halnf test(const IterRange<halni>& range) {
|
||||||
halnf avgCost = 0;
|
halnf avgCost = 0;
|
||||||
for (auto i : range) {
|
for (auto i : range) {
|
||||||
avgCost += eval(i);
|
avgCost += eval(i);
|
||||||
|
|
@ -182,7 +182,7 @@ struct NumberRec {
|
||||||
return avgCost;
|
return avgCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trainStep(const Range<halni>& range) {
|
void trainStep(const IterRange<halni>& range) {
|
||||||
nn.clearGrad();
|
nn.clearGrad();
|
||||||
for (auto i : range) {
|
for (auto i : range) {
|
||||||
nn.evaluate(mTestcases[i].input, output);
|
nn.evaluate(mTestcases[i].input, output);
|
||||||
|
|
@ -210,18 +210,19 @@ int main() {
|
||||||
NumberRec app;
|
NumberRec app;
|
||||||
|
|
||||||
auto numBatches = 10;
|
auto numBatches = 10;
|
||||||
auto trainRange = Range(0, 50000);
|
auto trainRange = IterRange(0, 50000);
|
||||||
auto testRange = Range(50000, 70000);
|
auto testRange = IterRange(50000, 70000);
|
||||||
|
|
||||||
auto batchSize = trainRange.idxDiff() / numBatches;
|
auto batchSize = trainRange.idxDiff() / numBatches;
|
||||||
|
|
||||||
for (auto epoch : Range(1)) {
|
for (auto epoch : IterRange(1)) {
|
||||||
printf("Epoch %i\n", epoch.index());
|
printf("Epoch %i\n", epoch.index());
|
||||||
|
|
||||||
for (auto batchIdx : Range(trainRange.idxDiff() / batchSize)) {
|
for (auto batchIdx : IterRange(trainRange.idxDiff() / batchSize)) {
|
||||||
printf(" - Batch :%i \n", batchIdx.index());
|
printf(" - Batch :%i \n", batchIdx.index());
|
||||||
|
|
||||||
auto batchRange = Range(trainRange.idxBegin() + batchSize * batchIdx, trainRange.idxBegin() + batchSize * (batchIdx + 1));
|
auto batchRange =
|
||||||
|
IterRange(trainRange.idxBegin() + batchSize * batchIdx, trainRange.idxBegin() + batchSize * (batchIdx + 1));
|
||||||
|
|
||||||
app.trainStep(batchRange);
|
app.trainStep(batchRange);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ void FCNN::initializeRandom(const Buffer<halni>& description) {
|
||||||
|
|
||||||
mLayers.reserve(description.size());
|
mLayers.reserve(description.size());
|
||||||
|
|
||||||
for (auto i : Range<halni>(0, (halni) description.size())) {
|
for (auto i : IterRange<halni>(0, (halni) description.size())) {
|
||||||
mLayers[i].neurons.reserve(description[i]);
|
mLayers[i].neurons.reserve(description[i]);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -50,17 +50,17 @@ void FCNN::initializeRandom(const Buffer<halni>& description) {
|
||||||
void FCNN::evaluate(const Buffer<halnf>& input, Buffer<halnf>& output) {
|
void FCNN::evaluate(const Buffer<halnf>& input, Buffer<halnf>& output) {
|
||||||
ASSERT(output.size() == mLayers.last().neurons.size() && input.size() == mLayers.first().neurons.size())
|
ASSERT(output.size() == mLayers.last().neurons.size() && input.size() == mLayers.first().neurons.size())
|
||||||
|
|
||||||
for (auto idx : Range(input.size())) {
|
for (auto idx : IterRange(input.size())) {
|
||||||
mLayers.first().neurons[idx].activationValue = input[idx];
|
mLayers.first().neurons[idx].activationValue = input[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto layerIdx : Range<halni>(1, (halni) mLayers.size())) {
|
for (auto layerIdx : IterRange<halni>(1, (halni) mLayers.size())) {
|
||||||
auto& layer = mLayers[layerIdx];
|
auto& layer = mLayers[layerIdx];
|
||||||
auto& layerPrev = mLayers[layerIdx - 1];
|
auto& layerPrev = mLayers[layerIdx - 1];
|
||||||
|
|
||||||
for (auto neuron : layer.neurons) {
|
for (auto neuron : layer.neurons) {
|
||||||
neuron->activationValue = 0;
|
neuron->activationValue = 0;
|
||||||
for (auto connectionIdx : Range(neuron->weights.size())) {
|
for (auto connectionIdx : IterRange(neuron->weights.size())) {
|
||||||
neuron->activationValue += neuron->weights[connectionIdx].val * layerPrev.neurons[connectionIdx].activationValue;
|
neuron->activationValue += neuron->weights[connectionIdx].val * layerPrev.neurons[connectionIdx].activationValue;
|
||||||
}
|
}
|
||||||
neuron->activationValue += neuron->bias.val;
|
neuron->activationValue += neuron->bias.val;
|
||||||
|
|
@ -69,26 +69,26 @@ void FCNN::evaluate(const Buffer<halnf>& input, Buffer<halnf>& output) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto idx : Range(output.size())) {
|
for (auto idx : IterRange(output.size())) {
|
||||||
output[idx] = mLayers.last().neurons[idx].activationValue;
|
output[idx] = mLayers.last().neurons[idx].activationValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
halnf FCNN::calcCost(const Buffer<halnf>& output) {
|
halnf FCNN::calcCost(const Buffer<halnf>& output) {
|
||||||
halnf out = 0;
|
halnf out = 0;
|
||||||
for (auto neuronIdx : Range(mLayers.last().neurons.size())) {
|
for (auto neuronIdx : IterRange(mLayers.last().neurons.size())) {
|
||||||
out += pow(output[neuronIdx] - mLayers.last().neurons[neuronIdx].activationValue, 2);
|
out += pow(output[neuronIdx] - mLayers.last().neurons[neuronIdx].activationValue, 2);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCNN::clearGrad() {
|
void FCNN::clearGrad() {
|
||||||
for (auto layIdx : Range<halni>(1, (halni) mLayers.size())) {
|
for (auto layIdx : IterRange<halni>(1, (halni) mLayers.size())) {
|
||||||
auto& layer = mLayers[layIdx];
|
auto& layer = mLayers[layIdx];
|
||||||
|
|
||||||
for (auto neuron : layer.neurons) {
|
for (auto neuron : layer.neurons) {
|
||||||
neuron->bias.grad = 0;
|
neuron->bias.grad = 0;
|
||||||
for (auto weightIdx : Range(neuron->weights.size())) {
|
for (auto weightIdx : IterRange(neuron->weights.size())) {
|
||||||
neuron->weights[weightIdx].grad = 0;
|
neuron->weights[weightIdx].grad = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +102,7 @@ void FCNN::calcGrad(const Buffer<halnf>& output) {
|
||||||
auto& lastLayer = mLayers.last();
|
auto& lastLayer = mLayers.last();
|
||||||
|
|
||||||
// calculate chaining cache value for each neuron in last layer
|
// calculate chaining cache value for each neuron in last layer
|
||||||
for (auto neuronIdx : Range(lastLayer.neurons.size())) {
|
for (auto neuronIdx : IterRange(lastLayer.neurons.size())) {
|
||||||
auto& neuron = lastLayer.neurons[neuronIdx];
|
auto& neuron = lastLayer.neurons[neuronIdx];
|
||||||
neuron.cache = 2 * (neuron.activationValue - output[neuronIdx]);
|
neuron.cache = 2 * (neuron.activationValue - output[neuronIdx]);
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +113,7 @@ void FCNN::calcGrad(const Buffer<halnf>& output) {
|
||||||
auto& currentLayer = mLayers[layerIdx];
|
auto& currentLayer = mLayers[layerIdx];
|
||||||
auto& inputLayer = mLayers[layerIdx - 1];
|
auto& inputLayer = mLayers[layerIdx - 1];
|
||||||
|
|
||||||
for (auto currentNeuronIdx : Range(currentLayer.neurons.size())) {
|
for (auto currentNeuronIdx : IterRange(currentLayer.neurons.size())) {
|
||||||
auto& currentNeuron = currentLayer.neurons[currentNeuronIdx];
|
auto& currentNeuron = currentLayer.neurons[currentNeuronIdx];
|
||||||
|
|
||||||
// calculate cache value (chaining)
|
// calculate cache value (chaining)
|
||||||
|
|
@ -131,7 +131,7 @@ void FCNN::calcGrad(const Buffer<halnf>& output) {
|
||||||
currentNeuron.bias.grad += currentNeuron.cache;
|
currentNeuron.bias.grad += currentNeuron.cache;
|
||||||
|
|
||||||
// calculate gradient for weights of current neuron
|
// calculate gradient for weights of current neuron
|
||||||
for (auto weightIdx : Range(currentNeuron.weights.size())) {
|
for (auto weightIdx : IterRange(currentNeuron.weights.size())) {
|
||||||
currentNeuron.weights[weightIdx].grad += inputLayer.neurons[weightIdx].activationValue * currentNeuron.cache;
|
currentNeuron.weights[weightIdx].grad += inputLayer.neurons[weightIdx].activationValue * currentNeuron.cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,12 +142,12 @@ void FCNN::calcGrad(const Buffer<halnf>& output) {
|
||||||
|
|
||||||
void FCNN::applyGrad(halnf step) {
|
void FCNN::applyGrad(halnf step) {
|
||||||
|
|
||||||
for (auto layIdx : Range<halni>(1, (halni) mLayers.size())) {
|
for (auto layIdx : IterRange<halni>(1, (halni) mLayers.size())) {
|
||||||
auto& layer = mLayers[layIdx];
|
auto& layer = mLayers[layIdx];
|
||||||
|
|
||||||
for (auto neuron : layer.neurons) {
|
for (auto neuron : layer.neurons) {
|
||||||
neuron->bias.val -= neuron->bias.grad / (halnf) mAvgCount * step;
|
neuron->bias.val -= neuron->bias.grad / (halnf) mAvgCount * step;
|
||||||
for (auto weightIdx : Range(neuron->weights.size())) {
|
for (auto weightIdx : IterRange(neuron->weights.size())) {
|
||||||
neuron->weights[weightIdx].val -= (neuron->weights[weightIdx].grad / (halnf) mAvgCount) * step;
|
neuron->weights[weightIdx].val -= (neuron->weights[weightIdx].grad / (halnf) mAvgCount) * step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,11 @@ SUITE(FCNN) {
|
||||||
Buffer<halnf> outputExpected(layers.last());
|
Buffer<halnf> outputExpected(layers.last());
|
||||||
Buffer<halnf> output(layers.last());
|
Buffer<halnf> output(layers.last());
|
||||||
|
|
||||||
for (auto inputVal : Range(layers.first())) {
|
for (auto inputVal : IterRange(layers.first())) {
|
||||||
input[inputVal] = inputLayer[inputVal];
|
input[inputVal] = inputLayer[inputVal];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto outIdx : Range(layers.last())) {
|
for (auto outIdx : IterRange(layers.last())) {
|
||||||
outputExpected[outIdx] = outputLayer[outIdx];
|
outputExpected[outIdx] = outputLayer[outIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ SUITE(FCNN) {
|
||||||
|
|
||||||
halnf cost = 0;
|
halnf cost = 0;
|
||||||
|
|
||||||
for (auto i : Range(150)) {
|
for (auto i : IterRange(150)) {
|
||||||
|
|
||||||
nn.evaluate(input, output);
|
nn.evaluate(input, output);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,18 +88,18 @@ void TopologyCache::updateCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformedPoints.reserve(Source->Points.size());
|
TransformedPoints.reserve(Source->Points.size());
|
||||||
for (auto idx : Range(TransformedPoints.size())) {
|
for (auto idx : IterRange(TransformedPoints.size())) {
|
||||||
TransformedPoints[idx] = Source->Basis.transform(Source->Points[idx]);
|
TransformedPoints[idx] = Source->Basis.transform(Source->Points[idx]);
|
||||||
TransformedPoints[idx] += Source->Origin;
|
TransformedPoints[idx] += Source->Origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformedNormals.reserve(Source->Normals.size());
|
TransformedNormals.reserve(Source->Normals.size());
|
||||||
for (auto idx : Range(TransformedNormals.size())) {
|
for (auto idx : IterRange(TransformedNormals.size())) {
|
||||||
TransformedNormals[idx] = Source->Basis.transform(Source->Normals[idx]);
|
TransformedNormals[idx] = Source->Basis.transform(Source->Normals[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrigCaches.reserve(Source->Indexes.size());
|
TrigCaches.reserve(Source->Indexes.size());
|
||||||
for (auto idx : Range(TrigCaches.size())) {
|
for (auto idx : IterRange(TrigCaches.size())) {
|
||||||
TrigCaches[idx].mP1 = Source->Indexes[idx].x;
|
TrigCaches[idx].mP1 = Source->Indexes[idx].x;
|
||||||
TrigCaches[idx].mP2 = Source->Indexes[idx].y;
|
TrigCaches[idx].mP2 = Source->Indexes[idx].y;
|
||||||
TrigCaches[idx].mP3 = Source->Indexes[idx].z;
|
TrigCaches[idx].mP3 = Source->Indexes[idx].z;
|
||||||
|
|
|
||||||
39
Math/public/Range.hpp
Normal file
39
Math/public/Range.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
template <typename Type>
|
||||||
|
class Range {
|
||||||
|
public:
|
||||||
|
Range() = default;
|
||||||
|
Range(Type v1, Type v2) : start(v1), end(v2) {}
|
||||||
|
|
||||||
|
Type mid() const { return (start + end) / 2.f; }
|
||||||
|
Type size() const { return (end - start); }
|
||||||
|
|
||||||
|
void resizeFromCenter(Type newSize) {
|
||||||
|
const auto middle = mid();
|
||||||
|
const auto len = newSize / 2;
|
||||||
|
start = middle - len;
|
||||||
|
end = middle + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clamp(const Range& inside, const Range& outside) {
|
||||||
|
start = tp::clamp(start, outside.start, inside.start);
|
||||||
|
end = tp::clamp(end, inside.end, outside.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clamp(const Range& outside) {
|
||||||
|
start = tp::clamp(start, outside.start, outside.end);
|
||||||
|
end = tp::clamp(end, outside.start, outside.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Type start{};
|
||||||
|
Type end{};
|
||||||
|
};
|
||||||
|
|
||||||
|
using RangeF = Range<halnf>;
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Vec.hpp"
|
#include "Vec.hpp"
|
||||||
|
#include "Range.hpp"
|
||||||
|
|
||||||
#include "Intersections.hpp"
|
#include "Intersections.hpp"
|
||||||
|
|
||||||
|
|
@ -35,6 +36,11 @@ namespace tp {
|
||||||
this->size = size;
|
this->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rect(const Range<Type>& rx, const Range<Type>& ry) {
|
||||||
|
this->pos = { rx.start, ry.start };
|
||||||
|
this->size = { rx.size(), ry.size() };
|
||||||
|
}
|
||||||
|
|
||||||
Rect(Type aPosX, Type posy, Type aSizeX, Type aSizeY) {
|
Rect(Type aPosX, Type posy, Type aSizeX, Type aSizeY) {
|
||||||
pos.assign(aPosX, posy);
|
pos.assign(aPosX, posy);
|
||||||
size.assign(aSizeX, aSizeY);
|
size.assign(aSizeX, aSizeY);
|
||||||
|
|
@ -64,7 +70,7 @@ namespace tp {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(Rect<Type>& rect) const { return (pos == rect.pos && size == rect.size); }
|
bool operator==(const Rect<Type>& rect) const { return (pos == rect.pos && size == rect.size); }
|
||||||
|
|
||||||
bool isEnclosedIn(const Rect<Type>& rect, bool aParent = false) const {
|
bool isEnclosedIn(const Rect<Type>& rect, bool aParent = false) const {
|
||||||
if (aParent) {
|
if (aParent) {
|
||||||
|
|
@ -102,6 +108,11 @@ namespace tp {
|
||||||
|
|
||||||
void invertY(Type scr_y) { pos.y = scr_y - pos.y - size.y; }
|
void invertY(Type scr_y) { pos.y = scr_y - pos.y - size.y; }
|
||||||
|
|
||||||
|
Rect& move(Vec2<Type> delta) {
|
||||||
|
move(delta.x, delta.y);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void move(Type dx, Type dy) {
|
void move(Type dx, Type dy) {
|
||||||
pos.x += dx;
|
pos.x += dx;
|
||||||
pos.y += dy;
|
pos.y += dy;
|
||||||
|
|
@ -119,6 +130,9 @@ namespace tp {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Range<Type> getRangeX() const { return { x, x + z }; }
|
||||||
|
Range<Type> getRangeY() const { return { y, y + w }; }
|
||||||
|
|
||||||
// pos
|
// pos
|
||||||
Vec2<Type> p1() const { return pos; }
|
Vec2<Type> p1() const { return pos; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,8 +226,8 @@ namespace tp {
|
||||||
Type y;
|
Type y;
|
||||||
|
|
||||||
Vec() :
|
Vec() :
|
||||||
x(0),
|
x{},
|
||||||
y(0) {}
|
y{} {}
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
template <typename TypeIn>
|
template <typename TypeIn>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace tp {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename tType = ualni>
|
template <typename tType = ualni>
|
||||||
class Range {
|
class IterRange {
|
||||||
public:
|
public:
|
||||||
class Iterator {
|
class Iterator {
|
||||||
public:
|
public:
|
||||||
|
|
@ -71,13 +71,13 @@ namespace tp {
|
||||||
tType mBegin{};
|
tType mBegin{};
|
||||||
tType mEnd{};
|
tType mEnd{};
|
||||||
|
|
||||||
Range() = default;
|
IterRange() = default;
|
||||||
|
|
||||||
explicit Range(tType pEndIndex) :
|
explicit IterRange(tType pEndIndex) :
|
||||||
mBegin(0),
|
mBegin(0),
|
||||||
mEnd(pEndIndex) {}
|
mEnd(pEndIndex) {}
|
||||||
|
|
||||||
Range(tType pStartIndex, tType pEndIndex) :
|
IterRange(tType pStartIndex, tType pEndIndex) :
|
||||||
mBegin(pStartIndex),
|
mBegin(pStartIndex),
|
||||||
mEnd(pEndIndex) {}
|
mEnd(pEndIndex) {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -410,14 +410,14 @@ alni instSize(const Instruction& inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeConst(ByteCode& out, alni& idx, uint2 data) {
|
void writeConst(ByteCode& out, alni& idx, uint2 data) {
|
||||||
for (auto byte : Range(sizeof(uint2))) {
|
for (auto byte : IterRange(sizeof(uint2))) {
|
||||||
out.mInstructions[idx] = OpCode((int1) (data >> byte * 8));
|
out.mInstructions[idx] = OpCode((int1) (data >> byte * 8));
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeParam(ByteCode& out, alni& idx, const int1* data, alni size) {
|
void writeParam(ByteCode& out, alni& idx, const int1* data, alni size) {
|
||||||
for (auto byte : Range(size)) {
|
for (auto byte : IterRange(size)) {
|
||||||
out.mInstructions[idx] = OpCode(data[byte]);
|
out.mInstructions[idx] = OpCode(data[byte]);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ void RayTracer::cycle(const RayCastData& castData, LightData& out, uhalni depth)
|
||||||
const auto delta1 = castData.trig->mEdgeP1P2.unitV();
|
const auto delta1 = castData.trig->mEdgeP1P2.unitV();
|
||||||
const auto delta2 = normal.cross(delta1);
|
const auto delta2 = normal.cross(delta1);
|
||||||
|
|
||||||
for (auto idx : Range(mSettings.spray)) {
|
for (auto idx : IterRange(mSettings.spray)) {
|
||||||
RayCastData materialCastData;
|
RayCastData materialCastData;
|
||||||
LightData lightData;
|
LightData lightData;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,16 +35,16 @@ const RGBA& Stroke::getColor() const { return mColor; }
|
||||||
void Stroke::updateGpuBuffers() { mGPUHandles.sendDataToGPU(&mPoints); }
|
void Stroke::updateGpuBuffers() { mGPUHandles.sendDataToGPU(&mPoints); }
|
||||||
|
|
||||||
void Stroke::denoisePos(halni passes) {
|
void Stroke::denoisePos(halni passes) {
|
||||||
for (auto pass : Range(passes)) {
|
for (auto pass : IterRange(passes)) {
|
||||||
for (auto pi : Range(mPoints.size() - 2)) {
|
for (auto pi : IterRange(mPoints.size() - 2)) {
|
||||||
mPoints[pi + 1].pos = (mPoints[pi + 1].pos + mPoints[pi].pos + mPoints[pi + 2].pos) / 3.f;
|
mPoints[pi + 1].pos = (mPoints[pi + 1].pos + mPoints[pi].pos + mPoints[pi + 2].pos) / 3.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::denoiseThickness(halni passes) {
|
void Stroke::denoiseThickness(halni passes) {
|
||||||
for (auto pass : Range(passes)) {
|
for (auto pass : IterRange(passes)) {
|
||||||
for (auto pi : Range(mPoints.size() - 2)) {
|
for (auto pi : IterRange(mPoints.size() - 2)) {
|
||||||
mPoints[pi + 1].thickness = (mPoints[pi].thickness + mPoints[pi + 2].thickness) / 2.f;
|
mPoints[pi + 1].thickness = (mPoints[pi].thickness + mPoints[pi + 2].thickness) / 2.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ void Stroke::compress(halnf factor) {
|
||||||
|
|
||||||
List<StrokePoint> passed_poits;
|
List<StrokePoint> passed_poits;
|
||||||
|
|
||||||
for (auto idx : Range(mPoints.size())) {
|
for (auto idx : IterRange(mPoints.size())) {
|
||||||
passed_poits.pushBack(mPoints[idx]);
|
passed_poits.pushBack(mPoints[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,14 +100,14 @@ void Stroke::subdiv(halnf precision, const Camera* cam, halni passes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<StrokePoint> new_points;
|
List<StrokePoint> new_points;
|
||||||
for (auto idx : Range(mPoints.size())) {
|
for (auto idx : IterRange(mPoints.size())) {
|
||||||
new_points.pushBack(mPoints[idx]);
|
new_points.pushBack(mPoints[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto viewmat = cam->calculateViewMatrix();
|
auto viewmat = cam->calculateViewMatrix();
|
||||||
auto projmat = cam->calculateProjectionMatrix();
|
auto projmat = cam->calculateProjectionMatrix();
|
||||||
|
|
||||||
for (auto i : Range(passes)) {
|
for (auto i : IterRange(passes)) {
|
||||||
|
|
||||||
auto n_points = new_points.length();
|
auto n_points = new_points.length();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ using namespace tp;
|
||||||
class WidgetApplication : public Application {
|
class WidgetApplication : public Application {
|
||||||
public:
|
public:
|
||||||
WidgetApplication() {
|
WidgetApplication() {
|
||||||
setup1();
|
setup2();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup1() {
|
void setup1() {
|
||||||
|
|
@ -20,8 +20,8 @@ public:
|
||||||
mDockLayout.addChild(&mFloatingMenu);
|
mDockLayout.addChild(&mFloatingMenu);
|
||||||
mDockLayout.addChild(&mFloatingMenu2);
|
mDockLayout.addChild(&mFloatingMenu2);
|
||||||
|
|
||||||
mDockLayout.setCenterWidget(&mButton3);
|
mDockLayout.setCenterWidget(&mButton4);
|
||||||
mDockLayout.dockWidget(&mButton4, DockLayoutWidget::RIGHT);
|
mDockLayout.dockWidget(&mButton3, DockLayoutWidget::RIGHT);
|
||||||
|
|
||||||
mFloatingMenu.addToMenu(&mButton);
|
mFloatingMenu.addToMenu(&mButton);
|
||||||
mFloatingMenu2.addToMenu(&mButton2);
|
mFloatingMenu2.addToMenu(&mButton2);
|
||||||
|
|
@ -29,6 +29,11 @@ public:
|
||||||
mButton.setAction([this]() { mButton2.setColor(RGBA::random()); });
|
mButton.setAction([this]() { mButton2.setColor(RGBA::random()); });
|
||||||
mButton2.setAction([this]() { mButton.setColor(RGBA::random()); });
|
mButton2.setAction([this]() { mButton.setColor(RGBA::random()); });
|
||||||
|
|
||||||
|
mButton3.setAction([this]() { mDockLayout.dockWidget(&mFloatingMenu, DockLayoutWidget::Side::LEFT); });
|
||||||
|
mButton3.setText("dock");
|
||||||
|
|
||||||
|
mButton4.setAction([this]() { mDockLayout.undockWidget(DockLayoutWidget::Side::LEFT); });
|
||||||
|
|
||||||
// mLayoutWidget.addChild(&mButton2);
|
// mLayoutWidget.addChild(&mButton2);
|
||||||
|
|
||||||
// mWidgetFloating.addChild(&mButton);
|
// mWidgetFloating.addChild(&mButton);
|
||||||
|
|
@ -48,7 +53,24 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup2() {
|
void setup2() {
|
||||||
mRootWidget.setRootWidget(&mLabel);
|
mRootWidget.setRootWidget(&mDesktopLayout);
|
||||||
|
mDesktopLayout.addChild(&mWidget);
|
||||||
|
|
||||||
|
mWidget.addChild(&mButton);
|
||||||
|
mWidget.addChild(&mButton2);
|
||||||
|
mWidget.addChild(&mButton3);
|
||||||
|
|
||||||
|
mButton.setSizePolicy(Widget::SizePolicy::Expand, Widget::SizePolicy::Contract);
|
||||||
|
mButton2.setSizePolicy(Widget::SizePolicy::Expand, Widget::SizePolicy::Contract);
|
||||||
|
mButton3.setSizePolicy(Widget::SizePolicy::Expand, Widget::SizePolicy::Contract);
|
||||||
|
|
||||||
|
mWidget.setSizePolicy(Widget::SizePolicy::Contract, Widget::SizePolicy::Contract);
|
||||||
|
mWidget.setLayoutPolicy(Widget::LayoutPolicy::Horizontally);
|
||||||
|
|
||||||
|
mButton.setAction([this]() { mButton2.setMinSize(mButton2.getMinSize() + 10); });
|
||||||
|
mButton2.setAction([this]() { mButton.setMinSize(mButton.getMinSize() + 10); } );
|
||||||
|
|
||||||
|
RootWidget::setWidgetArea(mWidget, { 300, 100, 150, 200 });
|
||||||
}
|
}
|
||||||
|
|
||||||
void processFrame(EventHandler* eventHandler, halnf deltaTime) override {
|
void processFrame(EventHandler* eventHandler, halnf deltaTime) override {
|
||||||
|
|
@ -67,6 +89,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Widget mWidget;
|
||||||
|
|
||||||
ButtonWidget mButton;
|
ButtonWidget mButton;
|
||||||
ButtonWidget mButton2;
|
ButtonWidget mButton2;
|
||||||
ButtonWidget mButton3;
|
ButtonWidget mButton3;
|
||||||
|
|
@ -78,7 +102,7 @@ private:
|
||||||
LabelWidget mLabel;
|
LabelWidget mLabel;
|
||||||
FloatingWidget mWidgetFloating;
|
FloatingWidget mWidgetFloating;
|
||||||
AnimationTestWidget mAnimationTestWidget;
|
AnimationTestWidget mAnimationTestWidget;
|
||||||
DesktopLayout mLayoutWidget;
|
DesktopLayout mDesktopLayout;
|
||||||
|
|
||||||
DockLayoutWidget mDockLayout;
|
DockLayoutWidget mDockLayout;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "DockLayoutWidget.hpp"
|
#include "DockLayoutWidget.hpp"
|
||||||
|
#include "FloatingWidget.hpp"
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
|
|
@ -11,9 +12,33 @@ DockLayoutWidget::DockLayoutWidget() {
|
||||||
|
|
||||||
void DockLayoutWidget::process(const EventHandler& events) {
|
void DockLayoutWidget::process(const EventHandler& events) {
|
||||||
// calculateHeaderAreas();
|
// calculateHeaderAreas();
|
||||||
// handlePreview(events);
|
|
||||||
|
|
||||||
handleResizeEvents(events);
|
Widget* floater = nullptr;
|
||||||
|
for (auto child : mChildren) {
|
||||||
|
if (auto iter = dynamic_cast<FloatingWidget*>(child)) {
|
||||||
|
if (iter->isFloating()) {
|
||||||
|
floater = iter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (floater) undockWidget(getSideFromWidget(floater), false);
|
||||||
|
|
||||||
|
if (floater) {
|
||||||
|
handlePreview(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPreviewWidget && !floater) {
|
||||||
|
dockWidget(mPreviewWidget, mPreviewSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreviewWidget = floater;
|
||||||
|
|
||||||
|
if (!mPreviewWidget) {
|
||||||
|
handleResizeEvents(events);
|
||||||
|
}
|
||||||
|
|
||||||
calculateSideAreas();
|
calculateSideAreas();
|
||||||
calculateResizeHandles();
|
calculateResizeHandles();
|
||||||
updateChildSideWidgets();
|
updateChildSideWidgets();
|
||||||
|
|
@ -40,7 +65,7 @@ void DockLayoutWidget::drawOverlay(Canvas& canvas) {
|
||||||
canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0);
|
canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPreview) {
|
if (mPreviewWidget) {
|
||||||
if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding);
|
if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding);
|
||||||
|
|
||||||
for (auto& sideWidget : mSideWidgets) {
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
|
@ -64,10 +89,16 @@ void DockLayoutWidget::setCenterWidget(Widget* widget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayoutWidget::dockWidget(Widget* widget, Side side) {
|
void DockLayoutWidget::dockWidget(Widget* widget, Side side) {
|
||||||
DEBUG_ASSERT(!sideExists(side))
|
if (sideExists(side) || side == Side::NONE) return;
|
||||||
|
|
||||||
addChild(widget);
|
addChild(widget);
|
||||||
|
|
||||||
|
widget->bringToBack();
|
||||||
|
if (mCenterWidget) mCenterWidget->bringToBack();
|
||||||
|
for (auto& order : mSideWidgets) {
|
||||||
|
if (order.widget) order.widget->bringToBack();
|
||||||
|
}
|
||||||
|
|
||||||
auto& sideWidget = mSideWidgets[side];
|
auto& sideWidget = mSideWidgets[side];
|
||||||
sideWidget.widget = widget;
|
sideWidget.widget = widget;
|
||||||
|
|
||||||
|
|
@ -79,10 +110,21 @@ void DockLayoutWidget::dockWidget(Widget* widget, Side side) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sideWidget.hidden = false;
|
sideWidget.hidden = false;
|
||||||
|
sideWidget.areaBeforeDocking = widget->getArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayoutWidget::undockWidget(Side side) {
|
void DockLayoutWidget::undockWidget(Side side, bool restoreArea) {
|
||||||
DEBUG_ASSERT(sideExists(side))
|
if (!sideExists(side) || (side == Side::NONE)) return;
|
||||||
|
|
||||||
|
auto& sideWidget = mSideWidgets[side];
|
||||||
|
|
||||||
|
sideWidget.widget->bringToFront();
|
||||||
|
|
||||||
|
if (restoreArea) {
|
||||||
|
sideWidget.widget->setArea(sideWidget.areaBeforeDocking);
|
||||||
|
} else {
|
||||||
|
sideWidget.widget->endAnimations();
|
||||||
|
}
|
||||||
|
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
for (ualni i = 0; i < 3; i++) {
|
for (ualni i = 0; i < 3; i++) {
|
||||||
|
|
@ -275,7 +317,9 @@ bool DockLayoutWidget::isSideVisible(DockLayoutWidget::Side side) {
|
||||||
return sideExists(side) && !mSideWidgets[side].hidden;
|
return sideExists(side) && !mSideWidgets[side].hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockLayoutWidget::sideExists(DockLayoutWidget::Side side) { return mSideWidgets[side].widget; }
|
bool DockLayoutWidget::sideExists(DockLayoutWidget::Side side) {
|
||||||
|
return mSideWidgets[side].widget;
|
||||||
|
}
|
||||||
|
|
||||||
ualni DockLayoutWidget::getVisibleSidesSize() {
|
ualni DockLayoutWidget::getVisibleSidesSize() {
|
||||||
ualni out = 0;
|
ualni out = 0;
|
||||||
|
|
@ -286,11 +330,6 @@ ualni DockLayoutWidget::getVisibleSidesSize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
||||||
if (!mPreview) {
|
|
||||||
mPreviewSide = NONE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const halnf factor = 0.3;
|
const halnf factor = 0.3;
|
||||||
const halnf handleFactor = 0.1;
|
const halnf handleFactor = 0.1;
|
||||||
|
|
||||||
|
|
@ -313,6 +352,7 @@ void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
||||||
|
|
||||||
mPreviewArea = {};
|
mPreviewArea = {};
|
||||||
mPreviewSide = NONE;
|
mPreviewSide = NONE;
|
||||||
|
|
||||||
for (auto& sideWidget : mSideWidgets) {
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
if (sideWidget.widget) continue;
|
if (sideWidget.widget) continue;
|
||||||
|
|
||||||
|
|
@ -322,3 +362,10 @@ void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto DockLayoutWidget::getSideFromWidget(Widget* widget) -> Side {
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (sideWidget.widget == widget) return sideWidget.side;
|
||||||
|
}
|
||||||
|
return DockLayoutWidget::NONE;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,20 @@ void FloatingWidget::process(const EventHandler& events) {
|
||||||
// triggerWidgetUpdate();
|
// triggerWidgetUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingWidget::adjustRect() {
|
void FloatingWidget::pickRect() {
|
||||||
auto area = getArea();
|
if (mIsFloating) {
|
||||||
|
auto area = getArea();
|
||||||
|
|
||||||
if (mIsResizing) {
|
if (mIsResizing) {
|
||||||
area.size = mPointerCurrent + mHandleSize / 2.f;
|
area.size = mPointerCurrent + mHandleSize / 2.f;
|
||||||
} else if (mIsFloating) {
|
} else if (mIsFloating) {
|
||||||
area.pos += mPointerCurrent - mPointerStart;
|
area.pos += mPointerCurrent - mPointerStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
setArea(area);
|
||||||
|
} else {
|
||||||
|
Widget::pickRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
setArea(area);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingWidget::draw(Canvas& canvas) {
|
void FloatingWidget::draw(Canvas& canvas) {
|
||||||
|
|
@ -56,3 +60,7 @@ RectF FloatingWidget::resizeHandleRect() {
|
||||||
bool FloatingWidget::propagateEventsToChildren() const {
|
bool FloatingWidget::propagateEventsToChildren() const {
|
||||||
return !mIsFloating;
|
return !mIsFloating;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FloatingWidget::isFloating() const {
|
||||||
|
return mIsFloating;
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,12 @@ void RootWidget::setRootWidget(Widget* widget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
||||||
|
if (mDebug) {
|
||||||
|
events->setEnableKeyEvents(true);
|
||||||
|
if (events->isPressed(InputID::K)) mDebugStopProcessing = !mDebugStopProcessing;
|
||||||
|
if (mDebugStopProcessing) return;
|
||||||
|
}
|
||||||
|
|
||||||
mScreenArea = screenArea;
|
mScreenArea = screenArea;
|
||||||
|
|
||||||
mRoot->setArea(screenArea);
|
mRoot->setArea(screenArea);
|
||||||
|
|
@ -38,6 +44,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
||||||
|
|
||||||
// check triggered widgets for removal
|
// check triggered widgets for removal
|
||||||
erase_if(mTriggeredWidgets, [this](auto widget) {
|
erase_if(mTriggeredWidgets, [this](auto widget) {
|
||||||
|
widget->updateAnimations();
|
||||||
if (mWidgetsToProcess.find(widget) == mWidgetsToProcess.end()) return false;
|
if (mWidgetsToProcess.find(widget) == mWidgetsToProcess.end()) return false;
|
||||||
auto end = !widget->needsNextFrame();
|
auto end = !widget->needsNextFrame();
|
||||||
if (end) {
|
if (end) {
|
||||||
|
|
@ -47,7 +54,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RootWidget::needsUpdate() const { return !mTriggeredWidgets.empty(); }
|
bool RootWidget::needsUpdate() const { return !mTriggeredWidgets.empty() || mDebugRedrawAlways; }
|
||||||
|
|
||||||
void RootWidget::drawFrame(Canvas& canvas) {
|
void RootWidget::drawFrame(Canvas& canvas) {
|
||||||
// draw from top to bottom
|
// draw from top to bottom
|
||||||
|
|
@ -60,8 +67,44 @@ void RootWidget::drawFrame(Canvas& canvas) {
|
||||||
|
|
||||||
if (mDebug) {
|
if (mDebug) {
|
||||||
drawDebug(canvas, mRoot, { 0, 0 }, 0);
|
drawDebug(canvas, mRoot, { 0, 0 }, 0);
|
||||||
|
|
||||||
ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.size());
|
ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.size());
|
||||||
ImGui::Text("Widgets To Process: %i", (int) mWidgetsToProcess.size());
|
ImGui::Text("Widgets To Process: %i", (int) mWidgetsToProcess.size());
|
||||||
|
|
||||||
|
ImGui::Text("To Toggle processing press k");
|
||||||
|
ImGui::Checkbox("Stop processing", &mDebugStopProcessing);
|
||||||
|
ImGui::Checkbox("Force new frames", &mDebugRedrawAlways);
|
||||||
|
|
||||||
|
|
||||||
|
if (mInFocusWidget) {
|
||||||
|
ImGui::Text("Item under cursor %s", mInFocusWidget->mName.c_str());
|
||||||
|
|
||||||
|
if (ImGui::BeginListBox("##empty", { -FLT_MIN, 0 })) {
|
||||||
|
for (auto widget = mInFocusWidget; widget && widget != this; widget = widget->mParent) {
|
||||||
|
if (ImGui::CollapsingHeader(widget->mName.c_str())) {
|
||||||
|
ImGui::InputFloat2("min size", &widget->mMinSize.x);
|
||||||
|
ImGui::InputFloat2("max size", &widget->mMaxSize.x);
|
||||||
|
|
||||||
|
int sizePolicyX = int(widget->mSizePolicy.x);
|
||||||
|
int sizePolicyY = int(widget->mSizePolicy.y);
|
||||||
|
int layout = int(widget->mLayoutPolicy);
|
||||||
|
|
||||||
|
if (ImGui::Combo("Size Policy X", &sizePolicyX, "Passive\0Expand\0Contract\0")) {
|
||||||
|
widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Combo("Size Policy Y", &sizePolicyY, "Passive\0Expand\0Contract\0")) {
|
||||||
|
widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Combo("Layout", &layout, "Passive\0Vertical\0Horizontal\0")) {
|
||||||
|
widget->setLayoutPolicy(LayoutPolicy(layout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndListBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,12 +248,13 @@ void RootWidget::updateWidget(Widget* widget) {
|
||||||
void RootWidget::adjustSizes(ActiveTreeNode* iter) {
|
void RootWidget::adjustSizes(ActiveTreeNode* iter) {
|
||||||
if (!iter) return;
|
if (!iter) return;
|
||||||
|
|
||||||
iter->widget->adjustRect();
|
|
||||||
iter->widget->adjustChildrenRect();
|
|
||||||
|
|
||||||
for (auto child : iter->children) {
|
for (auto child : iter->children) {
|
||||||
adjustSizes(child);
|
adjustSizes(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iter->widget->pickRect();
|
||||||
|
iter->widget->adjustChildrenRect();
|
||||||
|
// iter->widget->pickRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootWidget::processActiveTree(ActiveTreeNode* iter, EventHandler& events) {
|
void RootWidget::processActiveTree(ActiveTreeNode* iter, EventHandler& events) {
|
||||||
|
|
@ -257,6 +301,8 @@ void RootWidget::processFocusItems(EventHandler& events) {
|
||||||
|
|
||||||
events.setCursorOrigin(widgetGlobalPos[iter]);
|
events.setCursorOrigin(widgetGlobalPos[iter]);
|
||||||
|
|
||||||
|
widget->mLocalPoint = events.getPointer();
|
||||||
|
|
||||||
if (!eventsProcessed && widget->processesEvents()) {
|
if (!eventsProcessed && widget->processesEvents()) {
|
||||||
events.setEnableKeyEvents(true);
|
events.setEnableKeyEvents(true);
|
||||||
|
|
||||||
|
|
@ -266,6 +312,7 @@ void RootWidget::processFocusItems(EventHandler& events) {
|
||||||
events.setEnableKeyEvents(false);
|
events.setEnableKeyEvents(false);
|
||||||
eventsProcessed = true;
|
eventsProcessed = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
widget->updateAnimations();
|
widget->updateAnimations();
|
||||||
widget->process(events);
|
widget->process(events);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ void ButtonWidget::setColor(const RGBA& in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonWidget::process(const EventHandler& eventHandler) {
|
void ButtonWidget::process(const EventHandler& eventHandler) {
|
||||||
if (getArea().isInside(eventHandler.getPointer())) {
|
if (getRelativeArea().isInside(eventHandler.getPointer())) {
|
||||||
if (eventHandler.isPressed(InputID::MOUSE1)) {
|
if (eventHandler.isPressed(InputID::MOUSE1)) {
|
||||||
mAction();
|
mAction();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
WidgetManagerInterface* Widget::getRoot() {
|
WidgetManagerInterface* Widget::getRoot() {
|
||||||
|
|
@ -17,26 +19,33 @@ void Widget::triggerWidgetUpdate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget::Widget() {
|
Widget::Widget() {
|
||||||
mArea.setTargetRect({ 10, 10, 100, 40, });
|
mArea.setTargetRect({ 100, 100, 10, 10, });
|
||||||
mArea.endAnimation();
|
mArea.endAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::setArea(const RectF& area) {
|
void Widget::setArea(const RectF& area) {
|
||||||
mArea.setTargetRect(area);
|
if (mArea.getTargetRect() == area) return;
|
||||||
|
|
||||||
if (!mArea.shouldEndTransition()) {
|
mArea.setTargetRect(area);
|
||||||
triggerWidgetUpdate();
|
triggerWidgetUpdate();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RectF Widget::getArea() const {
|
RectF Widget::getArea() const {
|
||||||
return mArea.getCurrentRect();
|
return mArea.getCurrentRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RectF Widget::getAreaT() const {
|
||||||
|
return mArea.getTargetRect();
|
||||||
|
}
|
||||||
|
|
||||||
RectF Widget::getRelativeArea() const {
|
RectF Widget::getRelativeArea() const {
|
||||||
return { {}, mArea.getCurrentRect().size };
|
return { {}, mArea.getCurrentRect().size };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RectF Widget::getRelativeAreaT() const {
|
||||||
|
return { {}, mArea.getTargetRect().size };
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::endAnimations() {
|
void Widget::endAnimations() {
|
||||||
mArea.endAnimation();
|
mArea.endAnimation();
|
||||||
}
|
}
|
||||||
|
|
@ -53,20 +62,11 @@ bool Widget::needsNextFrame() const {
|
||||||
return !mArea.shouldEndTransition();
|
return !mArea.shouldEndTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::adjustRect() {
|
|
||||||
if (mChildren.empty()) return;
|
|
||||||
|
|
||||||
auto area = (*mChildren.begin())->getArea();
|
|
||||||
for (auto widget : mChildren) {
|
|
||||||
area.expand(widget->getArea());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::bringToFront() {
|
void Widget::bringToFront() {
|
||||||
if (!mParent) return;
|
if (!mParent) return;
|
||||||
auto& order = mParent->mDepthOrder;
|
auto& order = mParent->mDepthOrder;
|
||||||
auto node = order.find(this);
|
auto node = order.find(this);
|
||||||
DEBUG_ASSERT(node);
|
DEBUG_ASSERT(node)
|
||||||
order.detach(node);
|
order.detach(node);
|
||||||
order.pushFront(node);
|
order.pushFront(node);
|
||||||
}
|
}
|
||||||
|
|
@ -75,18 +75,11 @@ void Widget::bringToBack() {
|
||||||
if (!mParent) return;
|
if (!mParent) return;
|
||||||
auto& order = mParent->mDepthOrder;
|
auto& order = mParent->mDepthOrder;
|
||||||
auto node = order.find(this);
|
auto node = order.find(this);
|
||||||
DEBUG_ASSERT(node);
|
DEBUG_ASSERT(node)
|
||||||
order.detach(node);
|
order.detach(node);
|
||||||
order.pushBack(node);
|
order.pushBack(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::adjustChildrenRect() {
|
|
||||||
auto area = RectF({}, getArea().size);
|
|
||||||
for (auto widget : mChildren) {
|
|
||||||
widget->setArea(area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::mouseEnter() {
|
void Widget::mouseEnter() {
|
||||||
mInFocus = true;
|
mInFocus = true;
|
||||||
}
|
}
|
||||||
|
|
@ -100,6 +93,15 @@ bool Widget::propagateEventsToChildren() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::addChild(Widget* child) {
|
void Widget::addChild(Widget* child) {
|
||||||
|
if (auto node = mDepthOrder.find(child)) {
|
||||||
|
node->data->bringToFront();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child->mParent) {
|
||||||
|
child->mParent->removeChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
mChildren.push_back(child);
|
mChildren.push_back(child);
|
||||||
mDepthOrder.pushBack(child);
|
mDepthOrder.pushBack(child);
|
||||||
|
|
||||||
|
|
@ -108,3 +110,183 @@ void Widget::addChild(Widget* child) {
|
||||||
triggerWidgetUpdate();
|
triggerWidgetUpdate();
|
||||||
child->triggerWidgetUpdate();
|
child->triggerWidgetUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::removeChild(Widget* child) {
|
||||||
|
auto node = mDepthOrder.find(child);
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
mDepthOrder.removeNode(node);
|
||||||
|
mChildren.erase(std::remove(mChildren.begin(), mChildren.end(), child), mChildren.end());
|
||||||
|
|
||||||
|
triggerWidgetUpdate();
|
||||||
|
child->triggerWidgetUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setSizePolicy(tp::Widget::SizePolicy x, tp::Widget::SizePolicy y) {
|
||||||
|
mSizePolicy = { x, y };
|
||||||
|
triggerWidgetUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setLayoutPolicy(LayoutPolicy layoutPolicy) {
|
||||||
|
mLayoutPolicy = layoutPolicy;
|
||||||
|
triggerWidgetUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vec2F& Widget::getMinSize() { return mMinSize; }
|
||||||
|
|
||||||
|
void Widget::setMinSize(const Vec2F& size) {
|
||||||
|
mMinSize = size;
|
||||||
|
triggerWidgetUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::pickRect() {
|
||||||
|
auto current = getAreaT();
|
||||||
|
auto children = getChildrenEnclosure();
|
||||||
|
auto parent = getParentEnclosure();
|
||||||
|
|
||||||
|
auto rangeX = pickRange(current.getRangeX(), children.getRangeX(), parent.getRangeX(), false);
|
||||||
|
auto rangeY = pickRange(current.getRangeY(), children.getRangeY(), parent.getRangeY(), true);
|
||||||
|
|
||||||
|
auto newArea = RectF(rangeX, rangeY);
|
||||||
|
|
||||||
|
for (auto child : mChildren) {
|
||||||
|
child->setArea(child->getAreaT().move(current.pos - newArea.pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
setArea(newArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::clampRect() {
|
||||||
|
auto current = getAreaT();
|
||||||
|
auto children = getChildrenEnclosure();
|
||||||
|
auto parent = getParentEnclosure();
|
||||||
|
|
||||||
|
auto rangeX = clampRange(current.getRangeX(), children.getRangeX(), parent.getRangeX(), false);
|
||||||
|
auto rangeY = clampRange(current.getRangeY(), children.getRangeY(), parent.getRangeY(), true);
|
||||||
|
|
||||||
|
setArea(RectF(rangeX, rangeY));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::adjustChildrenRect() {
|
||||||
|
if (mChildren.empty()) return;
|
||||||
|
|
||||||
|
switch (mLayoutPolicy) {
|
||||||
|
case LayoutPolicy::Passive: break;
|
||||||
|
case LayoutPolicy::Vertically: adjustLayout(true); break;
|
||||||
|
case LayoutPolicy::Horizontally: adjustLayout(false); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
halnf Widget::changeChildSize(tp::Widget* widget, halnf diff, bool vertical) {
|
||||||
|
auto prevSize = widget->getAreaT().size[vertical];
|
||||||
|
{
|
||||||
|
auto area = widget->getAreaT();
|
||||||
|
area.size[vertical] += diff;
|
||||||
|
widget->setArea(area);
|
||||||
|
widget->clampRect();
|
||||||
|
}
|
||||||
|
auto newSize = widget->getAreaT().size[vertical];
|
||||||
|
|
||||||
|
return newSize - prevSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::adjustLayout(bool vertical) {
|
||||||
|
std::vector<std::pair<Widget*, bool>> contributors;
|
||||||
|
Vec2F contentSize = { 0, 0 };
|
||||||
|
Vec2F availableSize = getRelativeAreaT().size;
|
||||||
|
|
||||||
|
for (auto child : mChildren) {
|
||||||
|
contentSize += child->getAreaT().size;
|
||||||
|
if (child->mSizePolicy[vertical] == SizePolicy::Expand) {
|
||||||
|
contributors.emplace_back( child, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto diff = availableSize - contentSize;
|
||||||
|
|
||||||
|
// expand or contract as much as possible
|
||||||
|
while (!contributors.empty() && (diff[vertical] != 0)) {
|
||||||
|
auto quota = diff / (halnf) contributors.size();
|
||||||
|
|
||||||
|
for (auto& contributor : contributors) {
|
||||||
|
if (!contributor.second) continue;
|
||||||
|
|
||||||
|
auto contribution = changeChildSize(contributor.first, quota[vertical], vertical);
|
||||||
|
|
||||||
|
if (contribution == 0) {
|
||||||
|
contributor.second = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff[vertical] -= contribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
contributors.erase(
|
||||||
|
std::remove_if(contributors.begin(), contributors.end(), [](auto node) { return !node.second; }),
|
||||||
|
contributors.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// arrange
|
||||||
|
halnf iterPos = 0;
|
||||||
|
for (auto child : mChildren) {
|
||||||
|
auto area = child->getAreaT();
|
||||||
|
area.pos[vertical] = iterPos;
|
||||||
|
iterPos += area.size[vertical];
|
||||||
|
child->setArea(area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeF Widget::pickRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical) {
|
||||||
|
RangeF out;
|
||||||
|
|
||||||
|
switch (mSizePolicy[vertical]) {
|
||||||
|
case SizePolicy::Passive: out = current; break;
|
||||||
|
case SizePolicy::Expand: out = parent; break;
|
||||||
|
case SizePolicy::Contract: out = children; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = clampRange(out, children, parent, vertical);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeF Widget::clampRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical) {
|
||||||
|
auto out = current;
|
||||||
|
|
||||||
|
if (!mChildren.empty()) {
|
||||||
|
auto clampedChild = children;
|
||||||
|
clampedChild.clamp(parent);
|
||||||
|
out.clamp(clampedChild, parent);
|
||||||
|
} else {
|
||||||
|
out.clamp(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clamp min max sizes
|
||||||
|
auto len = clamp(current.size(), mMinSize[vertical], mMaxSize[vertical]);
|
||||||
|
if (len != current.size()) {
|
||||||
|
out.resizeFromCenter(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF Widget::getChildrenEnclosure() {
|
||||||
|
RectF out;
|
||||||
|
|
||||||
|
if (mChildren.empty()) {
|
||||||
|
out = { getAreaT().center(), { 0, 0 } };
|
||||||
|
} else {
|
||||||
|
for (auto child : mChildren) {
|
||||||
|
out.expand(child->getAreaT());
|
||||||
|
}
|
||||||
|
out.pos += getAreaT().pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF Widget::getParentEnclosure() {
|
||||||
|
DEBUG_ASSERT(mParent);
|
||||||
|
if (!mParent) return { { 0, 0 }, mMaxSize };
|
||||||
|
return mParent->getRelativeAreaT();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,15 @@ namespace tp {
|
||||||
RectF previewHandleArea = {};
|
RectF previewHandleArea = {};
|
||||||
|
|
||||||
ResizeHandle resizeHandle;
|
ResizeHandle resizeHandle;
|
||||||
|
|
||||||
|
RectF areaBeforeDocking = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DockLayoutWidget();
|
DockLayoutWidget();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void adjustRect() override {}
|
void pickRect() override {}
|
||||||
void adjustChildrenRect() override {}
|
void adjustChildrenRect() override {}
|
||||||
|
|
||||||
void process(const EventHandler& events) override;
|
void process(const EventHandler& events) override;
|
||||||
|
|
@ -47,10 +49,11 @@ namespace tp {
|
||||||
void setCenterWidget(Widget* widget);
|
void setCenterWidget(Widget* widget);
|
||||||
|
|
||||||
void dockWidget(Widget* widget, Side side);
|
void dockWidget(Widget* widget, Side side);
|
||||||
void undockWidget(Side side);
|
void undockWidget(Side side, bool restoreArea = true);
|
||||||
void toggleWidgetVisibility(Side side);
|
void toggleWidgetVisibility(Side side);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Side getSideFromWidget(Widget*);
|
||||||
void calculateSideAreas();
|
void calculateSideAreas();
|
||||||
void calculateResizeHandles();
|
void calculateResizeHandles();
|
||||||
void handleResizeEvents(const EventHandler& events);
|
void handleResizeEvents(const EventHandler& events);
|
||||||
|
|
@ -86,9 +89,9 @@ namespace tp {
|
||||||
RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1);
|
RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1);
|
||||||
RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1);
|
RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1);
|
||||||
RGBA mBackgroundColor = RGBA(0, 0, 0, 1);
|
RGBA mBackgroundColor = RGBA(0, 0, 0, 1);
|
||||||
RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 1);
|
RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 0.2);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool mPreview = false;
|
Widget* mPreviewWidget = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ namespace tp {
|
||||||
|
|
||||||
void process(const EventHandler& events) override;
|
void process(const EventHandler& events) override;
|
||||||
|
|
||||||
void adjustRect() override;
|
void pickRect() override;
|
||||||
|
|
||||||
void draw(Canvas& canvas) override;
|
void draw(Canvas& canvas) override;
|
||||||
|
|
||||||
|
|
@ -20,6 +20,8 @@ namespace tp {
|
||||||
|
|
||||||
[[nodiscard]] bool propagateEventsToChildren() const override;
|
[[nodiscard]] bool propagateEventsToChildren() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isFloating() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mIsFloating = false;
|
bool mIsFloating = false;
|
||||||
bool mIsResizing = false;
|
bool mIsResizing = false;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace tp {
|
||||||
// canvas.rect(getRelativeArea(), RGBA(0, 0, 0, 1));
|
// canvas.rect(getRelativeArea(), RGBA(0, 0, 0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjustRect() override {
|
void pickRect() override {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,5 +51,7 @@ namespace tp {
|
||||||
Widget* mInFocusWidget = nullptr;
|
Widget* mInFocusWidget = nullptr;
|
||||||
|
|
||||||
bool mDebug = true;
|
bool mDebug = true;
|
||||||
|
bool mDebugStopProcessing = false;
|
||||||
|
bool mDebugRedrawAlways = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,19 @@ namespace tp {
|
||||||
class Widget {
|
class Widget {
|
||||||
friend class RootWidget;
|
friend class RootWidget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class SizePolicy {
|
||||||
|
Passive,
|
||||||
|
Expand,
|
||||||
|
Contract,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class LayoutPolicy {
|
||||||
|
Passive,
|
||||||
|
Vertically,
|
||||||
|
Horizontally,
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Widget();
|
Widget();
|
||||||
virtual ~Widget() = default;
|
virtual ~Widget() = default;
|
||||||
|
|
@ -23,6 +36,7 @@ namespace tp {
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChild(Widget* child);
|
void addChild(Widget* child);
|
||||||
|
void removeChild(Widget* child);
|
||||||
|
|
||||||
WidgetManagerInterface* getRoot();
|
WidgetManagerInterface* getRoot();
|
||||||
|
|
||||||
|
|
@ -31,18 +45,33 @@ namespace tp {
|
||||||
void bringToFront();
|
void bringToFront();
|
||||||
void bringToBack();
|
void bringToBack();
|
||||||
|
|
||||||
|
void setSizePolicy(SizePolicy x, SizePolicy y);
|
||||||
|
void setLayoutPolicy(LayoutPolicy layoutPolicy);
|
||||||
|
|
||||||
|
const Vec2F& getMinSize();
|
||||||
|
void setMinSize(const Vec2F& size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void process(const EventHandler& events) {}
|
virtual void process(const EventHandler& events) {}
|
||||||
virtual void draw(Canvas& canvas) { canvas.rect(mArea.getCurrentRect(), RGBA(1.f), 10); }
|
virtual void draw(Canvas& canvas) {}
|
||||||
virtual void drawOverlay(Canvas& canvas) {}
|
virtual void drawOverlay(Canvas& canvas) {}
|
||||||
|
|
||||||
virtual void mouseEnter();
|
virtual void mouseEnter();
|
||||||
virtual void mouseLeave();
|
virtual void mouseLeave();
|
||||||
|
|
||||||
// size policies
|
// size policies
|
||||||
virtual void adjustRect();
|
virtual void pickRect();
|
||||||
|
virtual void clampRect();
|
||||||
virtual void adjustChildrenRect();
|
virtual void adjustChildrenRect();
|
||||||
|
|
||||||
|
// resizing
|
||||||
|
RangeF pickRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical);
|
||||||
|
RangeF clampRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical);
|
||||||
|
RectF getChildrenEnclosure();
|
||||||
|
RectF getParentEnclosure();
|
||||||
|
void adjustLayout(bool vertical);
|
||||||
|
halnf changeChildSize(Widget*, halnf diff, bool vertical);
|
||||||
|
|
||||||
[[nodiscard]] virtual bool processesEvents() const;
|
[[nodiscard]] virtual bool processesEvents() const;
|
||||||
[[nodiscard]] virtual bool propagateEventsToChildren() const;
|
[[nodiscard]] virtual bool propagateEventsToChildren() const;
|
||||||
|
|
||||||
|
|
@ -53,7 +82,11 @@ namespace tp {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] RectF getArea() const;
|
[[nodiscard]] RectF getArea() const;
|
||||||
|
[[nodiscard]] RectF getAreaT() const;
|
||||||
|
|
||||||
[[nodiscard]] RectF getRelativeArea() const;
|
[[nodiscard]] RectF getRelativeArea() const;
|
||||||
|
[[nodiscard]] RectF getRelativeAreaT() const;
|
||||||
|
|
||||||
void setArea(const RectF& area);
|
void setArea(const RectF& area);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -65,6 +98,12 @@ namespace tp {
|
||||||
// relative to the parent
|
// relative to the parent
|
||||||
SpringRect mArea;
|
SpringRect mArea;
|
||||||
|
|
||||||
|
// resizing
|
||||||
|
LayoutPolicy mLayoutPolicy = LayoutPolicy::Passive;
|
||||||
|
Vec2<SizePolicy> mSizePolicy = { SizePolicy::Passive, SizePolicy::Passive };
|
||||||
|
Vec2F mMinSize = { 50, 50 };
|
||||||
|
Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 };
|
||||||
|
|
||||||
bool mInFocus = false;
|
bool mInFocus = false;
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue