Jump to content

Color picker (codes available)


Recommended Posts

"Use a picture. It's worth a thousand words." - Tess Flanders, 1911

RDi1tJq.png

I searched for codes of a free color picker in this forum and found nothing. So I wrote a new one.

I spent way too much time and effort of rewriting a Unity color picker for KSP not to share this little gem to you. Enjoy!

The license of the original picker is not specified so I think it is released to the public domain.

using UnityEngine;

// credit to Brian Jones (https://github.com/boj)
// obtained from https://gist.github.com/boj/1181465 (warning: the original author's codes were written hurriedly, resulting in obvious bugs)
// license - not found; I think it is released to public domain
namespace CommNetConstellation
{
    [KSPAddon(KSPAddon.Startup.TrackingStation, false)]
    public class ColorPicker : MonoBehaviour
    {
        public bool showPicker = true;

        private Texture2D displayPicker;
        public int displayTextureWidth = 360;
        public int displayTextureHeight = 360;

        public int positionLeft;
        public int positionTop;

        public Color chosenColor;
        private Texture2D chosenColorTexture;

        private float hueSlider = 0f;
        private float prevHueSlider = 0f;
        private Texture2D hueTexture;
        
        protected void Awake()
        {
            positionLeft = (Screen.width / 2) - (displayTextureWidth / 2);
            positionTop = (Screen.height / 2) - (displayTextureHeight / 2);

            renderColorPicker();

            hueTexture = new Texture2D(10, displayTextureHeight, TextureFormat.ARGB32, false);
            for (int x = 0; x < hueTexture.width; x++)
            {
                for (int y = 0; y < hueTexture.height; y++)
                {
                    float h = (y / (hueTexture.height*1.0f)) * 1f;
                    hueTexture.SetPixel(x, y, new ColorHSV(h, 1f, 1f).ToColor());
                }
            }
            hueTexture.Apply();

            // small color picker box texture
            chosenColorTexture = new Texture2D(1, 1);
            chosenColorTexture.SetPixel(0, 0, chosenColor);
        }

        private void renderColorPicker()
        {
            Texture2D colorPicker = new Texture2D(displayTextureWidth, displayTextureHeight, TextureFormat.ARGB32, false);
            for (int x = 0; x < displayTextureWidth; x++)
            {
                for (int y = 0; y < displayTextureHeight; y++)
                {
                    float h = hueSlider;
                    float v = (y / (displayTextureHeight * 1.0f)) * 1f;
                    float s = (x / (displayTextureWidth * 1.0f)) * 1f;
                    colorPicker.SetPixel(x, y, new ColorHSV(h, s, v).ToColor());
                }
            }

            colorPicker.Apply();
            displayPicker = colorPicker;
        }

        protected void OnGUI()
        {
            if (!showPicker) return;

            GUI.Box(new Rect(positionLeft - 3, positionTop - 3, displayTextureWidth + 60, displayTextureHeight + 60), "");

            if (hueSlider != prevHueSlider) // new Hue value
            {
                prevHueSlider = hueSlider;
                renderColorPicker();
            }

            if (GUI.RepeatButton(new Rect(positionLeft, positionTop, displayTextureWidth, displayTextureHeight), displayPicker))
            {
                int a = (int)Input.mousePosition.x;
                int b = Screen.height - (int)Input.mousePosition.y;

                chosenColor = displayPicker.GetPixel(a - positionLeft, -(b - positionTop));
            }

            hueSlider = GUI.VerticalSlider(new Rect(positionLeft + displayTextureWidth + 3, positionTop, 10, displayTextureHeight), hueSlider, 1, 0);
            GUI.Box(new Rect(positionLeft + displayTextureWidth + 20, positionTop, 20, displayTextureHeight), hueTexture);

            if (GUI.Button(new Rect(positionLeft + displayTextureWidth - 60, positionTop + displayTextureHeight + 10, 60, 25), "Apply"))
            {
                chosenColor = chosenColorTexture.GetPixel(0, 0);
                showPicker = false;
            }

            // box for chosen color
            GUIStyle style = new GUIStyle();
            chosenColorTexture.SetPixel(0, 0, chosenColor);
            chosenColorTexture.Apply();
            style.normal.background = chosenColorTexture;
            GUI.Box(new Rect(positionLeft + displayTextureWidth + 10, positionTop + displayTextureHeight + 10, 30, 30), new GUIContent(""), style);
        }
    }
}

 

Edited by TaxiService
Link to comment
Share on other sites

For anyone asking  if it is possible to build a similar color picker using KSP's DialogGUI components (KSP 1.1 and later), the answer is undoubtedly yes.

tNZeerd.png

The catch is, however,

  • learn how to draw a texture (like this hue slider, main image) to pass to DialogGUIImage (and DialogGUISprite if possible)
  • There is no repeat button in DialogGUI components to choose a color so use the positions of mouse cursor and dialog's center to detect when a player presses his cursor within the color picker image
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;

namespace CommNetConstellation.UI
{
    public class ColorPickerDialog : AbstractDialog
    {
        private Callback<Color> callbackForChosenColor;

        private int displayTextureWidth = 250;
        private int displayTextureHeight = 250;
        private DialogGUIImage colorPickerImage;
        private Texture2D colorPickerTexture;

        private static int dialogWidth = 250 + 10;
        private static int dialogHeight = 300;

        private Color chosenColor;
        private Texture2D chosenColorTexture;
        private DialogGUIImage newColorImage;

        private Color currentColor;
        private Texture2D currentColorTexture;

        private float hueValue = 0f;
        private int sliderHeight = 5;

        private bool buttonPressing = false;

        public ColorPickerDialog(Color userColor, Callback<Color> callbackForChosenColor) : base("Color Picker",
                                                                                                0.5f, //x
                                                                                                0.5f, //y
                                                                                                dialogWidth, //width
                                                                                                dialogHeight, //height
                                                                                                new string[] { "hideclosebutton", "nodragging" }) //arguments
        {
            this.currentColor = userColor;
            this.chosenColor = userColor;
            this.callbackForChosenColor = callbackForChosenColor;

            this.chosenColorTexture = UIUtils.createAndColorize(30, 24, chosenColor);
            this.currentColorTexture = UIUtils.createAndColorize(30, 24, currentColor);
            this.colorPickerTexture = new Texture2D(displayTextureWidth, displayTextureHeight, TextureFormat.ARGB32, false);
            renderColorPicker(this.colorPickerTexture, hueValue);
        }

        protected override void OnUpdate() // MultiOptionDialog.OnUpdate = this method
        {
            Vector2 cursor = Input.mousePosition;
            Vector3 pickerCenter = Camera.current.WorldToScreenPoint(colorPickerImage.uiItem.transform.position);

            if (!EventSystem.current.IsPointerOverGameObject())
                buttonPressing = false;

            if (pickerCenter.x- displayTextureWidth/2 <= cursor.x && cursor.x <= pickerCenter.x+displayTextureWidth/2 &&
                pickerCenter.y - displayTextureHeight / 2 <= cursor.y && cursor.y <= pickerCenter.y + displayTextureHeight / 2)
            {
                if(!buttonPressing && Input.GetMouseButtonDown(0)) // user pressing button
                {
                    buttonPressing = true;
                }
                else if(buttonPressing && Input.GetMouseButtonUp(0)) // user releasing button
                {
                    buttonPressing = false;
                }

                if (buttonPressing)
                {
                    int localX = (int)(cursor.x - (pickerCenter.x - displayTextureWidth/2));
                    int localY = (int)(cursor.y - (pickerCenter.y - displayTextureHeight/2));

                    renderColorPicker(colorPickerTexture, hueValue); // wipe out cursor data
                    chosenColor = colorPickerTexture.GetPixel(localX, localY);
                    UIUtils.colorizeFull(chosenColorTexture, chosenColor);
                    newColorImage.uiItem.GetComponent<RawImage>().texture = chosenColorTexture;

                    colorPickerImage.uiItem.GetComponent<RawImage>().texture = drawCursorOn(colorPickerTexture, localX, localY);
                }
            }
        }

        protected override List<DialogGUIBase> drawContentComponents()
        {
            List<DialogGUIBase> listComponments = new List<DialogGUIBase>();

            DialogGUILabel newColorLabel = new DialogGUILabel("<b>  New</b>", 40, 12);
            newColorImage = new DialogGUIImage(new Vector2(30, 24), Vector2.zero, Color.white, chosenColorTexture); 
            DialogGUILabel currentColorLabel = new DialogGUILabel("<b>Current  </b>", 45, 12);
            DialogGUIImage currentColorImage = new DialogGUIImage(new Vector2(30, 24), Vector2.zero, Color.white, currentColorTexture);
            listComponments.Add(new DialogGUIHorizontalLayout(true, false, 0, new RectOffset(), TextAnchor.MiddleCenter, new DialogGUIBase[] { new DialogGUISpace(40), newColorImage, newColorLabel, new DialogGUISpace(dialogWidth - 80 - 145), currentColorLabel, currentColorImage, new DialogGUISpace(40) }));

            colorPickerImage = new DialogGUIImage(new Vector2(displayTextureWidth, displayTextureHeight), Vector2.zero, Color.white, colorPickerTexture);
            DialogGUIImage hueSliderImage = new DialogGUIImage(new Vector2(displayTextureWidth, sliderHeight * 2), Vector2.zero, Color.white, renderHueSliderTexture());
            DialogGUISlider hueSlider = new DialogGUISlider(() => hueValue, 0f, 1f, false, displayTextureWidth, sliderHeight, setHueValue);
            listComponments.Add(new DialogGUIVerticalLayout(true, false, 0, new RectOffset(), TextAnchor.UpperCenter, new DialogGUIBase[] { colorPickerImage, new DialogGUISpace(5f), hueSliderImage, hueSlider }));

            DialogGUIButton applyButton = new DialogGUIButton("Apply", applyClick);
            listComponments.Add(new DialogGUIHorizontalLayout(true, false, 0, new RectOffset(), TextAnchor.MiddleCenter, new DialogGUIBase[] { new DialogGUIFlexibleSpace(), applyButton, new DialogGUIFlexibleSpace() }));

            return listComponments;
        }

        protected override bool DialogAwake(object[] args)
        {
            return true;
        }

        private void renderColorPicker(Texture2D thisTexture, float hueValue)
        {
            for (int x = 0; x < displayTextureWidth; x++)
            {
                for (int y = 0; y < displayTextureHeight; y++)
                {
                    float h = hueValue;
                    float v = (y / (displayTextureHeight * 1.0f)) * 1f;
                    float s = (x / (displayTextureWidth * 1.0f)) * 1f;
                    thisTexture.SetPixel(x, y, new ColorHSV(h, s, v).ToColor());
                }
            }
            thisTexture.Apply();
        }

        private Texture2D renderHueSliderTexture()
        {
            Texture2D hueTexture = new Texture2D(displayTextureWidth, sliderHeight * 2, TextureFormat.ARGB32, false);
            for (int x = 0; x < hueTexture.width; x++)
            {
                for (int y = 0; y < hueTexture.height; y++)
                {
                    float h = (x / (hueTexture.width* 1.0f)) * 1f;
                    hueTexture.SetPixel(x, y, new ColorHSV(h, 1f, 1f).ToColor());
                }
            }
            hueTexture.Apply();
            return hueTexture;
        }

        private void setHueValue(float newValue)
        {
            this.hueValue = newValue;
            renderColorPicker(colorPickerTexture, newValue);
            colorPickerImage.uiItem.GetComponent<RawImage>().texture = colorPickerTexture;
        }

        private Texture2D drawCursorOn(Texture2D thisTexture, int x, int y)
        {
            Color cursorColor = Color.white;

            if (x - 2 >= 0) // left arm
                thisTexture.SetPixel(x-2, y, cursorColor);
            if (x - 3 >= 0)
                thisTexture.SetPixel(x-3, y, cursorColor);

            if (x +2  <= thisTexture.width) // right arm
                thisTexture.SetPixel(x + 2, y, cursorColor);
            if (x + 3 <= thisTexture.width)
                thisTexture.SetPixel(x + 3, y, cursorColor);

            if (y - 2 >= 0) // legs
                thisTexture.SetPixel(x, y - 2, cursorColor);
            if (y - 3 >= 0)
                thisTexture.SetPixel(x, y - 3, cursorColor);

            if (y + 2 <= thisTexture.height) // head
                thisTexture.SetPixel(x, y + 2, cursorColor);
            if (y + 3 <= thisTexture.height)
                thisTexture.SetPixel(x, y + 3, cursorColor);

            thisTexture.Apply();
            return thisTexture;
        }

        private void applyClick() // TODO: to be replaced by abstract dialog's close button's callback & text
        {
            UnityEngine.GameObject.DestroyImmediate(colorPickerTexture, true);
            UnityEngine.GameObject.DestroyImmediate(chosenColorTexture, true);
            UnityEngine.GameObject.DestroyImmediate(currentColorTexture, true);
            callbackForChosenColor(chosenColor);
            this.dismiss();
        }
    }
}

 

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...