Skip to content

File evabStretchBarPx.h

File List > src > evabStretchBarPx.h

Go to the documentation of this file

#pragma once

#include <evabElementBase.h>
#include <evabStretchBarPxResources.h>

namespace evab
{
    struct VerticalTilesetPolicy
    {
        static unsigned short CalculateTotalBlocks(Coor aSize)
        {
            return aSize.Y;
        }

        static unsigned short CalculateResolution(Coor aSize)
        {
            return 3 + (aSize.Y - 2) * 3 + 2;
        }

        static Coor GetTilePosition(Coor aPos, Coor aSize, unsigned char index, unsigned char total)
        {
            return {aPos.X, aPos.Y + aSize.Y - index - 1};
        }

        static Coor GetRestPosition(Coor aPos, Coor aSize)
        {
            return {aPos.X + 1, aPos.Y};
        }

        static Coor GetRestSize(Coor aPos, Coor aSize)
        {
            return {aSize.X - 1, aSize.Y};
        }
    };

    struct HorizontalTilesetPolicy
    {
        static unsigned short CalculateTotalBlocks(Coor aSize)
        {
            return aSize.X;
        }

        static unsigned short CalculateResolution(Coor aSize)
        {
            return 3 + (aSize.X - 2) * 3 + 2;
        }

        static Coor GetTilePosition(Coor aPos, Coor aSize, unsigned char index, unsigned char total)
        {
            return {aPos.X + index, aPos.Y};
        }
        static Coor GetRestPosition(Coor aPos, Coor aSize)
        {
            return {aPos.X, aPos.Y + 1};
        }
        static Coor GetRestSize(Coor aPos, Coor aSize)
        {
            return {aSize.X, aSize.Y - 1};
        }
    };

    template <typename TTileset, typename TOrientationTilesetPolicy>
    class StretchBarPx : public ElementBase
    {
    public:
        StretchBarPx(unsigned char aValue = 0, unsigned char aStep = 0)
            : mPercent(constrain(aValue, 0, 100)), mStep(aStep)
        {
        }

        void SetPercent(unsigned char aPercent)
        {
            aPercent = constrain(aPercent, 0, 100);
            if (mPercent == aPercent)
                return;
            mPercent = aPercent;
            redraw();
        }

        unsigned char GetPercent()
        {
            return mPercent;
        }

        void Increment(signed char delta)
        {
            SetPercent(mPercent + mStep * delta);
        }

    protected:
        void drawer(Screen *aScreen, Coor aPos, Coor aSize, unsigned char aIsFocused) override
        {
            unsigned short resolution = TOrientationTilesetPolicy::CalculateResolution(aSize);

            if (mStep == 0 && resolution > 0)
            {
                mStep = 100 / resolution + 1;
            }

            unsigned short normalizedValue = map(mPercent, 0, 100, 0, resolution);
            unsigned char totalBlocks = TOrientationTilesetPolicy::CalculateTotalBlocks(aSize);

            if (totalBlocks < 2)
                return;

            aScreen->Picto(
                TOrientationTilesetPolicy::GetTilePosition(aPos, aSize, 0, totalBlocks),
                TTileset::GetTile(START_BLOCK, blockFill(0, normalizedValue)),
                aIsFocused);

            for (unsigned char i = 1; i < totalBlocks - 1; i++)
            {
                aScreen->Picto(
                    TOrientationTilesetPolicy::GetTilePosition(aPos, aSize, i, totalBlocks),
                    TTileset::GetTile(MIDDLE_BLOCK, blockFill(i, normalizedValue)),
                    aIsFocused);
            }

            aScreen->Picto(
                TOrientationTilesetPolicy::GetTilePosition(aPos, aSize, totalBlocks - 1, totalBlocks),
                TTileset::GetTile(END_BLOCK, blockFill(totalBlocks - 1, normalizedValue)),
                aIsFocused);
            Coor clearAreaSize = TOrientationTilesetPolicy::GetRestSize(aPos, aSize);
            if (clearAreaSize.X > 0 && clearAreaSize.Y > 0)
                aScreen->Clear(TOrientationTilesetPolicy::GetRestPosition(aPos, aSize), clearAreaSize, aIsFocused);
        }

    private:
        char blockFill(unsigned char blockNumber, unsigned short normalizedValue)
        {
            if (normalizedValue / 3 < blockNumber)
                return 0;
            if (normalizedValue / 3 > blockNumber)
                return 4;
            return normalizedValue % 3 + 1;
        }

    private:
        static constexpr unsigned char START_BLOCK = 1;  
        static constexpr unsigned char MIDDLE_BLOCK = 2; 
        static constexpr unsigned char END_BLOCK = 3;    

        unsigned char mPercent; 
        unsigned char mStep;    
    };

    // Convenience typedefs for common stretch bar types
    using VerticalProgressBarPx = StretchBarPx<VerticalProgressBarTileset, VerticalTilesetPolicy>;
    using HorizontalProgressBarPx = StretchBarPx<HorizontalProgressBarTileset, HorizontalTilesetPolicy>;
    using VerticalScrollBarPx = StretchBarPx<VerticalScrollBarTileset, VerticalTilesetPolicy>;
    using HorizontalScrollBarPx = StretchBarPx<HorizontalScrollBarTileset, HorizontalTilesetPolicy>;
}