Juce::Grid::Item accept Grid/Rectangle as input for nesting grids

Hello everyone,

I’ve started to play with the Grid class recently, and I discovered a possible feature that would be great to have to make the class more flexible and enable building nested Grids. If some approach already exist I would be happy to learn it.

So basically for now, the only way you can build a nested grid is to create an empty component, pass it as an item to the grid, and then take the bounds of that component to performLayout of your inner grid. Since in my opinion this is an overkill, it would be great to be able to pass a Rectangle to a grid item, or even better, another grid.

Please let me know if you find that this could be helpful or if there are already any alternative approaches. Thanks

Edit: I just discovered another possible approach by adding an item with no component associated, and then getting the item currentBounds from the grid item array, although this method could probably be simplified by adding the above requested feature to the class.

Cool idea. I made some similar request for FlexBox.

2 Likes

Nice! I am currently working on my own implementation, it could probably be much better if I instead hacked the Juce Module, but I prefered to keep it separate, here it is in case anyone is interested.

Grid implementation to facilitate nested grids, and rectangles as item:

  ==============================================================================

    BetterGrid.h
    Created: 14 Jun 2023 4:00:51pm
    Author:  Gustavo Castelo

  ==============================================================================
*/


#pragma once

#include <JuceHeader.h>

/*This classes facilitate creating nested Grids, and provide more flexibility to juce::Grid*/

enum class itemType { Component, Grid, Rectangle };

class BetterGrid;
class BetterGridItem;

class BetterGridItem : public juce::GridItem{
public:
    BetterGridItem() : type(itemType::Component) {}

    BetterGridItem(Component* c) : type(itemType::Component) {
        this->associatedComponent = c;
    }
    BetterGridItem(Component& c) : type(itemType::Component) {
        this->associatedComponent = &c;
    }

    BetterGridItem(BetterGrid* g) : type(itemType::Grid), grid(g) {}
    BetterGridItem(BetterGrid& g) : type(itemType::Grid), grid(&g) {}

    BetterGridItem(Rectangle<int>* r) : type(itemType::Rectangle), rectangle(r) {}
    BetterGridItem(Rectangle<int>& r) : type(itemType::Rectangle), rectangle(&r) {}


    itemType getType() const { return type; }

    Component* getComponent() const { assert(type == itemType::Component); return this->associatedComponent; }
    BetterGrid* getGrid() const { assert(type == itemType::Grid); return grid; }
    Rectangle<int>* getRectangle() const { assert(type == itemType::Rectangle); return rectangle; }

private:
    itemType type;

    union {
        BetterGrid* grid;
        Rectangle<int>* rectangle;
    };
};



class BetterGrid {

public:
    BetterGrid() = default;

    template <typename... Args>

    void addItem(Args... args) {
        addItemImpl(args...);
    }

    void performLayout(Rectangle<int> targetArea) {

        grid.performLayout(targetArea);

        //Layout rectangles
        for (auto item : rectangleList) {
            *item.first = grid.items[item.second].currentBounds.toNearestInt();
        }

        //Layout inner grids
        for (auto item : gridList) {
            item.first->performLayout(grid.items[item.second].currentBounds.toNearestInt());
        }
    }

    juce::Grid& getGrid() { return grid; }
private:


    void addItemImpl() {}

    template <typename... Args>
    void addItemImpl(const BetterGridItem& item, Args... args) {
        grid.items.add(item);
        if (item.getType() == itemType::Grid) {
            gridList.add(std::make_pair(item.getGrid(), grid.items.size()-1));
        }
        else if (item.getType() == itemType::Grid) {
            rectangleList.add(std::make_pair(item.getRectangle(), grid.items.size()-1));
        }
        addItemImpl(args...);

    }

    juce::Grid grid;
    Array<std::pair<Rectangle<int>*, int>> rectangleList;
    Array<std::pair<BetterGrid*, int>> gridList;
};
1 Like