Исходник Customizable color picker (Supremacy)

Начинающий
Статус
Оффлайн
Регистрация
5 Мар 2020
Сообщения
32
Реакции[?]
2
Поинты[?]
0
pickerimg.png
colorpicker.cpp:
#include "includes.h"

void Colorpicker::update( )
{
    const int w{ COLORPICKER_SIZE };
    const int h{ COLORPICKER_SIZE };

    // allocate gradient.
    if( m_gradient.empty( ) )
        m_gradient = std::vector< Color >( w * h );

    // allocate new texture in engine.
    if( m_texture == 0 )
        m_texture = g_csgo.m_surface->CreateNewTextureID( true );

    // iterate width.
    for( int y{ }; y < w; ++y ) {

        // iterate height.
        for( int x{ }; x < h; ++x ) {

            float sat = x / float( h );
            float val = 1.0f - ( y / float( w ) );

            // write back to array.
            m_gradient[ y * w + x ] = Color::hsv_to_rgb( m_hue, sat, val, m_parent->m_alpha );
        }
    }

    // assign allocated memory containing the picker to said texture.
    g_csgo.m_surface->DrawSetTextureRGBA( m_texture, m_gradient.data(), w, h );
}

void Colorpicker::draw( )
{
    Rect area{ m_parent->GetElementsRect( ) };
    Point p{ area.x + m_pos.x, area.y + m_pos.y };

    // label.
    render::menu_shade.string(
        px + LABEL_OFFSET, py - 2,
        { 205, 205, 205, m_parent->m_alpha }, m_label );

    // update preview opacity.
    Color preview = m_color;
    preview.a( ) *= m_parent->m_opacity;

    // draw preview window.
    render::rect_filled(
        px + PREVIEW_OFFSET_X - PREVIEW_WIDTH + 1, py + 1,
        PREVIEW_WIDTH - 2, PREVIEW_HEIGHT - 2, preview );

    // fade / shine.
    render::rect_filled_fade(
        px + PREVIEW_OFFSET_X - PREVIEW_WIDTH + 1, py + 1,
        PREVIEW_WIDTH - 2, PREVIEW_HEIGHT - 2, { 50, 50, 35, m_parent->m_alpha }, 0, 150 );

    // outline.
    render::rect(
        px + PREVIEW_OFFSET_X - PREVIEW_WIDTH, py,
        PREVIEW_WIDTH, PREVIEW_HEIGHT, { 0, 0, 0, m_parent->m_alpha } );

    // draw picker
    if( m_open )
    {
        // update texture.
        Colorpicker::update( );

        // background.
        render::rect_filled(
            px + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_OFFSET_Y,
            COLORPICKER_SIZE + HUE_BAR_WIDTH + ( COLORPICKER_PADDING * 3 ),
            COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + ( COLORPICKER_PADDING * 3 ),
            { 41, 41, 41, m_parent->m_alpha } );

        // backgound outline.
        render::rect(
            px + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_OFFSET_Y,
            COLORPICKER_SIZE + HUE_BAR_WIDTH + ( COLORPICKER_PADDING * 3 ),
            COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + ( COLORPICKER_PADDING * 3 ),
            { 0, 0, 0, m_parent->m_alpha } );

        // set panel color.
        g_csgo.m_surface->DrawSetColor( { 255, 255, 255, m_parent->m_alpha });

        // set texture.
        g_csgo.m_surface->DrawSetTexture( m_texture );

        // draw picker.
        g_csgo.m_surface->DrawTexturedRect(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y,
            px + COLORPICKER_SIZE + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_SIZE + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y );

        // picker outline.
        render::rect(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y,
            COLORPICKER_SIZE,
            COLORPICKER_SIZE,
            { 0, 0, 0, m_parent->m_alpha } );

        // draw hue bar.
        for( int i{ }; i < COLORPICKER_SIZE; ++i ) {
            float hue = i / float( COLORPICKER_SIZE );
            render::rect_filled(
                px + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_X,
                py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y + i,
                HUE_BAR_WIDTH, 1,
                Color::hsv_to_rgb( hue, 1.0f, 1.0f, m_parent->m_alpha ) );
        }

        // hue bar outline.
        render::rect(
            px + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_X - 1,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y,
            HUE_BAR_WIDTH + 1,
            COLORPICKER_SIZE,
            { 0, 0, 0, m_parent->m_alpha } );

        // hue bar slider.
        render::rect_filled(
            px + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_X - 1,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y + m_hue * ( COLORPICKER_SIZE - 3 ),
            HUE_BAR_WIDTH + 1, 3,
            { 255, 255, 255, m_parent->m_alpha } );

        // hue bar slider outline
        render::rect(
            px + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_X - 1,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y + m_hue * ( COLORPICKER_SIZE - 3 ),
            HUE_BAR_WIDTH + 1, 3,
            { 0, 0, 0, m_parent->m_alpha } );

        // update alpha opacity.
        Color alpha_color = m_color;
        alpha_color.a( ) *= m_parent->m_opacity;

        // draw alpha bar.
        render::rect_filled(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_Y,
            COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + COLORPICKER_PADDING,
            ALPHA_BAR_HEIGHT,
            alpha_color );

        // alpha bar outline.
        render::rect(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_Y - 1,
            COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + COLORPICKER_PADDING,
            ALPHA_BAR_HEIGHT + 1,
            { 0, 0, 0, m_parent->m_alpha } );

        // alpha bar slider.
        render::rect_filled(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X + m_alpha * ( ( COLORPICKER_SIZE - 3 ) + ALPHA_BAR_HEIGHT + COLORPICKER_PADDING ),
            py + PREVIEW_HEIGHT + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_Y,
            3, ALPHA_BAR_HEIGHT - 1,
            { 255, 255, 255, m_parent->m_alpha } );

        // alpha bar slider outline.
        render::rect(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X + m_alpha * ( ( COLORPICKER_SIZE - 3 ) + ALPHA_BAR_HEIGHT + COLORPICKER_PADDING ),
            py + PREVIEW_HEIGHT + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_Y - 1,
            3, ALPHA_BAR_HEIGHT + 1,
            { 0, 0, 0, m_parent->m_alpha } );

        // color selector.
        render::rect_filled(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X + m_saturation * ( COLORPICKER_SIZE - 4 ),
            py + PREVIEW_HEIGHT + COLORPICKER_OFFSET_Y + COLORPICKER_PADDING + ( 1 - m_value ) * ( COLORPICKER_SIZE - 4 ),
            4, 4, { 255, 255, 255, m_parent->m_alpha } );

        // color selector outline.
        render::rect(
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X + m_saturation * ( COLORPICKER_SIZE - 4 ),
            py + PREVIEW_HEIGHT + COLORPICKER_OFFSET_Y + COLORPICKER_PADDING + ( 1 - m_value ) * ( COLORPICKER_SIZE - 4 ),
            4, 4, { 0, 0, 0, m_parent->m_alpha } );
    }
}

void Colorpicker::think( )
{
    Rect area{ m_parent->GetElementsRect( ) };
    Point p{ area.x + m_pos.x, area.y + m_pos.y };

    if( m_open ) {
        // color square bounds.
        Rect square{
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y,
            COLORPICKER_SIZE,
            COLORPICKER_SIZE };

        // hue bounds.
        Rect hue_bar{
            px + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_X - 1,
            py + PREVIEW_HEIGHT + COLORPICKER_PADDING + COLORPICKER_OFFSET_Y,
            HUE_BAR_WIDTH + 1,
            COLORPICKER_SIZE };

        // hue bounds.
        Rect alpha_bar{
            px + COLORPICKER_PADDING + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_SIZE + ( COLORPICKER_PADDING * 2 ) + COLORPICKER_OFFSET_Y - 1,
            COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + COLORPICKER_PADDING,
            ALPHA_BAR_HEIGHT + 1 };

        // update colors.
        if( g_input.GetKeyState( VK_LBUTTON ) )
        {
            // within color square.
            if( g_input.IsCursorInRect( square ) || m_color_drag )
            {
                // update color saturation.
                m_saturation = std::clamp(
                    ( g_input.m_mouse.x - square.x ) / float( COLORPICKER_SIZE ),
                    0.0f, 1.0f );

                // update color value.
                m_value = 1.0f - std::clamp(
                    (g_input.m_mouse.y - square.y ) / float( COLORPICKER_SIZE ),
                    0.0f, 1.0f );

                // dragging color.
                m_color_drag = true;
            }

            // within hue slider.
            else if( g_input.IsCursorInRect( hue_bar ) || m_hue_drag )
            {
                // update color hue.
                m_hue = std::clamp( ( g_input.m_mouse.y - hue_bar.y ) /
                    float( COLORPICKER_SIZE ), 0.0f, 1.0f );

                // dragging hue.
                m_hue_drag = true;
            }

            // within alpha slider.
            else if( g_input.IsCursorInRect( alpha_bar ) || m_alpha_drag )
            {
                // update color alpha.
                m_alpha = std::clamp(
                    (g_input.m_mouse.x - alpha_bar.x) /
                    float( COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + COLORPICKER_PADDING ),
                    0.0f, 1.0f);

                // dragging alpha.
                m_alpha_drag = true;
            }
        }
        else {
            // reset drag states.
            Colorpicker::ResetDrag( );
        }

        // update height.
        m_h = PREVIEW_HEIGHT + COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + ( COLORPICKER_PADDING * 3 ) + COLORPICKER_OFFSET_Y;

        // setup width addition.
        int preview_width = px + PREVIEW_OFFSET_X + 1;
        int colorpicker_width = px + COLORPICKER_OFFSET_X + COLORPICKER_SIZE + HUE_BAR_WIDTH + ( COLORPICKER_PADDING * 3 );
        int diff = ( colorpicker_width - preview_width );

        // update width.
        m_w = PREVIEW_OFFSET_X + ( diff > 0 ? diff : 0 );

        // color picker window.
        Rect window{
            px + COLORPICKER_OFFSET_X,
            py + PREVIEW_HEIGHT + COLORPICKER_OFFSET_Y,
            COLORPICKER_SIZE + HUE_BAR_WIDTH + ( COLORPICKER_PADDING * 3 ),
            COLORPICKER_SIZE + ALPHA_BAR_HEIGHT + ( COLORPICKER_PADDING * 3 ) };

        // using color picker.
        if( m_color_drag || m_hue_drag || m_alpha_drag ) 
        {
            // set updated colors.
            m_color = Color::hsv_to_rgb( m_hue, m_saturation, m_value );
            m_color.a( ) = ( m_alpha * 255.f );
        }

        // update active element.
        if( g_input.IsCursorInRect( window ) ) {
            m_parent->m_active_element = this;

            // don't drag menu.
            g_gui.m_drag_form = nullptr;
        }
        else {
            // close on element selection.
            if( m_parent->m_active_element != this ) {
                m_open = false;
    
                // callback on close.
                if( m_callback )
                    m_callback( );
            }
        }
    }
    else {
        // restore bounds.
        m_h = PREVIEW_HEIGHT;
        m_w = PREVIEW_OFFSET_X;
    }

    if( m_ptr )
        *m_ptr = m_color;
}

void Colorpicker::click( )
{
    Rect area{ m_parent->GetElementsRect( ) };
    Point p{ area.x + m_pos.x, area.y + m_pos.y };

    // color preview.
    Rect preview{
        px + PREVIEW_OFFSET_X - PREVIEW_WIDTH,
        py,
        PREVIEW_WIDTH,
        PREVIEW_HEIGHT };

    // cursor in preview.
    if( g_input.IsCursorInRect( preview ) )
    {
        // grab previous color.
        if( !m_open )
            Color::color_to_hsv( m_color, m_hue, m_saturation, m_value );

        // set open state.
        m_open = !m_open;
    }
}
colorpicker.h:
#pragma once

#define PREVIEW_WIDTH 20
#define PREVIEW_HEIGHT 8
#define PREVIEW_OFFSET_X 175

#define COLORPICKER_SIZE 150
#define COLORPICKER_PADDING 5
#define COLORPICKER_OFFSET_X 10
#define COLORPICKER_OFFSET_Y 5

#define HUE_BAR_WIDTH 10
#define ALPHA_BAR_HEIGHT 10

class Colorpicker : public Element {
public:
    __forceinline Colorpicker( ) : m_open{ false }, m_label{}, m_color{}, m_ptr{ nullptr } {
        m_flags = ElementFlags::DRAW | ElementFlags::CLICK | ElementFlags::ACTIVE | ElementFlags::SAVE;
        m_type = ElementTypes::COLORPICKER;
        m_h = m_base_h = PREVIEW_HEIGHT;
        m_use_label = true;
        m_show = true;
    }

    __forceinline void setup( const std::string &label, const std::string &file_id, Color color, Color* ptr = nullptr ) {
        m_label = label;
        m_file_id = file_id;
        m_color = color;
        m_alpha = m_color.a( ) / 255.0f;
        m_ptr = ptr;

        if( m_ptr )
            *m_ptr = m_color;
    }

    __forceinline void set( Color color ) {
        bool changed = m_color.rgba( ) != color.rgba( );

        m_color = color;
        m_alpha = m_color.a( ) / 255.0f;

        if( m_ptr )
            *m_ptr = m_color;

        if( changed && m_callback )
            m_callback( );
    }

    __forceinlineColor get() {
        return m_color;
    }

    __forceinline void ResetDrag( ) {
        m_color_drag = false;
        m_hue_drag = false;
        m_alpha_drag = false;
    }

protected:
    bool m_open;
    std::string m_label;
    Color m_color;
    Color* m_ptr;

    float m_hue;
    float m_saturation;
    float m_value;
    float m_alpha;

    bool m_alpha_drag;
    bool m_hue_drag;
    bool m_color_drag;

    int m_texture;
    std::vector< Color > m_gradient;

protected:
    void draw( ) override;
    void think( ) override;
    void click( ) override;
    void update( );
};
color.h:
#pragma once

class Color {
private:
    // easy reinterpret.
    union {
        struct {
            uint8_t m_r;
            uint8_t m_g;
            uint8_t m_b;
            uint8_t m_a;
        };

        uint32_t m_rgba;
    };

public:
    // ctors.
    __forceinline Color( ) : m_r{ 0 }, m_g{ 0 }, m_b{ 0 }, m_a{ 0 }, m_rgba{} {}
    __forceinline Color( int r, int g, int b, int a = 255 ): m_r{ ( uint8_t )r }, m_g{ ( uint8_t )g }, m_b{ ( uint8_t )b }, m_a{ ( uint8_t )a } { }
    __forceinline Color( uint32_t rgba ) : m_rgba{ rgba } {}

    static void color_to_hsv( Color c, float& h, float& s, float& v ) {
        float r_norm = cr( ) / 255.0f;
        float g_norm = cg( ) / 255.0f;
        float b_norm = cb( ) / 255.0f;

        float cmax = std::max( { r_norm, g_norm, b_norm } );
        float cmin = std::min( { r_norm, g_norm, b_norm } );
        float diff = cmax - cmin;

        v = cmax;

        if( cmax == 0.0f )
            s = 0.0f;
        else
            s = diff / cmax;

        if( diff == 0.0f )
            h = 0.0f;
        else if( cmax == r_norm )
            h = fmod( ( 60 * ( ( g_norm - b_norm ) / diff ) + 360 ), 360 ) / 360.0f;
        else if ( cmax == g_norm )
            h = fmod( ( 60 * ( ( b_norm - r_norm ) / diff ) + 120 ), 360 ) / 360.0f;
        else
            h = fmod( ( 60 * ( ( r_norm - g_norm ) / diff ) + 240 ), 360 ) / 360.0f;
    }

    static Color hsv_to_rgb( float h, float s, float v, float a ) {
        float r, g, b;
        if( s == 0.0f ) {
            r = g = b = v;
        }
        else {
            int i = int( h * 6.0f );
            float f = ( h * 6.0f ) - i;
            float p = v * ( 1.0f - s );
            float q = v * ( 1.0f - s * f );
            float t = v * ( 1.0f - s * ( 1.0f - f ) );

            switch( i % 6 ) {
            case 0: r = v, g = t, b = p; break;
            case 1: r = q, g = v, b = p; break;
            case 2: r = p, g = v, b = t; break;
            case 3: r = p, g = q, b = v; break;
            case 4: r = t, g = p, b = v; break;
            case 5: r = v, g = p, b = q; break;
            }
        }
        return Color( r * 255, g * 255, b * 255, a );
    }

    static Color hsv_to_rgb( float h, float s, float v ) {
        return hsv_to_rgb( h, s, v, 255.f );
    }

    // member accessors.
    __forceinline uint8_t& r( ) { return m_r; }
    __forceinline uint8_t& g( ) { return m_g; }
    __forceinline uint8_t& b( ) { return m_b; }
    __forceinline uint8_t& a( ) { return m_a; }
    __forceinline uint32_t& rgba( ) { return m_rgba; }

    // operators.
    __forceinline operator uint32_t() { return m_rgba; }
};

namespace colors {
    static Color white{ 255, 255, 255, 255 };
    static Color black{ 0, 0, 0, 255 };
    static Color red{ 255, 0, 0, 255 };
    static Color burgundy{ 0xff2d00b3 };
    static Color light_blue{ 95, 174, 227, 255 };
    static Color orange{ 243, 156, 18, 255 };
    static Color transparent_green{ 0, 255, 0, 200 };
    static Color transparent_yellow{ 255, 255, 0, 200 };
    static Color transparent_red{ 255, 0, 0, 200 };
}
 
Последнее редактирование:
Сверху Снизу