balance_wheel/IrrExtensions/gui/GUIColorEditBox.cpp

517 lines
11 KiB
C++

// (c) 2014 Nicolaus Anderson
#include "GUIColorEditBox.h"
#include <IGUISkin.h>
#include <IGUIFont.h>
namespace irr {
namespace gui {
GUIColorEditBox::GUIColorEditBox(
IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id
)
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, color(0xff000000)
, cursorColor(0x0000ddff)
, cursorIdx(0)
, cursorRect(0,0,0,0)
, focusTime(0)
{
Text = L"ff000000";
}
GUIColorEditBox::~GUIColorEditBox()
{}
SColor GUIColorEditBox::getColor()
{
return color;
}
void GUIColorEditBox::setColor( SColor pColor, bool notifyParent )
{
color = pColor;
convertColorToText();
if ( Parent && notifyParent )
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_EDITBOX_CHANGED;
Parent->OnEvent(newEvent);
}
}
void
GUIColorEditBox::setText(const wchar_t* text)
{
Text = text;
if ( Text.size() > 6 ) {
Text = Text.subString(0,6);
}
u32 i=0;
for (; i < 6; ++i) {
if ( Text[i] < '0' )
Text[i] = '0';
else if ( Text[i] > 'f' )
Text[i] = 'f';
}
convertTextToColor();
}
bool GUIColorEditBox::OnEvent( const SEvent& event )
{
SEvent newEvent;
if ( isEnabled() && isVisible() )
switch( event.EventType )
{
case EET_MOUSE_INPUT_EVENT:
if ( event.MouseInput.isLeftPressed() )
return setCursorIndexFromPosition(
vector2di(event.MouseInput.X, event.MouseInput.Y)
);
return false;
case EET_KEY_INPUT_EVENT:
if ( event.KeyInput.PressedDown )
if ( insertChar( event.KeyInput.Key, event.KeyInput.Char ) )
{
if ( Parent )
{
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_EDITBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
switch ( event.GUIEvent.EventType )
{
case EGET_ELEMENT_FOCUSED:
updateCursorRect();
break;
case EGET_ELEMENT_FOCUS_LOST:
break;
default: break;
}
default: break;
}
return IGUIElement::OnEvent(event);
}
void GUIColorEditBox::draw()
{
if ( !isVisible() )
return;
IGUISkin* skin = Environment->getSkin();
if ( Environment->getFocus() == this )
{
skin->draw3DSunkenPane(
this,
skin->getColor(EGDC_EDITABLE),
true, true,
AbsoluteRect, &AbsoluteClippingRect );
skin->getFont(irr::gui::EGDF_DEFAULT)->draw(
Text,
AbsoluteRect,
skin->getColor(EGDC_BUTTON_TEXT),
true, true, // center
&AbsoluteClippingRect
);
// Draw transitioning-color cursor
u32 ft = focusTime % 1000;
if ( ft > 500 )
{
ft = 1000 - ft;
}
ft /= 4;
cursorColor.setAlpha( core::clamp( ft, (u32)0, (u32)255 ) );
recti cR = cursorRect + AbsoluteRect.UpperLeftCorner;
skin->draw2DRectangle(
this,
cursorColor,
cR,
&AbsoluteClippingRect
);
} else {
skin->draw3DSunkenPane(
this,
skin->getColor(EGDC_GRAY_EDITABLE),
true, true,
AbsoluteRect, &AbsoluteClippingRect );
// Draw grayed text
skin->getFont()->draw(
Text,
AbsoluteRect,
skin->getColor(EGDC_GRAY_TEXT),
true, true, // center
&AbsoluteClippingRect
);
}
}
void GUIColorEditBox::OnPostRender(u32 timeMs)
{
focusTime = timeMs;
}
bool GUIColorEditBox::setCursorIndexFromPosition( vector2di pPos )
{
// Actual location
vector2di cursorPos = pPos - AbsoluteRect.UpperLeftCorner;
if ( ! AbsoluteClippingRect.isPointInside( pPos ) )
return false;
// Calculate by starting with the start position
dimension2du textSize = Environment->getSkin()->getFont()->getDimension(Text.c_str());
cursorPos.X -= (AbsoluteRect.getWidth() - textSize.Width)/2;
cursorPos.Y -= (AbsoluteRect.getHeight() - textSize.Height)/2;
// Cursor must be in text area
if ( cursorPos.X < 0 || (u32)cursorPos.X >= textSize.Width
|| cursorPos.Y < 0 || (u32)cursorPos.Y >= textSize.Height)
{
return false;
}
// KEEP for FAST version
//cursorIdx = u32( (cursorPos.X * 8) / textSize.Width );
cursorIdx = Environment->getSkin()->getFont()->getCharacterFromPos(Text.c_str(), cursorPos.X);
updateCursorRect();
return true;
}
void GUIColorEditBox::updateCursorRect()
{
dimension2du textSize = Environment->getSkin()->getFont()->getDimension(Text.c_str());
vector2di center( RelativeRect.getWidth(), RelativeRect.getHeight() );
center /= 2;
vector2di start = center - vector2di( textSize.Width/2, textSize.Height/2 );
// KEEP THIS FOR FASTER CODE
//cursorRect.UpperLeftCorner.X = start.X + (textSize.Width * cursorIdx)/8 - 1;
//cursorRect.UpperLeftCorner.Y = start.Y;
//cursorRect.LowerRightCorner.X = start.X + (textSize.Width * (cursorIdx+1))/8;
//cursorRect.LowerRightCorner.Y = start.Y + textSize.Height;
s32 indexCoord = 0;
s32 lastIndexCoord = 0;
core::stringw shortText;
if ( cursorIdx > 0 )
{
shortText = Text.subString(0,cursorIdx);
indexCoord = Environment->getSkin()->getFont()->getDimension( shortText.c_str() ).Width;
}
shortText = Text.subString(cursorIdx,1);
lastIndexCoord = Environment->getSkin()->getFont()->getDimension( shortText.c_str() ).Width;
cursorRect.UpperLeftCorner.X = start.X + indexCoord;
cursorRect.UpperLeftCorner.Y = start.Y;
cursorRect.LowerRightCorner.X = start.X + indexCoord + lastIndexCoord;
cursorRect.LowerRightCorner.Y = start.Y + textSize.Height;
//cursorRect.repair(); // Causes (a bug:) box to not appear when cursoxIdx>5
}
bool GUIColorEditBox::insertChar( EKEY_CODE pKeyCode, wchar_t pKey )
{
u32 cursorByte = (7-cursorIdx)*4;
//u32 savedColor = color.color & ( 0xffffffff ^ (0xf0000000 >> cursorByte) );
u32 savedColor = color.color & ( ~ ( 0x0000000f << cursorByte ) );
// Some systems (e.g. X11) fill event.KeyCode.Char correctly for NumPad but still pass the same KeyCode
// as if NumLock were off.
if ( pKey == 0 ) {
switch ( pKeyCode )
{
// Cursor movement
case KEY_HOME:
cursorIdx = 0;
updateCursorRect();
return true;
case KEY_END:
cursorIdx = 7;
updateCursorRect();
return true;
case KEY_DELETE:
clear();
cursorIdx = 0;
updateCursorRect();
return true;
case KEY_LEFT:
if ( cursorIdx > 0 )
--cursorIdx;
updateCursorRect();
return true;
case KEY_RIGHT:
if ( cursorIdx < 7 )
++cursorIdx;
updateCursorRect();
return true;
default:
return false;
}
}
u32 c_bit;
if ( pKey >= L'0' && pKey <= '9' ) {
c_bit = (u32) pKey - L'0';
color.color = (c_bit << cursorByte) | savedColor;
Text[cursorIdx] = pKey;
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
}
switch ( pKeyCode )
{
/*
// Inserting characters
case KEY_KEY_0:
case KEY_NUMPAD0:
color.color = savedColor;
Text[cursorIdx] = '0';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_1:
case KEY_NUMPAD1:
color.color = (1 << cursorByte) | savedColor;
Text[cursorIdx] = '1';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_2:
case KEY_NUMPAD2:
color.color = (2 << cursorByte) | savedColor;
Text[cursorIdx] = '2';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_3:
case KEY_NUMPAD3:
color.color = (3 << cursorByte) | savedColor;
Text[cursorIdx] = '3';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_4:
case KEY_NUMPAD4:
color.color = (4 << cursorByte) | savedColor;
Text[cursorIdx] = '4';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_5:
case KEY_NUMPAD5:
color.color = (5 << cursorByte) | savedColor;
Text[cursorIdx] = '5';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_6:
case KEY_NUMPAD6:
color.color = (6 << cursorByte) | savedColor;
Text[cursorIdx] = '6';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_7:
case KEY_NUMPAD7:
color.color = (7 << cursorByte) | savedColor;
Text[cursorIdx] = '7';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_8:
case KEY_NUMPAD8:
color.color = (8 << cursorByte) | savedColor;
Text[cursorIdx] = '8';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_9:
case KEY_NUMPAD9:
color.color = (9 << cursorByte) | savedColor;
Text[cursorIdx] = '9';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
*/
case KEY_KEY_A:
// same as: color.color = (0xa0 << cursorByte) | savedColor;
color.color = (10 << cursorByte) | savedColor;
Text[cursorIdx] = 'a';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_B:
color.color = (11 << cursorByte) | savedColor;
Text[cursorIdx] = 'b';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_C:
color.color = (12 << cursorByte) | savedColor;
Text[cursorIdx] = 'c';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_D:
color.color = (13 << cursorByte) | savedColor;
Text[cursorIdx] = 'd';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_E:
color.color = (14 << cursorByte) | savedColor;
Text[cursorIdx] = 'e';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_F:
color.color = (15 << cursorByte) | savedColor;
Text[cursorIdx] = 'f';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
default: break;
}
return false;
}
void GUIColorEditBox::convertTextToColor()
{
color.color = 0;
u32 i;
if ( Text.size() != 8 ) Text = L"ff000000"; // User used setText(), so fix it.
for ( i=0; i < 8; i++ )
{
if ( Text[i] <= 'f' && Text[i] >= 'a' )
color.color |= (Text[i] - 'a' + 10) >> (i*4);
else if ( Text[i] <= '9' && Text[i] >= '0' )
color.color |= (Text[i] - '0') >> (i*4);
// else
// User must have used setText()
}
}
void GUIColorEditBox::convertColorToText()
{
u32 i;
u8 chr;
if ( Text.size() != 8 ) Text = L"ff000000"; // User used setText(), so fix it.
for ( i=0; i < 8; i++ )
{
/* On this computer, when going FROM u32 TO u8, you have to shift the
bits to the right. I will probably need to have this check for endianess
if this is going to be portable code. */
chr = u8( ( color.color & (0xf0000000 >> (i*4)) ) >> ((7-i)*4) );
if ( chr > 9 )
Text[i] = c8( (chr-10) + 'a' );
else
Text[i] = c8( chr + '0' );
}
}
void GUIColorEditBox::clear()
{
color.color = 0;
Text = L"00000000";
}
void GUIColorEditBox::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::serializeAttributes(out,options);
out->addColor("Color", color);
}
void GUIColorEditBox::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::deserializeAttributes(in,options);
bool notifyParentOfEvent = false;
if ( in->existsAttribute("NotifyParentOfColorChange") ) {
notifyParentOfEvent = in->getAttributeAsBool("NotifyParentOfColorChange");
}
// Override setText()
if ( in->existsAttribute("Color") ) {
setColor( in->getAttributeAsColor("Color", color), notifyParentOfEvent );
}
}
}
}