// Copyright (C) 2002-2012 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CGUIColorSelectDialog.h" #ifdef _IRR_COMPILE_WITH_GUI_ #include "IGUISkin.h" #include "IGUIEnvironment.h" #include "IVideoDriver.h" #include "IGUIButton.h" #include "IGUIStaticText.h" #include "IGUIFont.h" #include "IGUISpriteBank.h" #include "IFileList.h" #include "os.h" #include "fast_atof.h" namespace irr { namespace gui { const s32 CSD_WIDTH = 350; const s32 CSD_HEIGHT = 300; namespace { struct subElementPredefines { const wchar_t *pre; const wchar_t *init; const wchar_t *post; int x, y; int range_down ,range_up; }; static const subElementPredefines Template [] = { { L"A:", L"0", 0,50,165, 0, 255 }, { L"R:", L"0", 0,20,205, 0, 255 }, { L"G:", L"0", 0,20,230, 0, 255 }, { L"B:", L"0", 0,20,255, 0, 255 }, { L"H:", L"0", L"°",80,205, 0, 360 }, { L"S:", L"0", L"%",80,230, 0, 100 }, { L"L:", L"0", L"%",80,255, 0, 100 }, }; } //! constructor CGUIColorSelectDialog::CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id) : IGUIColorSelectDialog(environment, parent, id, core::rect((parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2, (parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2, (parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2+CSD_WIDTH, (parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2+CSD_HEIGHT)), Dragging(false) { #ifdef _DEBUG IGUIElement::setDebugName("CGUIColorSelectDialog"); #endif Text = title; IGUISkin* skin = Environment->getSkin(); const s32 buttonw = environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH); const s32 posx = RelativeRect.getWidth() - buttonw - 4; CloseButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close"); if (skin && skin->getSpriteBank()) { CloseButton->setSpriteBank(skin->getSpriteBank()); CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL)); CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL)); } CloseButton->setSubElement(true); CloseButton->setTabStop(false); CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); CloseButton->grab(); OKButton = Environment->addButton( core::rect(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50), this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK"); OKButton->setSubElement(true); OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); OKButton->grab(); CancelButton = Environment->addButton( core::rect(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75), this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel"); CancelButton->setSubElement(true); CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); CancelButton->grab(); video::IVideoDriver* driver = Environment->getVideoDriver(); ColorRing.Texture = driver->getTexture ( "#colorring" ); if ( 0 == ColorRing.Texture ) { buildColorRing(core::dimension2d(128, 128), 1, Environment->getSkin()->getColor(EGDC_3D_SHADOW)); } core::rect r(20,20, 0,0); ColorRing.Control = Environment->addImage(ColorRing.Texture, r.UpperLeftCorner, true, this); ColorRing.Control->setSubElement(true); ColorRing.Control->grab(); for ( u32 i = 0; i != sizeof (Template) / sizeof ( subElementPredefines ); ++i ) { if ( Template[i].pre ) { r.UpperLeftCorner.X = Template[i].x; r.UpperLeftCorner.Y = Template[i].y; r.LowerRightCorner.X = r.UpperLeftCorner.X + 15; r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; IGUIElement *t = Environment->addStaticText(Template[i].pre, r, false, false, this); t->setSubElement(true); } if ( Template[i].post ) { r.UpperLeftCorner.X = Template[i].x + 56; r.UpperLeftCorner.Y = Template[i].y; r.LowerRightCorner.X = r.UpperLeftCorner.X + 15; r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; IGUIElement *t = Environment->addStaticText( Template[i].post, r, false, false, this); t->setSubElement(true); } r.UpperLeftCorner.X = Template[i].x + 15; r.UpperLeftCorner.Y = Template[i].y-2; r.LowerRightCorner.X = r.UpperLeftCorner.X + 40; r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; gui::IGUISpinBox* spin = Environment->addSpinBox( Template[i].init, r, true, this); spin->setSubElement(true); spin->setDecimalPlaces(0); spin->setRange((f32)Template[i].range_down, (f32)Template[i].range_up); spin->grab(); Battery.push_back(spin); } bringToFront(CancelButton); bringToFront(OKButton); } //! destructor CGUIColorSelectDialog::~CGUIColorSelectDialog() { if (CloseButton) CloseButton->drop(); if (OKButton) OKButton->drop(); if (CancelButton) CancelButton->drop(); for (u32 i = 0; i != Battery.size(); ++i) Battery[i]->drop(); if (ColorRing.Control) ColorRing.Control->drop(); } //! renders a antialiased, colored ring void CGUIColorSelectDialog::buildColorRing( const core::dimension2d & dim, s32 supersample, const video::SColor& borderColor ) { const core::dimension2d d(dim.Width * supersample, dim.Height * supersample); video::IVideoDriver* driver = Environment->getVideoDriver(); video::IImage *RawTexture = driver->createImage(video::ECF_A8R8G8B8, d); RawTexture->fill ( 0x00808080 ); const s32 radiusOut = ( d.Width / 2 ) - 4; const s32 fullR2 = radiusOut * radiusOut; video::SColorf rgb(0,0,0); video::SColorHSL hsl; hsl.Luminance = 50; hsl.Saturation = 100; core::position2d p; for ( p.Y = -radiusOut; p.Y <= radiusOut; p.Y += 1 ) { s32 y2 = p.Y * p.Y; for (p.X = -radiusOut; p.X <= radiusOut; p.X += 1) { s32 r2 = y2 + ( p.X * p.X ); // test point in circle s32 testa = r2 - fullR2; if ( testa < 0 ) { // dotproduct u ( x,y ) * v ( 1, 0 ) = cosinus(a) const f32 r = sqrtf((f32) r2); // normalize, dotproduct = xnorm const f32 xn = r == 0.f ? 0.f : -p.X * core::reciprocal(r); hsl.Hue = acosf(xn)*core::RADTODEG; if ( p.Y > 0 ) hsl.Hue = 360 - hsl.Hue; hsl.Hue -= 90; const f32 rTest = r / radiusOut; #if 0 if (rTest < 0.33f) { // luminance from 0 to 50 hsl.Luminance = 50*(rTest/0.33); hsl.Saturation = 0.f; hsl.toRGB(rgb); } else if ( rTest < 0.66f ) { // saturation from 0 to 100 hsl.Saturation = 100*(( rTest - 0.33f ) / 0.33f); hsl.Luminance = 50; hsl.toRGB(rgb); } else { // luminance from 50 to 100 hsl.Luminance = 100*(0.5f + ( ( rTest - 0.66f ) / .66f )); hsl.Saturation = 100; hsl.toRGB(rgb); } // borders should be slightly transparent if ( rTest >= 0.95f ) rgb.a = (1.f-rTest)*20; else rgb.a=1.f; #else if ( rTest > 0.5f ) { hsl.Saturation = 100; hsl.Luminance = 50; hsl.toRGB(rgb); } // borders should be slightly transparent if ( rTest < 0.5f ) rgb.a = 0; else if ( rTest >= 0.95f ) rgb.a = (1.f-rTest)*20; else if ( rTest <= 0.55f ) rgb.a = (rTest-0.5f)*20; else rgb.a=1.f; #endif RawTexture->setPixel(4+p.X+radiusOut, 4+p.Y+radiusOut, rgb.toSColor()); } } } if ( supersample > 1 ) { video::IImage * filter = driver->createImage(video::ECF_A8R8G8B8, dim ); RawTexture->copyToScalingBoxFilter(filter); RawTexture->drop(); RawTexture = filter; } bool generateMipLevels = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); driver->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, false); ColorRing.Texture = driver->addTexture ( "#colorring", RawTexture); RawTexture->drop(); driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, generateMipLevels); } //! called if an event happened. bool CGUIColorSelectDialog::OnEvent(const SEvent& event) { if (isEnabled()) { switch(event.EventType) { case EET_GUI_EVENT: switch(event.GUIEvent.EventType) { case EGET_SPINBOX_CHANGED: { for ( u32 i = 0; i!= Battery.size (); ++i ) { if ( event.GUIEvent.Caller == Battery[i] ) { if (i<4) { video::SColor rgb((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(), (u32)Battery[2]->getValue(), (u32)Battery[3]->getValue()); video::SColorHSL hsl; video::SColorf rgb2(rgb); hsl.fromRGB(rgb2); Battery[4]->setValue(hsl.Hue); Battery[5]->setValue(hsl.Saturation); Battery[6]->setValue(hsl.Luminance); } else { video::SColorHSL hsl(Battery[4]->getValue(), Battery[5]->getValue(), Battery[6]->getValue()); video::SColorf rgb2; hsl.toRGB(rgb2); video::SColor rgb = rgb2.toSColor(); Battery[1]->setValue((f32)rgb.getRed()); Battery[2]->setValue((f32)rgb.getGreen()); Battery[3]->setValue((f32)rgb.getBlue()); } } } return true; } case EGET_ELEMENT_FOCUS_LOST: Dragging = false; break; case EGET_BUTTON_CLICKED: if (event.GUIEvent.Caller == CloseButton || event.GUIEvent.Caller == CancelButton) { sendCancelEvent(); remove(); return true; } else if (event.GUIEvent.Caller == OKButton) { sendSelectedEvent(); remove(); return true; } break; case EGET_LISTBOX_CHANGED: case EGET_LISTBOX_SELECTED_AGAIN: default: break; } break; case EET_MOUSE_INPUT_EVENT: switch(event.MouseInput.Event) { case EMIE_LMOUSE_PRESSED_DOWN: DragStart.X = event.MouseInput.X; DragStart.Y = event.MouseInput.Y; Dragging = true; return true; case EMIE_LMOUSE_LEFT_UP: Dragging = false; return true; case EMIE_MOUSE_MOVED: if (Dragging) { // gui window should not be dragged outside its parent if (Parent) if (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 || event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 || event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 || event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1) return true; move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); DragStart.X = event.MouseInput.X; DragStart.Y = event.MouseInput.Y; return true; } default: break; } default: break; } } return IGUIElement::OnEvent(event); } //! draws the element and its children void CGUIColorSelectDialog::draw() { if (!IsVisible) return; IGUISkin* skin = Environment->getSkin(); core::rect rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), AbsoluteRect, &AbsoluteClippingRect); if (Text.size()) { rect.UpperLeftCorner.X += 2; rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5; IGUIFont* font = skin->getFont(EGDF_WINDOW); if (font) font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true, &AbsoluteClippingRect); } IGUIElement::draw(); // draw color selector after the window elements core::vector2di pos(ColorRing.Control->getAbsolutePosition().UpperLeftCorner); pos.X += ColorRing.Texture->getOriginalSize().Width/2; pos.Y += ColorRing.Texture->getOriginalSize().Height/2; #if 0 const f32 h = Battery[4]->getValue(); const f32 s = Battery[5]->getValue(); const f32 l = Battery[6]->getValue(); const f32 factor = 58.f*(((s==0)&&(l<50))?(l*0.33f/50):( (s<100)?((.33f+(s*0.33f/100))):((0.66f+(l-50)*0.33f/50)))); #else const f32 factor = 44; #endif pos.X += core::round32(sinf(Battery[4]->getValue()*core::DEGTORAD)*factor); pos.Y -= core::round32(cosf(Battery[4]->getValue()*core::DEGTORAD)*factor); Environment->getVideoDriver()->draw2DPolygon(pos, 4, 0xffffffff, 4); } video::SColor CGUIColorSelectDialog::getColor() { return video::SColor((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(), (u32)Battery[2]->getValue(), (u32)Battery[3]->getValue()); } video::SColorHSL CGUIColorSelectDialog::getColorHSL() { return video::SColorHSL(Battery[4]->getValue(), Battery[5]->getValue(), Battery[6]->getValue()); } //! sends the event that the file has been selected. void CGUIColorSelectDialog::sendSelectedEvent() { SEvent event; event.EventType = EET_GUI_EVENT; event.GUIEvent.Caller = this; event.GUIEvent.Element = 0; event.GUIEvent.EventType = EGET_FILE_SELECTED; Parent->OnEvent(event); } //! sends the event that the file choose process has been canceld void CGUIColorSelectDialog::sendCancelEvent() { SEvent event; event.EventType = EET_GUI_EVENT; event.GUIEvent.Caller = this; event.GUIEvent.Element = 0; event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED; Parent->OnEvent(event); } } // end namespace gui } // end namespace irr #endif // _IRR_COMPILE_WITH_GUI_