Color picker gui

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.

Color picker gui

Postby Ovan » Mon Dec 22, 2014 1:23 am

plop everyone I developpe a small, minimalist and cute color picker pane to replace the internal irrlicht IGUIColorSelectDialog that is really poor
for once I share my code so:

Image Image

cpp Code: Select all
#ifndef __C_GUI_COLOR_PICKER_HEADER__
#define __C_GUI_COLOR_PICKER_HEADER__
 
#include <irrlicht/IGUIElement.h>
#include <irrlicht/S3DVertex.h>
 
 
/**
 * Copyright (C) <2014> <Jehan-antoine vayssade>
 * Ovan/Magun contact on irrlicht-fr.org or ovan@sleek-think.ovh
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
**/

 
namespace irr
{
    namespace gui
    {
        class IGUIButton;
        class IGUIStaticText;
        class IGUIScrollBar;
 
        class CGUIColorPicker : public IGUIElement
        {
            public:
                CGUIColorPicker(IGUIEnvironment *environment, IGUIElement *parent, s32 id = 0) noexcept;
                ~CGUIColorPicker() noexcept;
 
                virtual void setRelativePosition(const core::recti &r);
 
                virtual bool OnEvent(const SEvent&) noexcept;
                virtual void updateAbsolutePosition();
 
                virtual void setPickedColor(const video::SColor&) noexcept;
                virtual const video::SColor& getPickedColor() const noexcept;
 
                virtual void setBackgroundColor(const video::SColor&) noexcept;
                virtual const video::SColor& getBackgroundColor() const noexcept;
 
                virtual void draw();
            protected:
                bool isGradient, isColor, isInside;
                virtual void recalculatePickedColor() noexcept;
                virtual void createAlphaTexture() noexcept;
                virtual void createGradientTexture() noexcept;
            protected:
                IGUIButton      *close;
                IGUIScrollBar   *scroll;
                video::ITexture *img[2];
            protected:
                video::SColor    pickcolor, color;
                video::SColor    background, white, black, alpha;
                core::recti      box, pickbox, gradient;
                core::vector2di  pickpos;
                int              colorpos;
        };
    }
}
 
#endif

cpp Code: Select all
#include "CGUIColorPicker.h"
 
#include <irrlicht/IGUIEnvironment.h>
#include <irrlicht/IGUIButton.h>
#include <irrlicht/IGUIScrollBar.h>
#include <irrlicht/IVideoDriver.h>
#include <irrlicht/irrMath.h>
#include <irrlicht/SColor.h>
 
namespace irr
{
    inline core::vector3df RGBftoHSV(const video::SColorf &rgb)
    {
        core::vector3df hsv;
 
        f32 M = core::max_(rgb.getRed(), rgb.getGreen(), rgb.getBlue());
        f32 m = core::min_(rgb.getRed(), rgb.getGreen(), rgb.getBlue());
        f32 C = M - m;
 
        if(C == 0)
            hsv.X = 0;
        else if(M <= rgb.getRed())
            hsv.X =((rgb.getGreen() - rgb.getBlue()) / C);
        else if(M <= rgb.getGreen())
            hsv.X =((rgb.getBlue() - rgb.getRed()) / C) + 2;
        else if(M <= rgb.getBlue())
            hsv.X =((rgb.getRed() - rgb.getGreen()) / C) + 4;
 
        hsv.X *= 60;
        if(hsv.X < 0)
            hsv.X += 360;
 
        hsv.Y = M;
 
        if(hsv.Y == 0) hsv.Z = 0;
        else hsv.Z = C / hsv.Y;
 
        return hsv;
    }
    namespace gui
    {
        CGUIColorPicker::CGUIColorPicker(IGUIEnvironment *environment, IGUIElement *parent, s32 id) noexcept
            : IGUIElement(EGUIET_COLOR_SELECT_DIALOG , environment, parent, id, {200, 200, 310, 360}),
              background{64, 255, 255, 255}, white{255, 255, 255, 255}, black{255, 0, 0, 0},
              colorpos(0), isGradient(false), isColor(false)
        {
            close = Environment->addButton({5, 140, 85, 156}, this, 0, L"take this color");
 
            scroll = Environment->addScrollBar(true, {5, 125, 85, 135}, this);
            scroll->setMin(0);
            scroll->setMax(255);
            scroll->setPos(255);
 
            createAlphaTexture();
            createGradientTexture();
 
            setPickedColor({255, 64, 64, 128});
            updateAbsolutePosition();
        }
        CGUIColorPicker::~CGUIColorPicker() noexcept
        {
            close->drop();
            scroll->drop();
            img[0]->drop();
            img[1]->drop();
        }
        void CGUIColorPicker::createAlphaTexture() noexcept
        {
            img[0] = Environment->getVideoDriver()->addTexture({16, 16}, "alpha", video::ECF_A8R8G8B8);
            u32 *tmp = (u32*) img[0]->lock();
 
            video::SColor color;
 
            #define square(colorstart, sx, sy, sz, sw)                         \
                color = colorstart;                                            \
                for(int y=sy; y<sw; ++y)                                       \
                    for(int x=sx; x<sz; ++x)                                   \
                        color.getData(&tmp[x + y*16], video::ECF_A8R8G8B8);    \

            square(video::SColor(255, 153, 153, 153), 0, 0,  8,  8);
            square(video::SColor(255, 153, 153, 153), 8, 8, 16, 16);
            square(video::SColor(255, 102, 102, 102), 8, 0, 16,  8);
            square(video::SColor(255, 102, 102, 102), 0, 8,  8, 16);
 
            img[0]->unlock();
        }
        void CGUIColorPicker::createGradientTexture() noexcept
        {
            img[1] = Environment->getVideoDriver()->addTexture({15, 151}, "gradient", video::ECF_A8R8G8B8);
            u32 *tmp = (u32*) img[1]->lock();
 
            video::SColor from;
            video::SColor to;
 
            #define interpolate(colorstart, colorend, start, end)              \
                from = colorstart;                                             \
                to = colorend;                                                 \
                                                                               \
                for(int y=start; y<end; ++y)                                   \
                {                                                              \
                    video::SColor c = to.getInterpolated(from, (y-start)/25.f);\
                    for(int x=0; x<15; ++x)                                    \
                        c.getData(&tmp[x + y*15], video::ECF_A8R8G8B8);        \
                }

 
            interpolate(video::SColor(255, 255, 0, 0),   video::SColor(255, 255, 0, 255),   0,  25);
            interpolate(video::SColor(255, 255, 0, 255), video::SColor(255, 0, 0, 255),    25,  50);
 
            interpolate(video::SColor(255, 0, 0, 255), video::SColor(255, 0, 255, 255),  50,  75);
            interpolate(video::SColor(255, 0, 255, 255), video::SColor(255, 0, 255, 0),  75, 100);
 
            interpolate(video::SColor(255, 0, 255, 0), video::SColor(255, 255, 255, 0), 100, 125);
            interpolate(video::SColor(255, 255, 255, 0), video::SColor(255, 255, 0, 0), 125, 151);
 
            img[1]->unlock();
        }
        void CGUIColorPicker::setRelativePosition(const core::recti &r)
        {
            RelativeRect.UpperLeftCorner = r.UpperLeftCorner;
            RelativeRect.LowerRightCorner.X = r.UpperLeftCorner.X + 110;
            RelativeRect.LowerRightCorner.Y = r.UpperLeftCorner.X + 160;
        }
        bool CGUIColorPicker::OnEvent(const SEvent &event) noexcept
        {
            if(event.EventType == EET_MOUSE_INPUT_EVENT)
            {
                core::vector2di pos(event.MouseInput.X, event.MouseInput.Y);
 
                if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
                {
                    isGradient = gradient.isPointInside(pos);
                    isColor = box.isPointInside(pos);
                    isInside = AbsoluteRect.isPointInside(pos);
                }
 
                if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
                {
                    // does not work since 1.7 (i think)
                    // probably need CGUIModalScreen if this module is add to the engine
                    //if(!AbsoluteRect.isPointInside(pos) && !isInside)
                    //{
                    //    SEvent event;
                    //    event.EventType = EET_GUI_EVENT;
                    //    event.GUIEvent.Caller = this;
                    //    event.GUIEvent.Element = 0;
                    //    event.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
                    //    Parent->OnEvent(event);
                    //    remove();
                    //    drop();
                    //}
                    isGradient = isColor = false;
                }
 
                if(isGradient)
                {
                    if(pos.X < gradient.UpperLeftCorner.X)
                        pos.X = gradient.UpperLeftCorner.X;
                    if(pos.Y < gradient.UpperLeftCorner.Y)
                        pos.Y = gradient.UpperLeftCorner.Y;
 
                    if(pos.X > gradient.LowerRightCorner.X)
                        pos.X = gradient.LowerRightCorner.X;
                    if(pos.Y > gradient.LowerRightCorner.Y)
                        pos.Y = gradient.LowerRightCorner.Y;
 
                    colorpos = pos.Y - gradient.UpperLeftCorner.Y;
                    u32 *tmp =(u32*)img[1]->lock();
                    color.set(tmp[colorpos*img[1]->getOriginalSize().Width]);
                    img[1]->unlock();
                    recalculatePickedColor();
                }
 
                if(isColor)
                {
                    if(pos.X < box.UpperLeftCorner.X)
                        pos.X = box.UpperLeftCorner.X;
                    if(pos.Y < box.UpperLeftCorner.Y)
                        pos.Y = box.UpperLeftCorner.Y;
 
                    if(pos.X > box.LowerRightCorner.X)
                        pos.X = box.LowerRightCorner.X;
                    if(pos.Y > box.LowerRightCorner.Y)
                        pos.Y = box.LowerRightCorner.Y;
 
                    pickpos.X = pos.X - box.UpperLeftCorner.X;
                    pickpos.Y = pos.Y - box.UpperLeftCorner.Y;
                    recalculatePickedColor();
                }
 
                if(isGradient || isColor)
                    return true;
            }
 
            if(event.EventType == EET_GUI_EVENT)
            {
                switch(event.GUIEvent.EventType)
                {
                    case EGET_BUTTON_CLICKED:
                        SEvent event;
                        event.EventType = EET_GUI_EVENT;
                        event.GUIEvent.Caller = this;
                        event.GUIEvent.Element = 0;
                        event.GUIEvent.EventType = EGET_FILE_SELECTED;
                        Parent->OnEvent(event);
                    break;
                    case EGET_SCROLL_BAR_CHANGED:
                        recalculatePickedColor();
                        return true;
                    break;
                }
            }
 
            return IGUIElement::OnEvent(event);
        }
        void CGUIColorPicker::recalculatePickedColor() noexcept
        {
            video::SColor hcolor = color.getInterpolated(white, pickpos.X/80.f);
 
            pickcolor = black.getInterpolated(hcolor, pickpos.Y/80.f);
            pickcolor.setAlpha(scroll->getPos());
 
            alpha = color;
            alpha.setAlpha(0);
        }
        void CGUIColorPicker::setPickedColor(const video::SColor &c) noexcept
        {
            pickcolor = c;
 
            core::vector3df hsv = RGBftoHSV({
                c.getRed()/255.f,
                c.getGreen()/255.f,
                c.getBlue()/255.f,
                c.getAlpha()/255.f
            });
 
            colorpos = 150-hsv.X/360.f*150.f;
            pickpos.X = hsv.Y*80.f;
            pickpos.Y = 80-(hsv.Z)*80.f;
 
            u32 *tmp =(u32*)img[1]->lock();
            color.set(tmp[colorpos*img[1]->getOriginalSize().Width]);
            img[1]->unlock();
 
            alpha = color;
            alpha.setAlpha(0);
        }
        const video::SColor& CGUIColorPicker::getPickedColor() const noexcept
        {
            return pickcolor;
        }
        void CGUIColorPicker::setBackgroundColor(const video::SColor &b) noexcept
        {
            background = b;
        }
        const video::SColor& CGUIColorPicker::getBackgroundColor() const noexcept
        {
            return background;
        }
        void CGUIColorPicker::updateAbsolutePosition()
        {
            IGUIElement::updateAbsolutePosition();
 
            box.UpperLeftCorner = AbsoluteRect.UpperLeftCorner;
            box.LowerRightCorner = AbsoluteRect.UpperLeftCorner;
            box.UpperLeftCorner.X += 5;
            box.UpperLeftCorner.Y += 5;
            box.LowerRightCorner.X += 85;
            box.LowerRightCorner.Y += 85;
 
            gradient.UpperLeftCorner = AbsoluteRect.UpperLeftCorner;
            gradient.LowerRightCorner = AbsoluteRect.UpperLeftCorner;
            gradient.UpperLeftCorner.X += 90;
            gradient.UpperLeftCorner.Y += 5;
            gradient.LowerRightCorner.X += 105;
            gradient.LowerRightCorner.Y += 155;
 
            pickbox.UpperLeftCorner = AbsoluteRect.UpperLeftCorner;
            pickbox.LowerRightCorner = AbsoluteRect.UpperLeftCorner;
            pickbox.UpperLeftCorner.X += 5;
            pickbox.UpperLeftCorner.Y += 90;
            pickbox.LowerRightCorner.X += 85;
            pickbox.LowerRightCorner.Y += 120;
        }
        void CGUIColorPicker::draw()
        {
            Environment->getSkin()->draw3DSunkenPane(
                this, background,
                false, true,
                AbsoluteRect,
                &AbsoluteClippingRect
            );
 
            IGUIElement::draw();
 
            Environment->getVideoDriver()->draw2DImage(img[1], {
                AbsoluteRect.UpperLeftCorner.X+90,
                AbsoluteRect.UpperLeftCorner.Y+5
            });
 
            // 2 draw because the interpolation in the diagonal is not well rendered
            Environment->getVideoDriver()->draw2DRectangle(black, box, &AbsoluteClippingRect);
            Environment->getVideoDriver()->draw2DRectangle(box, white, color, alpha, alpha, &AbsoluteClippingRect);
 
            {
                const core::vector2di start =  {AbsoluteRect.UpperLeftCorner.X+90,  AbsoluteRect.UpperLeftCorner.Y+5+colorpos};
                const core::vector2di end =    {AbsoluteRect.UpperLeftCorner.X+105,  AbsoluteRect.UpperLeftCorner.Y+5+colorpos};
                const core::vector2di hstart = {box.UpperLeftCorner.X,  box.UpperLeftCorner.Y+pickpos.Y};
                const core::vector2di hend =   {box.LowerRightCorner.X, box.UpperLeftCorner.Y+pickpos.Y};
                const core::vector2di vstart = {box.UpperLeftCorner.X+pickpos.X, box.UpperLeftCorner.Y};
                const core::vector2di vend =   {box.UpperLeftCorner.X+pickpos.X, box.LowerRightCorner.Y};
 
                Environment->getVideoDriver()->draw2DLine({ start.X,    start.Y-1}, { end.X,    end.Y-1}, white);
                Environment->getVideoDriver()->draw2DLine({ start.X,    start.Y+1}, { end.X,    end.Y+1}, white);
                Environment->getVideoDriver()->draw2DLine({hstart.X,   hstart.Y-1}, {hend.X,   hend.Y-1}, white);
                Environment->getVideoDriver()->draw2DLine({hstart.X,   hstart.Y+1}, {hend.X,   hend.Y+1}, white);
                Environment->getVideoDriver()->draw2DLine({vstart.X-1,   vstart.Y}, {vend.X-1, vend.Y  }, white);
                Environment->getVideoDriver()->draw2DLine({vstart.X+1,   vstart.Y}, {vend.X+1, vend.Y  }, white);
 
                Environment->getVideoDriver()->draw2DLine(start,   end, black);
                Environment->getVideoDriver()->draw2DLine(hstart, hend, black);
                Environment->getVideoDriver()->draw2DLine(vstart, vend, black);
            }
 
            Environment->getVideoDriver()->draw2DImage(img[0], pickbox, pickbox);
            Environment->getVideoDriver()->draw2DRectangle(
                pickcolor, pickbox,
                &AbsoluteClippingRect
            );
        }
    }
}

in accordance with that of irrlicht EGET_FILE_SELECTED is return "take this color" is clicked

my original post at http://irrlicht-fr.org/viewtopic.php?pid=11560 ;)
Last edited by Ovan on Tue Dec 23, 2014 10:44 pm, edited 2 times in total.
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Re: Color picker gui

Postby Seven » Mon Dec 22, 2014 1:14 pm

Awesome!
Seven
 
Posts: 875
Joined: Mon Nov 14, 2005 2:03 pm

Re: Color picker gui

Postby CuteAlien » Mon Dec 22, 2014 2:15 pm

Hi, could you consider putting this code under the zlib-license? The current color-picker in the engine never worked, so I would be glad if we had a replacement. I haven't tested this yet, but looks nice from screenshots, so maybe we could replace the one in the engine.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8362
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Color picker gui

Postby Ovan » Mon Dec 22, 2014 2:45 pm

yes off course (I hoped this)
I edit my previous message to add the licence on the header (it's good?)
can need some minor rewrite i use brace-initialization of c++11 feature
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Re: Color picker gui

Postby CuteAlien » Mon Dec 22, 2014 5:10 pm

Thanks! I suppose header is good. Although in Irrlicht we tend to just mention that the license is beside the sources, I hope that's fine. I will also have to do some minor rewrites before adding it (Irrlicht style slightly different and maybe we can replace the define by some function or even have one for that already). But that's minor stuff. I'll try to find some time to add it in the new year (probably no time before that).
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8362
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Color picker gui

Postby Ovan » Mon Dec 22, 2014 5:48 pm

Cool :)
you can add CGUIModalScreen or something similar when is created by IGUIEnvironment ?
make it as "popup" element if is add as modal, would be useful
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Re: Color picker gui

Postby CuteAlien » Mon Dec 22, 2014 6:38 pm

Yeah, old one also had a flag for that.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8362
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Color picker gui

Postby hendu » Mon Dec 22, 2014 8:37 pm

OT: Who named the function getData, when it clearly *puts* data... :P
hendu
 
Posts: 2587
Joined: Sat Dec 18, 2010 12:53 pm

Re: Color picker gui

Postby Ovan » Mon Dec 22, 2014 9:47 pm

http://irrlicht.sourceforge.net/docu/cl ... f28be96bc9
no it does not put data it really get data from color to a ptr memory and here this memory is the texture at coord [x, y]

same if you write

irr::u32 i;
color.getData(&i, ...);
Last edited by Ovan on Tue Dec 23, 2014 3:12 pm, edited 1 time in total.
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Re: Color picker gui

Postby hendu » Tue Dec 23, 2014 8:05 am

No, it doesn't get anything. It writes the color value into the data pointer. Getting would mean "get the color data *from* this pointer".
hendu
 
Posts: 2587
Joined: Sat Dec 18, 2010 12:53 pm

Re: Color picker gui

Postby CuteAlien » Tue Dec 23, 2014 3:00 pm

It's correct. Getter functions in classes are about getting the data from the class. The data pointer is the target. It doesn't matter if the target is an lvalue or a reference or a pointer into which to write the result - it's always a getter function. This way the name tells you some information which is not as easy visible on first view when looking at the function declaration.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8362
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Color picker gui

Postby hendu » Tue Dec 23, 2014 8:29 pm

I still think it's poorly named. getDataInto would be far more understandable if putData is against the irr style. Has it been in a release yet?
hendu
 
Posts: 2587
Joined: Sat Dec 18, 2010 12:53 pm

Re: Color picker gui

Postby ent1ty » Tue Dec 23, 2014 9:57 pm

Looks like the RGBftoHSV function is from my snippet here. If it makes into the engine, acknowledgement would be nice :P
irrRenderer 1.0
Height2Normal v. 2.1 - convert height maps to normal maps

Step back! I have a void pointer, and I'm not afraid to use it!
User avatar
ent1ty
Competition winner
 
Posts: 1106
Joined: Sun Nov 08, 2009 11:09 am

Re: Color picker gui

Postby Ovan » Tue Dec 23, 2014 10:42 pm

yeah sorry to not mention your code, I forget and thanks ;)

and no hendu, this name is clearly the right name it's the same thing if you write
void getSquare(int x, int *result) { *result = x*x; }
void getSquare(int x, int &result) { result = x*x;}
int getSquare(int x) { return x*x; }
all 3 function do the same thing, (in old C style "getSquare(int x, int *result)" is highly used)
and in this case for SColor a ptr is needed because the size of the returned value can change (due to E_COLOR_FORMAT)

getter function mean you get from the object (here is color) not from the parameter, the parameter is clearly the returned value
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Re: Color picker gui

Postby hendu » Fri Dec 26, 2014 4:14 pm

Logically a C style function would be "int getSquare(int)", returning it. Having a random result pointer without a different name would be confusing.

Like in this case, a reader may read it as "get data *into* this SColor from this pointer" like I did. It is not clear without changing the name, because we have 99% of getFoo functions that return the value.

edit:

Its pair, setData, has the same confusion. It can be read either way, set data from this SColor to the pointer, or from the pointer to this SColor. setDataFrom and getDataInto would clear both up.
hendu
 
Posts: 2587
Joined: Sat Dec 18, 2010 12:53 pm

Next

Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest