Program Listing for File tabheader.h

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

/*
    nanogui/tabheader.h -- Widget used to control tabs.

    The tab header widget was contributed by Stefan Ivanov.

    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/widget.h>
#include <vector>
#include <string>
#include <functional>
#include <utility>
#include <iterator>

NAMESPACE_BEGIN(nanogui)


class NANOGUI_EXPORT TabHeader : public Widget {
public:
    TabHeader(Widget *parent, const std::string &font = "sans-bold");

    void setFont(const std::string& font) { mFont = font; }
    const std::string& font() const { return mFont; }
    bool overflowing() const { return mOverflowing; }

    void setCallback(const std::function<void(int)>& callback) { mCallback = callback; };
    const std::function<void(int)>& callback() const { return mCallback; }

    void setActiveTab(int tabIndex);
    int activeTab() const;
    bool isTabVisible(int index) const;
    int tabCount() const { return (int) mTabButtons.size();  }

    void addTab(const std::string& label);

    void addTab(int index, const std::string& label);

    int removeTab(const std::string& label);

    void removeTab(int index);

    const std::string& tabLabelAt(int index) const;

    int tabIndex(const std::string& label);

    void ensureTabVisible(int index);

    std::pair<Vector2i, Vector2i> visibleButtonArea() const;

    std::pair<Vector2i, Vector2i> activeButtonArea() const;

    virtual void performLayout(NVGcontext* ctx) override;
    virtual Vector2i preferredSize(NVGcontext* ctx) const override;
    virtual bool mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) override;

    virtual void draw(NVGcontext* ctx) override;

private:
    class TabButton {
    public:
        constexpr static const char* dots = "...";

        TabButton(TabHeader& header, const std::string& label);

        void setLabel(const std::string& label) { mLabel = label; }
        const std::string& label() const { return mLabel; }
        void setSize(const Vector2i& size) { mSize = size; }
        const Vector2i& size() const { return mSize; }

        Vector2i preferredSize(NVGcontext* ctx) const;
        void calculateVisibleString(NVGcontext* ctx);
        void drawAtPosition(NVGcontext* ctx, const Vector2i& position, bool active);
        void drawActiveBorderAt(NVGcontext * ctx, const Vector2i& position, float offset, const Color& color);
        void drawInactiveBorderAt(NVGcontext * ctx, const Vector2i& position, float offset, const Color& color);

    private:
        TabHeader* mHeader;
        std::string mLabel;
        Vector2i mSize;

        struct StringView {
            const char* first = nullptr;
            const char* last = nullptr;
        };
        StringView mVisibleText;
        int mVisibleWidth = 0;
    };

    using TabIterator = std::vector<TabButton>::iterator;
    using ConstTabIterator = std::vector<TabButton>::const_iterator;

    enum class ClickLocation {
        LeftControls, RightControls, TabButtons
    };

    TabIterator visibleBegin() { return std::next(mTabButtons.begin(), mVisibleStart); }
    TabIterator visibleEnd() { return std::next(mTabButtons.begin(), mVisibleEnd); }
    TabIterator activeIterator() { return std::next(mTabButtons.begin(), mActiveTab); }
    TabIterator tabIterator(int index) { return std::next(mTabButtons.begin(), index); }

    ConstTabIterator visibleBegin() const { return std::next(mTabButtons.begin(), mVisibleStart); }
    ConstTabIterator visibleEnd() const { return std::next(mTabButtons.begin(), mVisibleEnd); }
    ConstTabIterator activeIterator() const { return std::next(mTabButtons.begin(), mActiveTab); }
    ConstTabIterator tabIterator(int index) const { return std::next(mTabButtons.begin(), index); }

    void calculateVisibleEnd();

    void drawControls(NVGcontext* ctx);
    ClickLocation locateClick(const Vector2i& p);
    void onArrowLeft();
    void onArrowRight();

    std::function<void(int)> mCallback;
    std::vector<TabButton> mTabButtons;
    int mVisibleStart = 0;
    int mVisibleEnd = 0;
    int mActiveTab = 0;
    bool mOverflowing = false;

    std::string mFont;
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

NAMESPACE_END(nanogui)