diff --git a/Containers/tests/AVLTreeProfiling.cpp b/Containers/tests/AVLTreeProfiling.cpp index 66532ce..54ee3f5 100644 --- a/Containers/tests/AVLTreeProfiling.cpp +++ b/Containers/tests/AVLTreeProfiling.cpp @@ -17,7 +17,7 @@ Item buff[size]; int main() { AvlTree, alni> tree; - for (auto i : Range(size)) { + for (auto i : IterRange(size)) { buff[i].data = i; } diff --git a/Containers/tests/BufferTest.cpp b/Containers/tests/BufferTest.cpp index ae631bd..e696b28 100644 --- a/Containers/tests/BufferTest.cpp +++ b/Containers/tests/BufferTest.cpp @@ -9,7 +9,7 @@ SUITE(Buffer) { TEST(Simple1) { Buffer buff; CHECK(buff.size() == 0); - for (auto i : Range(size * 10)) { + for (auto i : IterRange(size * 10)) { buff.append(TestClass(i)); } CHECK(buff.size() == size * 10); @@ -21,7 +21,7 @@ SUITE(Buffer) { TEST(Simple2) { Buffer buff(size); CHECK(buff.size() == size); - for (auto i : Range(size * 10)) + for (auto i : IterRange(size * 10)) buff.append(TestClass(i)); CHECK(buff.size() == size + size * 10); while (buff.size()) diff --git a/Containers/tests/IntervalTreeTests.cpp b/Containers/tests/IntervalTreeTests.cpp index fccd4f8..2acd700 100644 --- a/Containers/tests/IntervalTreeTests.cpp +++ b/Containers/tests/IntervalTreeTests.cpp @@ -99,7 +99,7 @@ SUITE(IntervalTree) { }; // initialize - for (auto i : Range(NUM_TEST_INTERVALS)) { + for (auto i : IterRange(NUM_TEST_INTERVALS)) { auto interval = Interval(); interval.random(SPAN); @@ -114,7 +114,7 @@ SUITE(IntervalTree) { test(); // remove some - for (auto i : Range(NUM_TEST_INTERVALS / 2)) { + for (auto i : IterRange(NUM_TEST_INTERVALS / 2)) { auto idx = ualni(randomFloat() * (alnf) pool.size()); pool[idx].ignore = true; intervalTree.remove({ pool[idx].start, pool[idx].end }); @@ -139,18 +139,18 @@ SUITE(IntervalTree) { Buffer testIntervals; auto WOBBLE = SPAN * 0; - for (auto i : Range(NUM_TEST_INTERVALS)) { + for (auto i : IterRange(NUM_TEST_INTERVALS)) { auto interval = Interval(); interval.randomSized(SPAN, SCALE, WOBBLE); intervalTree.insert({ interval.start, interval.end }, i); // WOBBLE -= 1.f; } - for (auto i : Range(0)) + for (auto i : IterRange(0)) intervalTree.insert({ (halnf) i * 0.01f, SPAN }, 0); WOBBLE = 0; - for (auto i : Range(NUM_CHECKS)) { + for (auto i : IterRange(NUM_CHECKS)) { auto interval = Interval(); interval.randomSized(SPAN, SCALE, WOBBLE); testIntervals.append(interval); @@ -200,7 +200,7 @@ SUITE(IntervalTree) { }; Buffer stats; - for (auto i : Range(2, 5)) { + for (auto i : IterRange(2, 5)) { Stat stat = test(pow(10, i), 100); stats.append(stat); } diff --git a/Containers/tests/MapTest.cpp b/Containers/tests/MapTest.cpp index 3fb8ef6..feca1f7 100644 --- a/Containers/tests/MapTest.cpp +++ b/Containers/tests/MapTest.cpp @@ -8,26 +8,26 @@ SUITE(HashTable) { TEST(SimpleReference) { tp::Map map; - for (auto i : Range(1000, 100000)) { + for (auto i : IterRange(1000, 100000)) { map.put(i, TestClass(i)); } - for (auto i : Range(1000, 100000)) { + for (auto i : IterRange(1000, 100000)) { CHECK(map.presents(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)); } - for (auto i : Range(1000, 2000)) { + for (auto i : IterRange(1000, 2000)) { CHECK(map.presents(i)); map.remove(i); CHECK(!map.presents(i)); } - for (auto i : Range(2000, 100000)) { + for (auto i : IterRange(2000, 100000)) { CHECK(map.presents(i)); CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i); } @@ -42,29 +42,29 @@ SUITE(HashTable) { TEST(SimplePointer) { tp::Map map; - for (auto i : Range(1000)) { + for (auto i : IterRange(1000)) { map.put(i, new TestClass(i)); } - for (auto i : Range(1000)) { + for (auto i : IterRange(1000)) { CHECK(map.presents(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); map.put(i, new TestClass(i)); delete del; } - for (auto i : Range(900, 1000)) { + for (auto i : IterRange(900, 1000)) { CHECK(map.presents(i)); delete map.get(i); map.remove(i); CHECK(!map.presents(i)); } - for (auto i : Range(900)) { + for (auto i : IterRange(900)) { CHECK(map.presents(i)); CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i); } @@ -80,7 +80,7 @@ SUITE(HashTable) { TEST(Copy) { tp::Map map; - for (auto i : Range(10)) { + for (auto i : IterRange(10)) { map.put(i, TestClass(i)); } @@ -95,7 +95,7 @@ SUITE(HashTable) { TEST(SaveLoad) { tp::Map map; - for (auto i : Range(10)) { + for (auto i : IterRange(10)) { map.put(i, TestClass(i)); } @@ -114,7 +114,7 @@ SUITE(HashTable) { CHECK(map.size() == 10); - for (auto i : Range(10)) { + for (auto i : IterRange(10)) { CHECK(map.presents(i)); CHECK_EQUAL(map.get(i).getVal(), i); } diff --git a/Containers/tests/TreeTest.cpp b/Containers/tests/TreeTest.cpp index 8d726ad..e53f06c 100644 --- a/Containers/tests/TreeTest.cpp +++ b/Containers/tests/TreeTest.cpp @@ -37,7 +37,7 @@ SUITE(AvlTree) { Item buff[size]; - for (auto i : Range(size)) { + for (auto i : IterRange(size)) { buff[i].data.setVal(i); } diff --git a/DataAnalysis/applications/NumRecApp.cpp b/DataAnalysis/applications/NumRecApp.cpp index 421612a..aa98ac9 100644 --- a/DataAnalysis/applications/NumRecApp.cpp +++ b/DataAnalysis/applications/NumRecApp.cpp @@ -18,7 +18,7 @@ void loadImage(Buffer& output, const char* name) { output.reserve(x * y); - for (auto i : Range(output.size())) { + for (auto i : IterRange(output.size())) { output[i] = loadedImage[i * 4] / 255.f; } diff --git a/DataAnalysis/applications/NumRecTraining.cpp b/DataAnalysis/applications/NumRecTraining.cpp index 69cd71c..e6c808e 100644 --- a/DataAnalysis/applications/NumRecTraining.cpp +++ b/DataAnalysis/applications/NumRecTraining.cpp @@ -52,7 +52,7 @@ bool loadDataset(Dataset& out, const std::string& location) { out.labels.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]; image.reserve(sizeX * sizeY); dataset.readBytes((LocalConnection::Byte*) image.getBuff(), sizeX * sizeY); @@ -89,7 +89,7 @@ struct NumberRec { } 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 label = dataset.labels[i]; @@ -97,13 +97,13 @@ struct NumberRec { testcase.output.reserve(10); - for (auto dig : Range(10)) { + for (auto dig : IterRange(10)) { testcase.output[dig] = label == dig ? 1 : 0; } 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; } } @@ -137,7 +137,7 @@ struct NumberRec { static halni getMaxIdx(const Buffer& in) { halni out = 0; - for (auto i : Range(in.size())) { + for (auto i : IterRange(in.size())) { if (in[i] > in[out]) { out = i; } @@ -165,15 +165,15 @@ struct NumberRec { void displayImage(ualni idx) { auto& testcase = mTestcases[idx]; printf("Image : %i\n", int(getMaxIdx(testcase.output))); - for (auto i : Range(28)) { - for (auto j : Range(28)) { + for (auto i : IterRange(28)) { + for (auto j : IterRange(28)) { printf("%c", char(testcase.input[j * 28 + i] * 255)); } printf("\n"); } } - halnf test(const Range& range) { + halnf test(const IterRange& range) { halnf avgCost = 0; for (auto i : range) { avgCost += eval(i); @@ -182,7 +182,7 @@ struct NumberRec { return avgCost; } - void trainStep(const Range& range) { + void trainStep(const IterRange& range) { nn.clearGrad(); for (auto i : range) { nn.evaluate(mTestcases[i].input, output); @@ -210,18 +210,19 @@ int main() { NumberRec app; auto numBatches = 10; - auto trainRange = Range(0, 50000); - auto testRange = Range(50000, 70000); + auto trainRange = IterRange(0, 50000); + auto testRange = IterRange(50000, 70000); auto batchSize = trainRange.idxDiff() / numBatches; - for (auto epoch : Range(1)) { + for (auto epoch : IterRange(1)) { 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()); - 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); diff --git a/DataAnalysis/private/FCNN.cpp b/DataAnalysis/private/FCNN.cpp index be5b322..94b429a 100644 --- a/DataAnalysis/private/FCNN.cpp +++ b/DataAnalysis/private/FCNN.cpp @@ -32,7 +32,7 @@ void FCNN::initializeRandom(const Buffer& description) { mLayers.reserve(description.size()); - for (auto i : Range(0, (halni) description.size())) { + for (auto i : IterRange(0, (halni) description.size())) { mLayers[i].neurons.reserve(description[i]); if (i == 0) { continue; @@ -50,17 +50,17 @@ void FCNN::initializeRandom(const Buffer& description) { void FCNN::evaluate(const Buffer& input, Buffer& output) { 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]; } - for (auto layerIdx : Range(1, (halni) mLayers.size())) { + for (auto layerIdx : IterRange(1, (halni) mLayers.size())) { auto& layer = mLayers[layerIdx]; auto& layerPrev = mLayers[layerIdx - 1]; for (auto neuron : layer.neurons) { 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->bias.val; @@ -69,26 +69,26 @@ void FCNN::evaluate(const Buffer& input, Buffer& output) { } } - for (auto idx : Range(output.size())) { + for (auto idx : IterRange(output.size())) { output[idx] = mLayers.last().neurons[idx].activationValue; } } halnf FCNN::calcCost(const Buffer& output) { 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); } return out; } void FCNN::clearGrad() { - for (auto layIdx : Range(1, (halni) mLayers.size())) { + for (auto layIdx : IterRange(1, (halni) mLayers.size())) { auto& layer = mLayers[layIdx]; for (auto neuron : layer.neurons) { neuron->bias.grad = 0; - for (auto weightIdx : Range(neuron->weights.size())) { + for (auto weightIdx : IterRange(neuron->weights.size())) { neuron->weights[weightIdx].grad = 0; } } @@ -102,7 +102,7 @@ void FCNN::calcGrad(const Buffer& output) { auto& lastLayer = mLayers.last(); // 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]; neuron.cache = 2 * (neuron.activationValue - output[neuronIdx]); } @@ -113,7 +113,7 @@ void FCNN::calcGrad(const Buffer& output) { auto& currentLayer = mLayers[layerIdx]; auto& inputLayer = mLayers[layerIdx - 1]; - for (auto currentNeuronIdx : Range(currentLayer.neurons.size())) { + for (auto currentNeuronIdx : IterRange(currentLayer.neurons.size())) { auto& currentNeuron = currentLayer.neurons[currentNeuronIdx]; // calculate cache value (chaining) @@ -131,7 +131,7 @@ void FCNN::calcGrad(const Buffer& output) { currentNeuron.bias.grad += currentNeuron.cache; // 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; } } @@ -142,12 +142,12 @@ void FCNN::calcGrad(const Buffer& output) { void FCNN::applyGrad(halnf step) { - for (auto layIdx : Range(1, (halni) mLayers.size())) { + for (auto layIdx : IterRange(1, (halni) mLayers.size())) { auto& layer = mLayers[layIdx]; for (auto neuron : layer.neurons) { 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; } } diff --git a/DataAnalysis/tests/Tests.cpp b/DataAnalysis/tests/Tests.cpp index af7b914..f0886e9 100644 --- a/DataAnalysis/tests/Tests.cpp +++ b/DataAnalysis/tests/Tests.cpp @@ -31,11 +31,11 @@ SUITE(FCNN) { Buffer outputExpected(layers.last()); Buffer output(layers.last()); - for (auto inputVal : Range(layers.first())) { + for (auto inputVal : IterRange(layers.first())) { input[inputVal] = inputLayer[inputVal]; } - for (auto outIdx : Range(layers.last())) { + for (auto outIdx : IterRange(layers.last())) { outputExpected[outIdx] = outputLayer[outIdx]; } @@ -44,7 +44,7 @@ SUITE(FCNN) { halnf cost = 0; - for (auto i : Range(150)) { + for (auto i : IterRange(150)) { nn.evaluate(input, output); diff --git a/Math/private/Topology.cpp b/Math/private/Topology.cpp index 90583c2..96af391 100644 --- a/Math/private/Topology.cpp +++ b/Math/private/Topology.cpp @@ -88,18 +88,18 @@ void TopologyCache::updateCache() { } 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->Origin; } 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]); } 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].mP2 = Source->Indexes[idx].y; TrigCaches[idx].mP3 = Source->Indexes[idx].z; diff --git a/Math/public/Range.hpp b/Math/public/Range.hpp new file mode 100644 index 0000000..208d23b --- /dev/null +++ b/Math/public/Range.hpp @@ -0,0 +1,39 @@ + +#pragma once + +#include "Common.hpp" + +namespace tp { + template + 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; +} \ No newline at end of file diff --git a/Math/public/Rect.hpp b/Math/public/Rect.hpp index 60efbe5..55ca00e 100644 --- a/Math/public/Rect.hpp +++ b/Math/public/Rect.hpp @@ -2,6 +2,7 @@ #pragma once #include "Vec.hpp" +#include "Range.hpp" #include "Intersections.hpp" @@ -35,6 +36,11 @@ namespace tp { this->size = size; } + Rect(const Range& rx, const Range& ry) { + this->pos = { rx.start, ry.start }; + this->size = { rx.size(), ry.size() }; + } + Rect(Type aPosX, Type posy, Type aSizeX, Type aSizeY) { pos.assign(aPosX, posy); size.assign(aSizeX, aSizeY); @@ -64,7 +70,7 @@ namespace tp { return *this; } - bool operator==(Rect& rect) const { return (pos == rect.pos && size == rect.size); } + bool operator==(const Rect& rect) const { return (pos == rect.pos && size == rect.size); } bool isEnclosedIn(const Rect& rect, bool aParent = false) const { if (aParent) { @@ -102,6 +108,11 @@ namespace tp { void invertY(Type scr_y) { pos.y = scr_y - pos.y - size.y; } + Rect& move(Vec2 delta) { + move(delta.x, delta.y); + return *this; + } + void move(Type dx, Type dy) { pos.x += dx; pos.y += dy; @@ -119,6 +130,9 @@ namespace tp { return *this; } + Range getRangeX() const { return { x, x + z }; } + Range getRangeY() const { return { y, y + w }; } + // pos Vec2 p1() const { return pos; } diff --git a/Math/public/Vec.hpp b/Math/public/Vec.hpp index f331b42..0441fa8 100644 --- a/Math/public/Vec.hpp +++ b/Math/public/Vec.hpp @@ -226,8 +226,8 @@ namespace tp { Type y; Vec() : - x(0), - y(0) {} + x{}, + y{} {} // Initialization template diff --git a/Modules/public/Utils.hpp b/Modules/public/Utils.hpp index eaa1c37..1035d50 100644 --- a/Modules/public/Utils.hpp +++ b/Modules/public/Utils.hpp @@ -46,7 +46,7 @@ namespace tp { }; template - class Range { + class IterRange { public: class Iterator { public: @@ -71,13 +71,13 @@ namespace tp { tType mBegin{}; tType mEnd{}; - Range() = default; + IterRange() = default; - explicit Range(tType pEndIndex) : + explicit IterRange(tType pEndIndex) : mBegin(0), mEnd(pEndIndex) {} - Range(tType pStartIndex, tType pEndIndex) : + IterRange(tType pStartIndex, tType pEndIndex) : mBegin(pStartIndex), mEnd(pEndIndex) {} diff --git a/Objects/private/compiler/Functions.cpp b/Objects/private/compiler/Functions.cpp index cce4ee8..3ae4407 100644 --- a/Objects/private/compiler/Functions.cpp +++ b/Objects/private/compiler/Functions.cpp @@ -410,14 +410,14 @@ alni instSize(const Instruction& inst) { } 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)); idx++; } } 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]); idx++; } diff --git a/RayTracer/private/RayTracer.cpp b/RayTracer/private/RayTracer.cpp index 994e5e8..e8355e7 100644 --- a/RayTracer/private/RayTracer.cpp +++ b/RayTracer/private/RayTracer.cpp @@ -79,7 +79,7 @@ void RayTracer::cycle(const RayCastData& castData, LightData& out, uhalni depth) const auto delta1 = castData.trig->mEdgeP1P2.unitV(); const auto delta2 = normal.cross(delta1); - for (auto idx : Range(mSettings.spray)) { + for (auto idx : IterRange(mSettings.spray)) { RayCastData materialCastData; LightData lightData; diff --git a/Sketch3D/private/Sketch3D.cpp b/Sketch3D/private/Sketch3D.cpp index 7c58868..a8b32c8 100644 --- a/Sketch3D/private/Sketch3D.cpp +++ b/Sketch3D/private/Sketch3D.cpp @@ -35,16 +35,16 @@ const RGBA& Stroke::getColor() const { return mColor; } void Stroke::updateGpuBuffers() { mGPUHandles.sendDataToGPU(&mPoints); } void Stroke::denoisePos(halni passes) { - for (auto pass : Range(passes)) { - for (auto pi : Range(mPoints.size() - 2)) { + for (auto pass : IterRange(passes)) { + for (auto pi : IterRange(mPoints.size() - 2)) { mPoints[pi + 1].pos = (mPoints[pi + 1].pos + mPoints[pi].pos + mPoints[pi + 2].pos) / 3.f; } } } void Stroke::denoiseThickness(halni passes) { - for (auto pass : Range(passes)) { - for (auto pi : Range(mPoints.size() - 2)) { + for (auto pass : IterRange(passes)) { + for (auto pi : IterRange(mPoints.size() - 2)) { mPoints[pi + 1].thickness = (mPoints[pi].thickness + mPoints[pi + 2].thickness) / 2.f; } } @@ -57,7 +57,7 @@ void Stroke::compress(halnf factor) { List passed_poits; - for (auto idx : Range(mPoints.size())) { + for (auto idx : IterRange(mPoints.size())) { passed_poits.pushBack(mPoints[idx]); } @@ -100,14 +100,14 @@ void Stroke::subdiv(halnf precision, const Camera* cam, halni passes) { } List new_points; - for (auto idx : Range(mPoints.size())) { + for (auto idx : IterRange(mPoints.size())) { new_points.pushBack(mPoints[idx]); } auto viewmat = cam->calculateViewMatrix(); auto projmat = cam->calculateProjectionMatrix(); - for (auto i : Range(passes)) { + for (auto i : IterRange(passes)) { auto n_points = new_points.length(); diff --git a/WidgetsNew/examples/Example.cpp b/WidgetsNew/examples/Example.cpp index 273a7df..6f8207a 100644 --- a/WidgetsNew/examples/Example.cpp +++ b/WidgetsNew/examples/Example.cpp @@ -11,7 +11,7 @@ using namespace tp; class WidgetApplication : public Application { public: WidgetApplication() { - setup1(); + setup2(); } void setup1() { @@ -20,8 +20,8 @@ public: mDockLayout.addChild(&mFloatingMenu); mDockLayout.addChild(&mFloatingMenu2); - mDockLayout.setCenterWidget(&mButton3); - mDockLayout.dockWidget(&mButton4, DockLayoutWidget::RIGHT); + mDockLayout.setCenterWidget(&mButton4); + mDockLayout.dockWidget(&mButton3, DockLayoutWidget::RIGHT); mFloatingMenu.addToMenu(&mButton); mFloatingMenu2.addToMenu(&mButton2); @@ -29,6 +29,11 @@ public: mButton.setAction([this]() { mButton2.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); // mWidgetFloating.addChild(&mButton); @@ -48,7 +53,24 @@ public: } 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 { @@ -67,6 +89,8 @@ public: } private: + Widget mWidget; + ButtonWidget mButton; ButtonWidget mButton2; ButtonWidget mButton3; @@ -78,7 +102,7 @@ private: LabelWidget mLabel; FloatingWidget mWidgetFloating; AnimationTestWidget mAnimationTestWidget; - DesktopLayout mLayoutWidget; + DesktopLayout mDesktopLayout; DockLayoutWidget mDockLayout; diff --git a/WidgetsNew/private/DockLayoutWidget.cpp b/WidgetsNew/private/DockLayoutWidget.cpp index 5c717a6..6767483 100644 --- a/WidgetsNew/private/DockLayoutWidget.cpp +++ b/WidgetsNew/private/DockLayoutWidget.cpp @@ -1,4 +1,5 @@ #include "DockLayoutWidget.hpp" +#include "FloatingWidget.hpp" using namespace tp; @@ -11,9 +12,33 @@ DockLayoutWidget::DockLayoutWidget() { void DockLayoutWidget::process(const EventHandler& events) { // calculateHeaderAreas(); - // handlePreview(events); - handleResizeEvents(events); + Widget* floater = nullptr; + for (auto child : mChildren) { + if (auto iter = dynamic_cast(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(); calculateResizeHandles(); updateChildSideWidgets(); @@ -40,7 +65,7 @@ void DockLayoutWidget::drawOverlay(Canvas& canvas) { canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0); } - if (mPreview) { + if (mPreviewWidget) { if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding); for (auto& sideWidget : mSideWidgets) { @@ -64,10 +89,16 @@ void DockLayoutWidget::setCenterWidget(Widget* widget) { } void DockLayoutWidget::dockWidget(Widget* widget, Side side) { - DEBUG_ASSERT(!sideExists(side)) + if (sideExists(side) || side == Side::NONE) return; addChild(widget); + widget->bringToBack(); + if (mCenterWidget) mCenterWidget->bringToBack(); + for (auto& order : mSideWidgets) { + if (order.widget) order.widget->bringToBack(); + } + auto& sideWidget = mSideWidgets[side]; sideWidget.widget = widget; @@ -79,10 +110,21 @@ void DockLayoutWidget::dockWidget(Widget* widget, Side side) { } sideWidget.hidden = false; + sideWidget.areaBeforeDocking = widget->getArea(); } -void DockLayoutWidget::undockWidget(Side side) { - DEBUG_ASSERT(sideExists(side)) +void DockLayoutWidget::undockWidget(Side side, bool restoreArea) { + 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; for (ualni i = 0; i < 3; i++) { @@ -275,7 +317,9 @@ bool DockLayoutWidget::isSideVisible(DockLayoutWidget::Side side) { 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 out = 0; @@ -286,11 +330,6 @@ ualni DockLayoutWidget::getVisibleSidesSize() { } void DockLayoutWidget::handlePreview(const EventHandler& events) { - if (!mPreview) { - mPreviewSide = NONE; - return; - } - const halnf factor = 0.3; const halnf handleFactor = 0.1; @@ -313,6 +352,7 @@ void DockLayoutWidget::handlePreview(const EventHandler& events) { mPreviewArea = {}; mPreviewSide = NONE; + for (auto& sideWidget : mSideWidgets) { 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; +} diff --git a/WidgetsNew/private/FloatingWidget.cpp b/WidgetsNew/private/FloatingWidget.cpp index c65ba27..4702fa7 100644 --- a/WidgetsNew/private/FloatingWidget.cpp +++ b/WidgetsNew/private/FloatingWidget.cpp @@ -28,16 +28,20 @@ void FloatingWidget::process(const EventHandler& events) { // triggerWidgetUpdate(); } -void FloatingWidget::adjustRect() { - auto area = getArea(); +void FloatingWidget::pickRect() { + if (mIsFloating) { + auto area = getArea(); - if (mIsResizing) { - area.size = mPointerCurrent + mHandleSize / 2.f; - } else if (mIsFloating) { - area.pos += mPointerCurrent - mPointerStart; + if (mIsResizing) { + area.size = mPointerCurrent + mHandleSize / 2.f; + } else if (mIsFloating) { + area.pos += mPointerCurrent - mPointerStart; + } + + setArea(area); + } else { + Widget::pickRect(); } - - setArea(area); } void FloatingWidget::draw(Canvas& canvas) { @@ -55,4 +59,8 @@ RectF FloatingWidget::resizeHandleRect() { bool FloatingWidget::propagateEventsToChildren() const { return !mIsFloating; +} + +bool FloatingWidget::isFloating() const { + return mIsFloating; } \ No newline at end of file diff --git a/WidgetsNew/private/RootWidget.cpp b/WidgetsNew/private/RootWidget.cpp index 4562c75..7630e1c 100644 --- a/WidgetsNew/private/RootWidget.cpp +++ b/WidgetsNew/private/RootWidget.cpp @@ -12,6 +12,12 @@ void RootWidget::setRootWidget(Widget* widget) { } 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; mRoot->setArea(screenArea); @@ -38,6 +44,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { // check triggered widgets for removal erase_if(mTriggeredWidgets, [this](auto widget) { + widget->updateAnimations(); if (mWidgetsToProcess.find(widget) == mWidgetsToProcess.end()) return false; auto end = !widget->needsNextFrame(); 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) { // draw from top to bottom @@ -60,8 +67,44 @@ void RootWidget::drawFrame(Canvas& canvas) { if (mDebug) { drawDebug(canvas, mRoot, { 0, 0 }, 0); + ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.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) { if (!iter) return; - iter->widget->adjustRect(); - iter->widget->adjustChildrenRect(); - for (auto child : iter->children) { adjustSizes(child); } + + iter->widget->pickRect(); + iter->widget->adjustChildrenRect(); + // iter->widget->pickRect(); } void RootWidget::processActiveTree(ActiveTreeNode* iter, EventHandler& events) { @@ -257,6 +301,8 @@ void RootWidget::processFocusItems(EventHandler& events) { events.setCursorOrigin(widgetGlobalPos[iter]); + widget->mLocalPoint = events.getPointer(); + if (!eventsProcessed && widget->processesEvents()) { events.setEnableKeyEvents(true); @@ -266,6 +312,7 @@ void RootWidget::processFocusItems(EventHandler& events) { events.setEnableKeyEvents(false); eventsProcessed = true; } else { + widget->updateAnimations(); widget->process(events); } diff --git a/WidgetsNew/private/SimpleWidgets.cpp b/WidgetsNew/private/SimpleWidgets.cpp index d957a31..07cc57c 100644 --- a/WidgetsNew/private/SimpleWidgets.cpp +++ b/WidgetsNew/private/SimpleWidgets.cpp @@ -37,7 +37,7 @@ void ButtonWidget::setColor(const RGBA& in) { } void ButtonWidget::process(const EventHandler& eventHandler) { - if (getArea().isInside(eventHandler.getPointer())) { + if (getRelativeArea().isInside(eventHandler.getPointer())) { if (eventHandler.isPressed(InputID::MOUSE1)) { mAction(); } diff --git a/WidgetsNew/private/Widget.cpp b/WidgetsNew/private/Widget.cpp index 8f0eccb..a565d10 100644 --- a/WidgetsNew/private/Widget.cpp +++ b/WidgetsNew/private/Widget.cpp @@ -1,5 +1,7 @@ #include "Widget.hpp" +#include + using namespace tp; WidgetManagerInterface* Widget::getRoot() { @@ -17,26 +19,33 @@ void Widget::triggerWidgetUpdate() { } Widget::Widget() { - mArea.setTargetRect({ 10, 10, 100, 40, }); + mArea.setTargetRect({ 100, 100, 10, 10, }); mArea.endAnimation(); } void Widget::setArea(const RectF& area) { - mArea.setTargetRect(area); + if (mArea.getTargetRect() == area) return; - if (!mArea.shouldEndTransition()) { - triggerWidgetUpdate(); - } + mArea.setTargetRect(area); + triggerWidgetUpdate(); } RectF Widget::getArea() const { return mArea.getCurrentRect(); } +RectF Widget::getAreaT() const { + return mArea.getTargetRect(); +} + RectF Widget::getRelativeArea() const { return { {}, mArea.getCurrentRect().size }; } +RectF Widget::getRelativeAreaT() const { + return { {}, mArea.getTargetRect().size }; +} + void Widget::endAnimations() { mArea.endAnimation(); } @@ -53,20 +62,11 @@ bool Widget::needsNextFrame() const { 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() { if (!mParent) return; auto& order = mParent->mDepthOrder; auto node = order.find(this); - DEBUG_ASSERT(node); + DEBUG_ASSERT(node) order.detach(node); order.pushFront(node); } @@ -75,18 +75,11 @@ void Widget::bringToBack() { if (!mParent) return; auto& order = mParent->mDepthOrder; auto node = order.find(this); - DEBUG_ASSERT(node); + DEBUG_ASSERT(node) order.detach(node); order.pushBack(node); } -void Widget::adjustChildrenRect() { - auto area = RectF({}, getArea().size); - for (auto widget : mChildren) { - widget->setArea(area); - } -} - void Widget::mouseEnter() { mInFocus = true; } @@ -100,6 +93,15 @@ bool Widget::propagateEventsToChildren() const { } 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); mDepthOrder.pushBack(child); @@ -108,3 +110,183 @@ void Widget::addChild(Widget* 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> 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(); +} diff --git a/WidgetsNew/public/DockLayoutWidget.hpp b/WidgetsNew/public/DockLayoutWidget.hpp index 2e6173d..77f3340 100644 --- a/WidgetsNew/public/DockLayoutWidget.hpp +++ b/WidgetsNew/public/DockLayoutWidget.hpp @@ -27,13 +27,15 @@ namespace tp { RectF previewHandleArea = {}; ResizeHandle resizeHandle; + + RectF areaBeforeDocking = {}; }; public: DockLayoutWidget(); public: - void adjustRect() override {} + void pickRect() override {} void adjustChildrenRect() override {} void process(const EventHandler& events) override; @@ -47,10 +49,11 @@ namespace tp { void setCenterWidget(Widget* widget); void dockWidget(Widget* widget, Side side); - void undockWidget(Side side); + void undockWidget(Side side, bool restoreArea = true); void toggleWidgetVisibility(Side side); private: + Side getSideFromWidget(Widget*); void calculateSideAreas(); void calculateResizeHandles(); void handleResizeEvents(const EventHandler& events); @@ -86,9 +89,9 @@ namespace tp { RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1); RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 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: - bool mPreview = false; + Widget* mPreviewWidget = nullptr; }; } \ No newline at end of file diff --git a/WidgetsNew/public/FloatingWidget.hpp b/WidgetsNew/public/FloatingWidget.hpp index a701244..6551610 100644 --- a/WidgetsNew/public/FloatingWidget.hpp +++ b/WidgetsNew/public/FloatingWidget.hpp @@ -12,7 +12,7 @@ namespace tp { void process(const EventHandler& events) override; - void adjustRect() override; + void pickRect() override; void draw(Canvas& canvas) override; @@ -20,6 +20,8 @@ namespace tp { [[nodiscard]] bool propagateEventsToChildren() const override; + [[nodiscard]] bool isFloating() const; + private: bool mIsFloating = false; bool mIsResizing = false; diff --git a/WidgetsNew/public/LayoutWidget.hpp b/WidgetsNew/public/LayoutWidget.hpp index 68d8f13..ac85986 100644 --- a/WidgetsNew/public/LayoutWidget.hpp +++ b/WidgetsNew/public/LayoutWidget.hpp @@ -11,7 +11,7 @@ namespace tp { // canvas.rect(getRelativeArea(), RGBA(0, 0, 0, 1)); } - void adjustRect() override { + void pickRect() override { // do nothing } diff --git a/WidgetsNew/public/RootWidget.hpp b/WidgetsNew/public/RootWidget.hpp index 6f9e55e..90a01c7 100644 --- a/WidgetsNew/public/RootWidget.hpp +++ b/WidgetsNew/public/RootWidget.hpp @@ -51,5 +51,7 @@ namespace tp { Widget* mInFocusWidget = nullptr; bool mDebug = true; + bool mDebugStopProcessing = false; + bool mDebugRedrawAlways = false; }; } \ No newline at end of file diff --git a/WidgetsNew/public/Widget.hpp b/WidgetsNew/public/Widget.hpp index 5c8507f..30b2c9e 100644 --- a/WidgetsNew/public/Widget.hpp +++ b/WidgetsNew/public/Widget.hpp @@ -13,6 +13,19 @@ namespace tp { class Widget { friend class RootWidget; + public: + enum class SizePolicy { + Passive, + Expand, + Contract, + }; + + enum class LayoutPolicy { + Passive, + Vertically, + Horizontally, + }; + public: Widget(); virtual ~Widget() = default; @@ -23,6 +36,7 @@ namespace tp { } void addChild(Widget* child); + void removeChild(Widget* child); WidgetManagerInterface* getRoot(); @@ -31,18 +45,33 @@ namespace tp { void bringToFront(); void bringToBack(); + void setSizePolicy(SizePolicy x, SizePolicy y); + void setLayoutPolicy(LayoutPolicy layoutPolicy); + + const Vec2F& getMinSize(); + void setMinSize(const Vec2F& size); + public: 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 mouseEnter(); virtual void mouseLeave(); // size policies - virtual void adjustRect(); + virtual void pickRect(); + virtual void clampRect(); 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 propagateEventsToChildren() const; @@ -53,7 +82,11 @@ namespace tp { public: [[nodiscard]] RectF getArea() const; + [[nodiscard]] RectF getAreaT() const; + [[nodiscard]] RectF getRelativeArea() const; + [[nodiscard]] RectF getRelativeAreaT() const; + void setArea(const RectF& area); protected: @@ -65,6 +98,12 @@ namespace tp { // relative to the parent SpringRect mArea; + // resizing + LayoutPolicy mLayoutPolicy = LayoutPolicy::Passive; + Vec2 mSizePolicy = { SizePolicy::Passive, SizePolicy::Passive }; + Vec2F mMinSize = { 50, 50 }; + Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 }; + bool mInFocus = false; // debug