How to make an color picker in pygame?

Question:

I am making an illustrator n pygame and now i need to color my shapes. I need to make an color picker like this:
enter image description here

The idea is that the user will scroll on the bar and select an color then it will return the program an rgb value or you can say the color that will tell which color is selected.
How can i make this possible.
Should i have to use surface.set_at() and make this my setting the color of each pixel or there an alternate way of doing this.
This is my code:

import pygame 
import math
pygame.init()

HEIGHT = 700
WIDTH = 1000

WHITE  = (255, 255, 255)
BLACK  = (0, 0, 0) 
AQUA = "aqua"

shapes = []

window = pygame.display.set_mode((WIDTH, HEIGHT), pygame.RESIZABLE)
pygame.display.set_caption("Illustrator")

window.fill(WHITE)


class Square:
    def __init__(self, square_x, square_y, square_width, square_height):
        self.square_x = square_x
        self.square_y = square_y
        self.square_width = square_width
        self.square_height = square_height

class Circle:
    def __init__(self, circle_x, cirlce_y, circle_radius):
        self.circle_x = circle_x
        self.circle_y = cirlce_y
        self.circle_radius = circle_radius

class Button:
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
    
    def clicked(self):
        mouse_x, mouse_y = pygame.mouse.get_pos()
        if self.x <= mouse_x <= self.x + self.width and self.y <= mouse_y <= self.y + self.height:
            return True

square_button  = Button(10, 10, 50, 30)
circle_button  = Button(10, 50, 50, 30)


def buttons(window):
    pygame.draw.rect(window, BLACK, pygame.Rect(square_button.x, square_button.y, square_button.width, square_button.height))
    pygame.draw.rect(window, BLACK, pygame.Rect(circle_button.x, circle_button.y, circle_button.width, circle_button.height))


def draw_square(window, x, y, width, height): 
    color = "black"
    pygame.draw.rect(window, color, pygame.Rect(x, y, width, height))

def draw_circle(window, x, y, radius):
    pygame.draw.circle(window, AQUA, (x, y), radius)

def square_logic(mouse_x_button_down, mouse_y_button_down, mouse_x_button_up, mouse_y_button_up, delta_x, delta_y):
    if delta_x > 0 and delta_y > 0:
        shapes.append(Square(mouse_x_button_down, mouse_y_button_down, delta_x, delta_y))
    elif delta_x < 0 and delta_y < 0 :
        shapes.append(Square(mouse_x_button_up, mouse_y_button_up, abs(delta_x), abs(delta_y)))
    elif delta_x < 0 and delta_y > 0:
        shapes.append(Square(mouse_x_button_up, mouse_y_button_down, abs(delta_x), delta_y))
    elif delta_x > 0 and delta_y < 0:
        shapes.append(Square(mouse_x_button_down, mouse_y_button_up, delta_x, abs(delta_y)))
        
def square_logic_for_drag(mouse_x_button_down, mouse_y_button_down, mouse_x, mouse_y, delta_x, delta_y):
    if delta_x > 0 and delta_y > 0:
        draw_square(window, mouse_x_button_down, mouse_y_button_down, delta_x, delta_y)
    elif delta_x < 0 and delta_y < 0 :
        draw_square(window, mouse_x, mouse_y, abs(delta_x), abs(delta_y))
    elif delta_x < 0 and delta_y > 0:
        draw_square(window, mouse_x, mouse_y_button_down, abs(delta_x), delta_y)
    elif delta_x > 0 and delta_y < 0:
        draw_square(window, mouse_x_button_down, mouse_y, delta_x, abs(delta_y))

def circle_logic(delta_x, delta_y, mouse_x_button_down, mouse_y_button_down, radius):
    if delta_x > 0 and delta_y > 0 or delta_x < 0 and delta_y > 0 or delta_x > 0 and delta_y < 0 or delta_x < 0 and delta_y < 0:
        shapes.append(Circle(mouse_x_button_down + delta_x/2, mouse_y_button_down + delta_y/2, radius))


def circle_logic_for_drag(delta_x, delta_y, mouse_x_button_down, mouse_y_button_down, radius):
    if delta_x > 0 and delta_y > 0 or delta_x < 0 and delta_y > 0 or delta_x > 0 and delta_y < 0 or delta_x < 0 and delta_y < 0:
        draw_circle(window, mouse_x_button_down + delta_x/2, mouse_y_button_down + delta_y/2, radius)


def draw_previous_shapes():
    for j in  range(len(shapes)):
        if type(shapes[j]) == Square:
            draw_square(window, shapes[j].square_x, shapes[j].square_y, shapes[j].square_width, shapes[j].square_height)
        if type(shapes[j]) == Circle:
            draw_circle(window, shapes[j].circle_x, shapes[j].circle_y, shapes[j].circle_radius)


def main():
    run = True
    mouse_button_down = False
    mouse_button_up = False
    shape = "square"
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                
            if event.type == pygame.MOUSEBUTTONDOWN:
                mouse_x_button_down, mouse_y_button_down = pygame.mouse.get_pos()
                print(mouse_x_button_down, mouse_y_button_down)
                mouse_button_down = True
                if square_button.clicked():
                    shape = "square"
                if circle_button.clicked():
                    shape = "circle"
                
            if event.type == pygame.MOUSEBUTTONUP:
                mouse_x_button_up, mouse_y_button_up = pygame.mouse.get_pos()
                print(mouse_x_button_up, mouse_y_button_up)
                mouse_button_up = True
            
            if event.type == pygame.KEYDOWN:

                if event.key == pygame.K_z and (pygame.key.get_mods() == 64 or pygame.key.get_mods() == 128):
                    try:
                        shapes.pop(len(shapes) - 1)
                        window.fill(WHITE)
                        draw_previous_shapes()
                    except:
                        pass

        buttons(window)
        
        if mouse_button_down == True :
            if mouse_button_up == True:
                mouse_button_down = False
                mouse_button_up = False

                delta_x = mouse_x_button_up - mouse_x_button_down
                delta_y = mouse_y_button_up - mouse_y_button_down

                radius = math.sqrt(delta_x*delta_x + delta_y*delta_y) /2

                print( delta_x, delta_y)

                if shape == "square":
                    square_logic(mouse_x_button_down, mouse_y_button_down, mouse_x_button_up, mouse_y_button_up, delta_x, delta_y)
                if shape == "circle":
                    circle_logic(delta_x, delta_y, mouse_x_button_down, mouse_y_button_down, radius)
            
            else:
                window.fill(WHITE)
                buttons(window)
                draw_previous_shapes()

                mouse_x, mouse_y = pygame.mouse.get_pos()
                delta_x = mouse_x - mouse_x_button_down
                delta_y = mouse_y - mouse_y_button_down

                radius = math.sqrt(delta_x*delta_x + delta_y*delta_y) /2

                if shape == "square":
                    square_logic_for_drag(mouse_x_button_down, mouse_y_button_down, mouse_x, mouse_y, delta_x, delta_y)
                if shape == "circle":
                    circle_logic_for_drag(delta_x, delta_y, mouse_x_button_down, mouse_y_button_down, radius)

        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()

For further explaination comment me?

Asked By: Muhammad Umer

||

Answers:

The pygame.Color object can be used to convert between the RGB and [HSL/HSV](HSL and HSV) color schemes.

The hsla property:

The HSLA representation of the Color. The HSLA components are in the ranges H = [0, 360], S = [0, 100], V = [0, 100], A = [0, 100].

Create a pygame.Surface and use the function `hsla to create an image for the color picker:

class ColorPicker:
    def __init__(self, x, y, w, h):
        self.rect = pygame.Rect(x, y, w, h)
        self.image = pygame.Surface((w, h))
        self.image.fill((255, 255, 255))
        self.rad = h//2
        self.pwidth = w-self.rad*2
        for i in range(self.pwidth):
            color = pygame.Color(0)
            color.hsla = (int(360*i/self.pwidth), 100, 50, 100)
            pygame.draw.rect(self.image, color, (i+self.rad, h//3, 1, h-2*h//3))

Calculation of the relative position in the coller picker when the mouse button is held down:

class ColorPicker:
    # [...]
    
    def update(self):
        moude_buttons = pygame.mouse.get_pressed()
        mouse_pos = pygame.mouse.get_pos()
        if moude_buttons[0] and self.rect.collidepoint(mouse_pos):
            self.p = (mouse_pos[0] - self.rect.left - self.rad) / self.pwidth
            self.p = (max(0, min(self.p, 1)))

Determine the color from the relative position in the color picker:

class ColorPicker:
    # [...]

    def get_color(self):
        color = pygame.Color(0)
        color.hsla = (int(self.p * self.pwidth), 100, 50, 100)
        return color

Minimal example:

import pygame

class ColorPicker:
    def __init__(self, x, y, w, h):
        self.rect = pygame.Rect(x, y, w, h)
        self.image = pygame.Surface((w, h))
        self.image.fill((255, 255, 255))
        self.rad = h//2
        self.pwidth = w-self.rad*2
        for i in range(self.pwidth):
            color = pygame.Color(0)
            color.hsla = (int(360*i/self.pwidth), 100, 50, 100)
            pygame.draw.rect(self.image, color, (i+self.rad, h//3, 1, h-2*h//3))
        self.p = 0

    def get_color(self):
        color = pygame.Color(0)
        color.hsla = (int(self.p * self.pwidth), 100, 50, 100)
        return color

    def update(self):
        moude_buttons = pygame.mouse.get_pressed()
        mouse_pos = pygame.mouse.get_pos()
        if moude_buttons[0] and self.rect.collidepoint(mouse_pos):
            self.p = (mouse_pos[0] - self.rect.left - self.rad) / self.pwidth
            self.p = (max(0, min(self.p, 1)))

    def draw(self, surf):
        surf.blit(self.image, self.rect)
        center = self.rect.left + self.rad + self.p * self.pwidth, self.rect.centery
        pygame.draw.circle(surf, self.get_color(), center, self.rect.height // 2)

pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()

cp = ColorPicker(50, 50, 400, 60)

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 

    cp.update()

    window.fill(0)
    cp.draw(window)
    pygame.display.flip()
    
pygame.quit()
exit()
Answered By: Rabbid76
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.