-
Автор темы
- #1
- Color picker size and position can be adjusted from definitions inside of colorpicker.h
- Some code was used from here https://yougame.biz/threads/331465/ credits to them
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 };
}
Последнее редактирование: