Program Listing for File layout.h

Return to documentation for file (nanogui/layout.h)

/*
    NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
    The widget drawing code is based on the NanoVG demo application
    by Mikko Mononen.

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE.txt file.
*/
#pragma once

#include <nanogui/object.h>
#include <cstdio>
#include <unordered_map>

NAMESPACE_BEGIN(nanogui)

enum class Alignment : uint8_t {
    Minimum = 0,
    Middle,
    Maximum,
    Fill
};

enum class Orientation {
    Horizontal = 0,
    Vertical
};

class NANOGUI_EXPORT Layout : public Object {
public:
    virtual void performLayout(NVGcontext *ctx, Widget *widget) const = 0;

    virtual Vector2i preferredSize(NVGcontext *ctx, const Widget *widget) const = 0;

protected:
    virtual ~Layout() { }
};

class NANOGUI_EXPORT BoxLayout : public Layout {
public:
    BoxLayout(Orientation orientation, Alignment alignment = Alignment::Middle,
              int margin = 0, int spacing = 0);

    Orientation orientation() const { return mOrientation; }

    void setOrientation(Orientation orientation) { mOrientation = orientation; }

    Alignment alignment() const { return mAlignment; }

    void setAlignment(Alignment alignment) { mAlignment = alignment; }

    int margin() const { return mMargin; }

    void setMargin(int margin) { mMargin = margin; }

    int spacing() const { return mSpacing; }

    void setSpacing(int spacing) { mSpacing = spacing; }

    /* Implementation of the layout interface */
    virtual Vector2i preferredSize(NVGcontext *ctx, const Widget *widget) const override;

    virtual void performLayout(NVGcontext *ctx, Widget *widget) const override;

protected:
    Orientation mOrientation;

    Alignment mAlignment;

    int mMargin;

    int mSpacing;
};

class NANOGUI_EXPORT GroupLayout : public Layout {
public:
    GroupLayout(int margin = 15, int spacing = 6, int groupSpacing = 14,
                int groupIndent = 20)
        : mMargin(margin), mSpacing(spacing), mGroupSpacing(groupSpacing),
          mGroupIndent(groupIndent) {}

    int margin() const { return mMargin; }

    void setMargin(int margin) { mMargin = margin; }

    int spacing() const { return mSpacing; }

    void setSpacing(int spacing) { mSpacing = spacing; }

    int groupIndent() const { return mGroupIndent; }

    void setGroupIndent(int groupIndent) { mGroupIndent = groupIndent; }

    int groupSpacing() const { return mGroupSpacing; }

    void setGroupSpacing(int groupSpacing) { mGroupSpacing = groupSpacing; }

    /* Implementation of the layout interface */
    virtual Vector2i preferredSize(NVGcontext *ctx, const Widget *widget) const override;

    virtual void performLayout(NVGcontext *ctx, Widget *widget) const override;

protected:
    int mMargin;

    int mSpacing;

    int mGroupSpacing;

    int mGroupIndent;
};

class NANOGUI_EXPORT GridLayout : public Layout {
public:
    GridLayout(Orientation orientation = Orientation::Horizontal, int resolution = 2,
               Alignment alignment = Alignment::Middle,
               int margin = 0, int spacing = 0)
        : mOrientation(orientation), mResolution(resolution), mMargin(margin) {
        mDefaultAlignment[0] = mDefaultAlignment[1] = alignment;
        mSpacing = Vector2i::Constant(spacing);
    }

    Orientation orientation() const { return mOrientation; }

    void setOrientation(Orientation orientation) {
        mOrientation = orientation;
    }

    int resolution() const { return mResolution; }

    void setResolution(int resolution) { mResolution = resolution; }

    int spacing(int axis) const { return mSpacing[axis]; }

    void setSpacing(int axis, int spacing) { mSpacing[axis] = spacing; }

    void setSpacing(int spacing) { mSpacing[0] = mSpacing[1] = spacing; }

    int margin() const { return mMargin; }

    void setMargin(int margin) { mMargin = margin; }

    Alignment alignment(int axis, int item) const {
        if (item < (int) mAlignment[axis].size())
            return mAlignment[axis][item];
        else
            return mDefaultAlignment[axis];
    }

    void setColAlignment(Alignment value) { mDefaultAlignment[0] = value; }

    void setRowAlignment(Alignment value) { mDefaultAlignment[1] = value; }

    void setColAlignment(const std::vector<Alignment> &value) { mAlignment[0] = value; }

    void setRowAlignment(const std::vector<Alignment> &value) { mAlignment[1] = value; }

    /* Implementation of the layout interface */
    virtual Vector2i preferredSize(NVGcontext *ctx, const Widget *widget) const override;

    virtual void performLayout(NVGcontext *ctx, Widget *widget) const override;

protected:
    void computeLayout(NVGcontext *ctx, const Widget *widget,
                       std::vector<int> *grid) const;

protected:
    Orientation mOrientation;

    Alignment mDefaultAlignment[2];

    std::vector<Alignment> mAlignment[2];

    int mResolution;

    Vector2i mSpacing;

    int mMargin;
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class NANOGUI_EXPORT AdvancedGridLayout : public Layout {
public:
    struct Anchor {
        uint8_t pos[2];
        uint8_t size[2];
        Alignment align[2];

        Anchor() { }

        Anchor(int x, int y, Alignment horiz = Alignment::Fill,
              Alignment vert = Alignment::Fill) {
            pos[0] = (uint8_t) x; pos[1] = (uint8_t) y;
            size[0] = size[1] = 1;
            align[0] = horiz; align[1] = vert;
        }

        Anchor(int x, int y, int w, int h,
              Alignment horiz = Alignment::Fill,
              Alignment vert = Alignment::Fill) {
            pos[0] = (uint8_t) x; pos[1] = (uint8_t) y;
            size[0] = (uint8_t) w; size[1] = (uint8_t) h;
            align[0] = horiz; align[1] = vert;
        }

        operator std::string() const {
            char buf[50];
            std::snprintf(buf, 50, "Format[pos=(%i, %i), size=(%i, %i), align=(%i, %i)]",
                pos[0], pos[1], size[0], size[1], (int) align[0], (int) align[1]);
            return buf;
        }
    };

    AdvancedGridLayout(const std::vector<int> &cols = {}, const std::vector<int> &rows = {}, int margin = 0);

    int margin() const { return mMargin; }

    void setMargin(int margin) { mMargin = margin; }

    int colCount() const { return (int) mCols.size(); }

    int rowCount() const { return (int) mRows.size(); }

    void appendRow(int size, float stretch = 0.f) { mRows.push_back(size); mRowStretch.push_back(stretch); };

    void appendCol(int size, float stretch = 0.f) { mCols.push_back(size); mColStretch.push_back(stretch); };

    void setRowStretch(int index, float stretch) { mRowStretch.at(index) = stretch; }

    void setColStretch(int index, float stretch) { mColStretch.at(index) = stretch; }

    void setAnchor(const Widget *widget, const Anchor &anchor) { mAnchor[widget] = anchor; }

    Anchor anchor(const Widget *widget) const {
        auto it = mAnchor.find(widget);
        if (it == mAnchor.end())
            throw std::runtime_error("Widget was not registered with the grid layout!");
        return it->second;
    }

    /* Implementation of the layout interface */
    virtual Vector2i preferredSize(NVGcontext *ctx, const Widget *widget) const override;

    virtual void performLayout(NVGcontext *ctx, Widget *widget) const override;

protected:
    void computeLayout(NVGcontext *ctx, const Widget *widget,
                       std::vector<int> *grid) const;

protected:
    std::vector<int> mCols;

    std::vector<int> mRows;

    std::vector<float> mColStretch;

    std::vector<float> mRowStretch;

    std::unordered_map<const Widget *, Anchor> mAnchor;

    int mMargin;
};

NAMESPACE_END(nanogui)