Buttons can now now have 7 more image-states, 1 more sprite-state and the sprites are now scaleable.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4756 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2014-04-02 21:05:39 +00:00
parent 88581a4c42
commit 5b156c1dca
7 changed files with 456 additions and 201 deletions

View File

@ -1,6 +1,7 @@
--------------------------
Changes in 1.9 (not yet released)
- Buttons can now now have 7 more image-states, 1 more sprite-state and the sprites are now scaleable.
- Spritebanks can now draw scaled sprites and are a little easier to use.
- Improved i18n key input for X11 (languages like cyrillic work now).
- Fix bug that ListBox would not allow to 'tab' to the next element (thx @ FlavourBoat for reporting)

View File

@ -20,11 +20,16 @@ namespace gui
class IGUIFont;
class IGUISpriteBank;
//! Current state of buttons used for drawing sprites.
//! Note that up to 3 states can be active at the same time:
//! EGBS_BUTTON_UP or EGBS_BUTTON_DOWN
//! EGBS_BUTTON_MOUSE_OVER or EGBS_BUTTON_MOUSE_OFF
//! EGBS_BUTTON_FOCUSED or EGBS_BUTTON_NOT_FOCUSED
enum EGUI_BUTTON_STATE
{
//! The button is not pressed
//! The button is not pressed.
EGBS_BUTTON_UP=0,
//! The button is currently pressed down
//! The button is currently pressed down.
EGBS_BUTTON_DOWN,
//! The mouse cursor is over the button
EGBS_BUTTON_MOUSE_OVER,
@ -34,12 +39,14 @@ namespace gui
EGBS_BUTTON_FOCUSED,
//! The button doesn't have the focus
EGBS_BUTTON_NOT_FOCUSED,
//! The button is disabled All other states are ignored in that case.
EGBS_BUTTON_DISABLED,
//! not used, counts the number of enumerated items
EGBS_COUNT
};
//! Names for gui button state icons
const c8* const GUIButtonStateNames[] =
const c8* const GUIButtonStateNames[EGBS_COUNT+1] =
{
"buttonUp",
"buttonDown",
@ -47,8 +54,52 @@ namespace gui
"buttonMouseOff",
"buttonFocused",
"buttonNotFocused",
0,
0,
"buttonDisabled",
0 // count
};
//! State of buttons used for drawing texture images.
//! Note that only a single state is active at a time
//! Also when no image is defined for a state it will use images from another state
//! and if that state is not set from the replacement for that,etc.
//! So in many cases setting EGBIS_IMAGE_UP and EGBIS_IMAGE_DOWN is sufficient.
enum EGUI_BUTTON_IMAGE_STATE
{
//! When no other states have images they will all use this one.
EGBIS_IMAGE_UP,
//! When not set EGBIS_IMAGE_UP is used.
EGBIS_IMAGE_UP_MOUSEOVER,
//! When not set EGBIS_IMAGE_UP_MOUSEOVER is used.
EGBIS_IMAGE_UP_FOCUSED,
//! When not set EGBIS_IMAGE_UP_FOCUSED is used.
EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER,
//! When not set EGBIS_IMAGE_UP is used.
EGBIS_IMAGE_DOWN,
//! When not set EGBIS_IMAGE_DOWN is used.
EGBIS_IMAGE_DOWN_MOUSEOVER,
//! When not set EGBIS_IMAGE_DOWN_MOUSEOVER is used.
EGBIS_IMAGE_DOWN_FOCUSED,
//! When not set EGBIS_IMAGE_DOWN_FOCUSED is used.
EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER,
//! When not set EGBIS_IMAGE_UP or EGBIS_IMAGE_DOWN are used (depending on button state).
EGBIS_IMAGE_DISABLED,
//! not used, counts the number of enumerated items
EGBIS_COUNT
};
//! Names for gui button image states
const c8* const GUIButtonImageStateNames[EGBIS_COUNT+1] =
{
"Image", // not "ImageUp" as it otherwise breaks serialization of old files
"ImageUpOver",
"ImageUpFocused",
"ImageUpFocusedOver",
"PressedImage", // not "ImageDown" as it otherwise breaks serialization of old files
"ImageDownOver",
"ImageDownFocused",
"ImageDownFocusedOver",
"ImageDisabled",
0 // count
};
//! GUI Button interface.
@ -77,38 +128,71 @@ namespace gui
font of the active skin otherwise */
virtual IGUIFont* getActiveFont() const = 0;
//! Sets an image which should be displayed on the button when it is in the given state.
/** Only one image-state can be active at a time. Images are drawn below sprites.
If a state is without image it will try to use images from other states as described
in ::EGUI_BUTTON_IMAGE_STATE.
Images are a little less flexible than sprites, but easier to use.
\param state: One of ::EGUI_BUTTON_IMAGE_STATE
\param image: Image to be displayed or NULL to remove the image
\param sourceRect: Source rectangle on the image texture. When width or height are 0 then the full texture-size is used (default). */
virtual void setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image=0, const core::rect<s32>& sourceRect=core::rect<s32>(0,0,0,0)) = 0;
//! Sets an image which should be displayed on the button when it is in normal state.
/** \param image: Image to be displayed */
/** This is identical to calling setImage(EGBIS_IMAGE_UP, image); and might be deprecated in future revisions.
\param image: Image to be displayed */
virtual void setImage(video::ITexture* image=0) = 0;
//! Sets a background image for the button when it is in normal state.
/** \param image: Texture containing the image to be displayed
\param pos: Position in the texture, where the image is located */
virtual void setImage(video::ITexture* image, const core::rect<s32>& pos) = 0;
/** This is identical to calling setImage(EGBIS_IMAGE_UP, image, sourceRect); and might be deprecated in future revisions.
\param image: Texture containing the image to be displayed
\param sourceRect: Position in the texture, where the image is located.
When width or height are 0 then the full texture-size is used */
virtual void setImage(video::ITexture* image, const core::rect<s32>& sourceRect) = 0;
//! Sets a background image for the button when it is in pressed state.
/** If no images is specified for the pressed state via
/** This is identical to calling setImage(EGBIS_IMAGE_DOWN, image); and might be deprecated in future revisions.
If no images is specified for the pressed state via
setPressedImage(), this image is also drawn in pressed state.
\param image: Image to be displayed */
virtual void setPressedImage(video::ITexture* image=0) = 0;
//! Sets an image which should be displayed on the button when it is in pressed state.
/** \param image: Texture containing the image to be displayed
\param pos: Position in the texture, where the image is located */
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) = 0;
/** This is identical to calling setImage(EGBIS_IMAGE_DOWN, image, sourceRect); and might be deprecated in future revisions.
\param image: Texture containing the image to be displayed
\param sourceRect: Position in the texture, where the image is located */
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& sourceRect) = 0;
//! Sets the sprite bank used by the button
/** NOTE: The spritebank itself is _not_ serialized so far. The sprites are serialized.
Which means after loading the gui you still have to set the spritebank manually. */
virtual void setSpriteBank(IGUISpriteBank* bank=0) = 0;
//! Sets the animated sprite for a specific button state
/** \param index: Number of the sprite within the sprite bank, use -1 for no sprite
/** Several sprites can be drawn at the same time.
Sprites can be animated.
Sprites are drawn above the images.
\param index: Number of the sprite within the sprite bank, use -1 for no sprite
\param state: State of the button to set the sprite for
\param index: The sprite number from the current sprite bank
\param color: The color of the sprite
\param loop: True if the animation should loop, false if not
*/
\param scale: True if the sprite should scale to button size, false if not */
virtual void setSprite(EGUI_BUTTON_STATE state, s32 index,
video::SColor color=video::SColor(255,255,255,255), bool loop=false) = 0;
video::SColor color=video::SColor(255,255,255,255), bool loop=false, bool scale=false) = 0;
//! Get the sprite-index for the given state or -1 when no sprite is set
virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const = 0;
//! Get the sprite color for the given state. Color is only used when a sprite is set.
virtual video::SColor getSpriteColor(EGUI_BUTTON_STATE state) const = 0;
//! Returns if the sprite in the given state does loop
virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const = 0;
//! Returns if the sprite in the given state is scaled
virtual bool getSpriteScale(EGUI_BUTTON_STATE state) const = 0;
//! Sets if the button should behave like a push button.
/** Which means it can be in two states: Normal or Pressed. With a click on the button,

View File

@ -183,14 +183,18 @@ namespace gui
EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT,
//! maximal space to reserve for messagebox text-height
EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT,
//! pixels to move the button image to the right when a pushbutton is pressed
//! pixels to move an unscaled button image to the right when a button is pressed and the unpressed image looks identical
EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X,
//! pixels to move the button image down when a pushbutton is pressed
//! pixels to move an unscaled button image down when a button is pressed and the unpressed image looks identical
EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y,
//! pixels to move the button text to the right when a pushbutton is pressed
//! pixels to move the button text to the right when a button is pressed
EGDS_BUTTON_PRESSED_TEXT_OFFSET_X,
//! pixels to move the button text down when a pushbutton is pressed
//! pixels to move the button text down when a button is pressed
EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y,
//! pixels to move an unscaled button sprite to the right when a button is pressed
EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X,
//! pixels to move an unscaled button sprite down when a button is pressed
EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y,
//! this value is not used, it only specifies the amount of default sizes
//! available.
@ -222,6 +226,8 @@ namespace gui
"ButtonPressedImageOffsetY"
"ButtonPressedTextOffsetX",
"ButtonPressedTextOffsetY",
"ButtonPressedSpriteOffsetX",
"ButtonPressedSpriteOffsetY",
0
};

View File

@ -20,7 +20,7 @@ namespace gui
CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip)
: IGUIButton(environment, parent, id, rectangle),
SpriteBank(0), OverrideFont(0), Image(0), PressedImage(0),
SpriteBank(0), OverrideFont(0),
ClickTime(0), HoverTime(0), FocusTime(0),
IsPushButton(false), Pressed(false),
UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)
@ -30,10 +30,6 @@ CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
#endif
setNotClipped(noclip);
// Initialize the sprites.
for (u32 i=0; i<EGBS_COUNT; ++i)
ButtonSprites[i].Index = -1;
// This element can be tabbed.
setTabStop(true);
setTabOrder(-1);
@ -46,12 +42,6 @@ CGUIButton::~CGUIButton()
if (OverrideFont)
OverrideFont->drop();
if (Image)
Image->drop();
if (PressedImage)
PressedImage->drop();
if (SpriteBank)
SpriteBank->drop();
}
@ -91,20 +81,37 @@ void CGUIButton::setSpriteBank(IGUISpriteBank* sprites)
}
void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop)
void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)
{
if (SpriteBank)
{
ButtonSprites[(u32)state].Index = index;
ButtonSprites[(u32)state].Color = color;
ButtonSprites[(u32)state].Loop = loop;
}
else
{
ButtonSprites[(u32)state].Index = -1;
}
ButtonSprites[(u32)state].Index = index;
ButtonSprites[(u32)state].Color = color;
ButtonSprites[(u32)state].Loop = loop;
ButtonSprites[(u32)state].Scale = scale;
}
//! Get the sprite-index for the given state or -1 when no sprite is set
s32 CGUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Index;
}
//! Get the sprite color for the given state. Color is only used when a sprite is set.
video::SColor CGUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Color;
}
//! Returns if the sprite in the given state does loop
bool CGUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Loop;
}
//! Returns if the sprite in the given state is scaled
bool CGUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Scale;
}
//! called if an event happened.
bool CGUIButton::OnEvent(const SEvent& event)
@ -235,94 +242,77 @@ void CGUIButton::draw()
IGUISkin* skin = Environment->getSkin();
video::IVideoDriver* driver = Environment->getVideoDriver();
// todo: move sprite up and text down if the pressed state has a sprite
const core::position2di spritePos = AbsoluteRect.getCenter();
if (!Pressed)
if (DrawBorder)
{
if (DrawBorder)
skin->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect);
if (Image)
if (!Pressed)
{
core::position2d<s32> pos = spritePos;
pos.X -= ImageRect.getWidth() / 2;
pos.Y -= ImageRect.getHeight() / 2;
driver->draw2DImage(Image,
ScaleImage? AbsoluteRect :
core::recti(pos, ImageRect.getSize()),
ImageRect, &AbsoluteClippingRect,
0, UseAlphaChannel);
skin->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect);
}
else
{
skin->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect);
}
}
else
const core::position2di buttonCenter(AbsoluteRect.getCenter());
EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed);
if ( ButtonImages[(u32)imageState].Texture )
{
if (DrawBorder)
skin->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect);
core::position2d<s32> pos(buttonCenter);
core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);
if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )
sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());
video::ITexture * imgPressed = PressedImage;
core::rect<s32> rectPressed(PressedImageRect);
bool movePos = false; // pressed-down effect by moving the image
if (!imgPressed && Image)
{
imgPressed = Image;
rectPressed = ImageRect;
movePos = true;
}
else if (Image == PressedImage && PressedImageRect == ImageRect)
{
movePos = true;
}
if (imgPressed)
{
core::position2d<s32> pos = spritePos;
pos.X -= rectPressed.getWidth() / 2;
pos.Y -= rectPressed.getHeight() / 2;
pos.X -= sourceRect.getWidth() / 2;
pos.Y -= sourceRect.getHeight() / 2;
if (movePos)
if ( Pressed )
{
// Create a pressed-down effect by moving the image when it looks identical to the unpressed state image
EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);
if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )
{
pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);
pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);
}
driver->draw2DImage(imgPressed,
ScaleImage? AbsoluteRect :
core::recti(pos, rectPressed.getSize()),
rectPressed, &AbsoluteClippingRect,
0, UseAlphaChannel);
}
driver->draw2DImage(ButtonImages[(u32)imageState].Texture,
ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
sourceRect, &AbsoluteClippingRect,
0, UseAlphaChannel);
}
if (SpriteBank)
{
// pressed / unpressed animation
u32 state = Pressed ? (u32)EGBS_BUTTON_DOWN : (u32)EGBS_BUTTON_UP;
if (ButtonSprites[state].Index != -1)
core::position2di pos(buttonCenter);
if ( Pressed )
{
SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos,
&AbsoluteClippingRect, ButtonSprites[state].Color, ClickTime, os::Timer::getTime(),
ButtonSprites[state].Loop, true);
IGUISkin* skin = Environment->getSkin();
pos.X += skin->getSize(EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X);
pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y);
}
// focused / unfocused animation
state = Environment->hasFocus(this) ? (u32)EGBS_BUTTON_FOCUSED : (u32)EGBS_BUTTON_NOT_FOCUSED;
if (ButtonSprites[state].Index != -1)
{
SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos,
&AbsoluteClippingRect, ButtonSprites[state].Color, FocusTime, os::Timer::getTime(),
ButtonSprites[state].Loop, true);
}
// mouse over / off animation
if (isEnabled())
{
state = Environment->getHovered() == this ? (u32)EGBS_BUTTON_MOUSE_OVER : (u32)EGBS_BUTTON_MOUSE_OFF;
if (ButtonSprites[state].Index != -1)
{
SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos,
&AbsoluteClippingRect, ButtonSprites[state].Color, HoverTime, os::Timer::getTime(),
ButtonSprites[state].Loop, true);
}
// pressed / unpressed animation
EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;
drawSprite(state, ClickTime, pos);
// focused / unfocused animation
state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;
drawSprite(state, FocusTime, pos);
// mouse over / off animation
state = Environment->getHovered() == this ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;
drawSprite(state, HoverTime, pos);
}
else
{
// draw disabled
drawSprite(EGBS_BUTTON_DISABLED, 0, pos);
}
}
@ -346,6 +336,93 @@ void CGUIButton::draw()
IGUIElement::draw();
}
void CGUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)
{
u32 stateIdx = (u32)state;
if (ButtonSprites[stateIdx].Index != -1)
{
if ( ButtonSprites[stateIdx].Scale )
{
const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect,
&AbsoluteClippingRect, colors,
os::Timer::getTime()-startTime, ButtonSprites[stateIdx].Loop);
}
else
{
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,
&AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, os::Timer::getTime(),
ButtonSprites[stateIdx].Loop, true);
}
}
}
EGUI_BUTTON_IMAGE_STATE CGUIButton::getImageState(bool pressed) const
{
// figure state we should have
EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;
bool focused = Environment->hasFocus(this);
bool mouseOver = Environment->getHovered() == this;
if (isEnabled())
{
if ( pressed )
{
if ( focused && mouseOver )
state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;
else if ( focused )
state = EGBIS_IMAGE_DOWN_FOCUSED;
else if ( mouseOver )
state = EGBIS_IMAGE_DOWN_MOUSEOVER;
else
state = EGBIS_IMAGE_DOWN;
}
else // !pressed
{
if ( focused && mouseOver )
state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;
else if ( focused )
state = EGBIS_IMAGE_UP_FOCUSED;
else if ( mouseOver )
state = EGBIS_IMAGE_UP_MOUSEOVER;
else
state = EGBIS_IMAGE_UP;
}
}
// find a compatible state that has images
while ( state != EGBIS_IMAGE_UP && !ButtonImages[(u32)state].Texture )
{
switch ( state )
{
case EGBIS_IMAGE_UP_FOCUSED:
state = EGBIS_IMAGE_UP_MOUSEOVER;
break;
case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:
state = EGBIS_IMAGE_UP_FOCUSED;
break;
case EGBIS_IMAGE_DOWN_MOUSEOVER:
state = EGBIS_IMAGE_DOWN;
break;
case EGBIS_IMAGE_DOWN_FOCUSED:
state = EGBIS_IMAGE_DOWN_MOUSEOVER;
break;
case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:
state = EGBIS_IMAGE_DOWN_FOCUSED;
break;
case EGBIS_IMAGE_DISABLED:
if ( pressed )
state = EGBIS_IMAGE_DOWN;
else
state = EGBIS_IMAGE_UP;
break;
default:
state = EGBIS_IMAGE_UP;
}
}
return state;
}
//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
void CGUIButton::setOverrideFont(IGUIFont* font)
@ -379,51 +456,22 @@ IGUIFont* CGUIButton::getActiveFont() const
return 0;
}
//! Sets an image which should be displayed on the button when it is in normal state.
void CGUIButton::setImage(video::ITexture* image)
void CGUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)
{
if (image)
image->grab();
if (Image)
Image->drop();
if ( state >= EGBIS_COUNT )
return;
Image = image;
if (image)
ImageRect = core::rect<s32>(core::position2d<s32>(0,0), image->getOriginalSize());
}
//! Sets the image which should be displayed on the button when it is in its normal state.
void CGUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)
{
setImage(image);
ImageRect = pos;
}
//! Sets an image which should be displayed on the button when it is in pressed state.
void CGUIButton::setPressedImage(video::ITexture* image)
{
if (image)
if ( image )
image->grab();
if (PressedImage)
PressedImage->drop();
u32 stateIdx = (u32)state;
if ( ButtonImages[stateIdx].Texture )
ButtonImages[stateIdx].Texture->drop();
PressedImage = image;
if (image)
PressedImageRect = core::rect<s32>(core::position2d<s32>(0,0), image->getOriginalSize());
ButtonImages[stateIdx].Texture = image;
ButtonImages[stateIdx].SourceRect = sourceRect;
}
//! Sets the image which should be displayed on the button when it is in its pressed state.
void CGUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)
{
setPressedImage(image);
PressedImageRect = pos;
}
//! Sets if the button should behave like a push button. Which means it
//! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of the button.
@ -489,16 +537,44 @@ void CGUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWri
out->addBool ("PushButton", IsPushButton );
if (IsPushButton)
out->addBool("Pressed", Pressed);
out->addBool("Pressed", Pressed);
out->addTexture ("Image", Image);
out->addRect ("ImageRect", ImageRect);
out->addTexture ("PressedImage", PressedImage);
out->addRect ("PressedImageRect", PressedImageRect);
for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )
{
if ( ButtonImages[i].Texture )
{
core::stringc name( GUIButtonImageStateNames[i] );
out->addTexture(name.c_str(), ButtonImages[i].Texture);
name += "Rect";
out->addRect(name.c_str(), ButtonImages[i].SourceRect);
}
}
out->addBool ("UseAlphaChannel", isAlphaChannelUsed());
out->addBool ("Border", isDrawingBorder());
out->addBool ("ScaleImage", isScalingImage());
out->addBool ("UseAlphaChannel", UseAlphaChannel);
out->addBool ("Border", DrawBorder);
out->addBool ("ScaleImage", ScaleImage);
for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )
{
if ( ButtonSprites[i].Index >= 0 )
{
core::stringc nameIndex( GUIButtonStateNames[i] );
nameIndex += "Index";
out->addInt(nameIndex.c_str(), ButtonSprites[i].Index );
core::stringc nameColor( GUIButtonStateNames[i] );
nameColor += "Color";
out->addColor(nameColor.c_str(), ButtonSprites[i].Color );
core::stringc nameLoop( GUIButtonStateNames[i] );
nameLoop += "Loop";
out->addBool(nameLoop.c_str(), ButtonSprites[i].Loop );
core::stringc nameScale( GUIButtonStateNames[i] );
nameScale += "Scale";
out->addBool(nameScale.c_str(), ButtonSprites[i].Scale );
}
}
// out->addString ("OverrideFont", OverrideFont);
}
@ -509,24 +585,41 @@ void CGUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWr
{
IGUIButton::deserializeAttributes(in,options);
IsPushButton = in->getAttributeAsBool("PushButton");
Pressed = IsPushButton ? in->getAttributeAsBool("Pressed") : false;
IsPushButton = in->getAttributeAsBool("PushButton", IsPushButton);
Pressed = IsPushButton ? in->getAttributeAsBool("Pressed", Pressed) : false;
core::rect<s32> rec = in->getAttributeAsRect("ImageRect");
if (rec.isValid())
setImage( in->getAttributeAsTexture("Image"), rec);
else
setImage( in->getAttributeAsTexture("Image") );
for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )
{
core::stringc nameRect( GUIButtonImageStateNames[i] );
nameRect += "Rect";
rec = in->getAttributeAsRect("PressedImageRect");
if (rec.isValid())
setPressedImage( in->getAttributeAsTexture("PressedImage"), rec);
else
setPressedImage( in->getAttributeAsTexture("PressedImage") );
setImage((EGUI_BUTTON_IMAGE_STATE)i,
in->getAttributeAsTexture(GUIButtonImageStateNames[i], ButtonImages[i].Texture),
in->getAttributeAsRect(nameRect.c_str(), ButtonImages[i].SourceRect) );
}
setDrawBorder(in->getAttributeAsBool("Border"));
setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel"));
setScaleImage(in->getAttributeAsBool("ScaleImage"));
setDrawBorder(in->getAttributeAsBool("Border", DrawBorder));
setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel", UseAlphaChannel));
setScaleImage(in->getAttributeAsBool("ScaleImage", ScaleImage));
for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )
{
core::stringc nameIndex( GUIButtonStateNames[i] );
nameIndex += "Index";
ButtonSprites[i].Index = in->getAttributeAsInt(nameIndex.c_str(), ButtonSprites[i].Index );
core::stringc nameColor( GUIButtonStateNames[i] );
nameColor += "Color";
ButtonSprites[i].Color = in->getAttributeAsColor(nameColor.c_str(), ButtonSprites[i].Color );
core::stringc nameLoop( GUIButtonStateNames[i] );
nameLoop += "Loop";
ButtonSprites[i].Loop = in->getAttributeAsBool(nameLoop.c_str(), ButtonSprites[i].Loop );
core::stringc nameScale( GUIButtonStateNames[i] );
nameScale += "Scale";
ButtonSprites[i].Scale = in->getAttributeAsBool(nameScale.c_str(), ButtonSprites[i].Scale );
}
// setOverrideFont(in->getAttributeAsString("OverrideFont"));

View File

@ -10,6 +10,7 @@
#include "IGUIButton.h"
#include "IGUISpriteBank.h"
#include "ITexture.h"
#include "SColor.h"
namespace irr
@ -43,17 +44,32 @@ namespace gui
//! Get the font which is used right now for drawing
virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_;
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image=0) _IRR_OVERRIDE_;
//! Sets an image which should be displayed on the button when it is in the given state.
virtual void setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image=0, const core::rect<s32>& sourceRect=core::rect<s32>(0,0,0,0)) _IRR_OVERRIDE_;
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image, const core::rect<s32>& pos) _IRR_OVERRIDE_;
virtual void setImage(video::ITexture* image=0) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_UP, image);
}
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image, const core::rect<s32>& pos) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_UP, image, pos);
}
//! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image=0) _IRR_OVERRIDE_;
virtual void setPressedImage(video::ITexture* image=0) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_DOWN, image);
}
//! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) _IRR_OVERRIDE_;
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_DOWN, image, pos);
}
//! Sets the sprite bank used by the button
virtual void setSpriteBank(IGUISpriteBank* bank=0) _IRR_OVERRIDE_;
@ -65,7 +81,20 @@ namespace gui
\param color: The color of the sprite
*/
virtual void setSprite(EGUI_BUTTON_STATE state, s32 index,
video::SColor color=video::SColor(255,255,255,255), bool loop=false) _IRR_OVERRIDE_;
video::SColor color=video::SColor(255,255,255,255),
bool loop=false, bool scale=false) _IRR_OVERRIDE_;
//! Get the sprite-index for the given state or -1 when no sprite is set
virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Get the sprite color for the given state. Color is only used when a sprite is set.
virtual video::SColor getSpriteColor(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Returns if the sprite in the given state does loop
virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Returns if the sprite in the given state is scaled
virtual bool getSpriteScale(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Sets if the button should behave like a push button. Which means it
//! can be in two states: Normal or Pressed. With a click on the button,
@ -105,26 +134,76 @@ namespace gui
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_;
protected:
void drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);
EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;
private:
struct ButtonSprite
{
ButtonSprite() : Index(-1), Loop(false), Scale(false)
{
}
bool operator==(const ButtonSprite& other) const
{
return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale;
}
s32 Index;
video::SColor Color;
bool Loop;
bool Scale;
};
ButtonSprite ButtonSprites[EGBS_COUNT];
IGUISpriteBank* SpriteBank;
struct ButtonImage
{
ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
{
}
ButtonImage(const ButtonImage& other) : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
{
*this = other;
}
~ButtonImage()
{
if ( Texture )
Texture->drop();
}
ButtonImage& operator=(const ButtonImage& other)
{
if ( this == &other )
return *this;
if (other.Texture)
other.Texture->grab();
if ( Texture )
Texture->drop();
Texture = other.Texture;
SourceRect = other.SourceRect;
}
bool operator==(const ButtonImage& other) const
{
return Texture == other.Texture && SourceRect == other.SourceRect;
}
video::ITexture* Texture;
core::rect<s32> SourceRect;
};
ButtonImage ButtonImages[EGBIS_COUNT];
IGUIFont* OverrideFont;
video::ITexture* Image;
video::ITexture* PressedImage;
core::rect<s32> ImageRect;
core::rect<s32> PressedImageRect;
u32 ClickTime, HoverTime, FocusTime;
bool IsPushButton;

View File

@ -123,6 +123,8 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver)
Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y] = 1;
Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_X] = 0;
Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y] = 2;
Sizes[EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X] = 0;
Sizes[EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y] = 0;
Texts[EGDT_MSG_BOX_OK] = L"OK";
Texts[EGDT_MSG_BOX_CANCEL] = L"Cancel";
@ -970,9 +972,7 @@ void CGUISkin::draw2DRectangle(IGUIElement* element,
}
//! Writes attributes of the object.
//! Implement this to expose the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml serialization purposes.
//! Writes attributes of the skin
void CGUISkin::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
u32 i;
@ -990,25 +990,21 @@ void CGUISkin::serializeAttributes(io::IAttributes* out, io::SAttributeReadWrite
}
//! Reads attributes of the object.
//! Implement this to set the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml deserialization purposes.
//! Reads attributes of the skikn
void CGUISkin::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
// TODO: This is not nice code for downward compatibility, whenever new values are added and users
// load an old skin the corresponding values will be set to 0.
u32 i;
for (i=0; i<EGDC_COUNT; ++i)
Colors[i] = in->getAttributeAsColor(GUISkinColorNames[i]);
Colors[i] = in->getAttributeAsColor(GUISkinColorNames[i], Colors[i]);
for (i=0; i<EGDS_COUNT; ++i)
Sizes[i] = in->getAttributeAsInt(GUISkinSizeNames[i]);
Sizes[i] = in->getAttributeAsInt(GUISkinSizeNames[i], Sizes[i]);
for (i=0; i<EGDT_COUNT; ++i)
Texts[i] = in->getAttributeAsStringW(GUISkinTextNames[i]);
Texts[i] = in->getAttributeAsStringW(GUISkinTextNames[i], Texts[i]);
for (i=0; i<EGDI_COUNT; ++i)
Icons[i] = in->getAttributeAsInt(GUISkinIconNames[i]);
Icons[i] = in->getAttributeAsInt(GUISkinIconNames[i], Icons[i]);
}

View File

@ -216,14 +216,10 @@ namespace gui
//! get the type of this skin
virtual EGUI_SKIN_TYPE getType() const _IRR_OVERRIDE_;
//! Writes attributes of the object.
//! Implement this to expose the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml serialization purposes.
//! Writes attributes of the skin
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
//! Reads attributes of the object.
//! Implement this to set the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml deserialization purposes.
//! Reads attributes of the skin
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
private: