(C++) icon/slot drag/drop rpg style 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.
doqkhanh
Posts: 158
Joined: Sat Mar 01, 2008 3:14 am
Location: Tokyo, Japan
Contact:

Post by doqkhanh »

B@z wrote:HTTP1.1 STATUS 403 Remote Access to this object forbidden

Direct Access Forbidden
This file cannot be directly accessed from a remote site, but must be linked through the Brinkster Member's site.
:roll: New link for you B@z, but in my game, the application crash when I try to drag and drop.
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

This code works only from main function... if you have icon touch crash, that is because slotArray went out of scope, like the man said few years ago. Make slotArray global, or do some intelligent modification.
doqkhanh
Posts: 158
Joined: Sat Mar 01, 2008 3:14 am
Location: Tokyo, Japan
Contact:

Post by doqkhanh »

pera wrote:This code works only from main function... if you have icon touch crash, that is because slotArray went out of scope, like the man said few years ago. Make slotArray global, or do some intelligent modification.
You are right. But, this code have 2 logic error when processing event.
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

Yes, that is correct.
When code was moved to Irrlicht 1.4, only compiler errors were fixed.
In order to make it work, you have to use 1.4 OnEvent functions for GUIWindow, and CIcon. I There were some changes in event handling, so you have to do it like that for it to work properly.
I made those changes and succeded to make code work fine, I can post changes later, but during code exploration I relized this GUI component was pretty awkwardly coded. There is two new classes CSlotWindow and that BringUpButton wich don't do anything different then regular component (CSlotWindow creates slotArray and returns it but its not even member component of CSlotWindow, and BringUpButton shows/hides window wich any regular button can do - no need for special class I think).
my favorite is
Dragged = true*Movable;
Anyhow, I think This inventory should be one GUI class that can be added to window like any other button or list or text. It should have addItem and couple of more functions and thats about it. If I make something like that usable, I'll post it.
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

This are my modifications to Window class in order to make it work in Irrlicht 1.4:

Code: Select all

#include "CGUISlotWindow.h"
#include "CGUIBringUpSlotWindowButton.h"
#include "CGUIIconSlot.h"

namespace irr
{
namespace gui
{


//! constructor
CGUISlotWindow::CGUISlotWindow(IrrlichtDevice* device, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUIWindow(device->getGUIEnvironment(), parent, id, rectangle), Dragging(false), Device(device)
{
	#ifdef _DEBUG
	setDebugName("CGUISlotWindow");
	#endif

	IGUISkin* skin = 0;
	if (Environment)
		skin = Environment->getSkin();

	IGUISpriteBank* sprites = 0;
	video::SColor color(255,255,255,255);

	s32 buttonw = 15;
	if (skin)
	{
		buttonw = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);
		sprites = skin->getSpriteBank();
		color = skin->getColor(EGDC_WINDOW_SYMBOL);
	}
	s32 posx = RelativeRect.getWidth() - buttonw - 4;

	CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
		L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close" );
	CloseButton->setSubElement(true);
	CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	if (sprites)
	{
		CloseButton->setSpriteBank(sprites);
		CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), color);
		CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), color);
	}
	posx -= buttonw + 2;

	RestoreButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
		L"", skin ? skin->getDefaultText(EGDT_WINDOW_RESTORE) : L"Restore" );
	RestoreButton->setVisible(false);
	RestoreButton->setSubElement(true);
	RestoreButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	if (sprites)
	{
		RestoreButton->setSpriteBank(sprites);
		RestoreButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_RESTORE), color);
		RestoreButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_RESTORE), color);
	}
	posx -= buttonw + 2;

	MinButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
		L"", skin ? skin->getDefaultText(EGDT_WINDOW_MINIMIZE) : L"Minimize" );
	MinButton->setVisible(false);
	MinButton->setSubElement(true);
	MinButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	if (sprites)
	{
		MinButton->setSpriteBank(sprites);
		MinButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_MINIMIZE), color);
		MinButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_MINIMIZE), color);
	}

	MinButton->grab();
	RestoreButton->grab();
	CloseButton->grab();
}



//! destructor
CGUISlotWindow::~CGUISlotWindow()
{
	if (MinButton)
		MinButton->drop();

	if (RestoreButton)
		RestoreButton->drop();

	if (CloseButton)
		CloseButton->drop();
}



//! called if an event happened.
bool CGUISlotWindow::OnEvent(const SEvent& event)
{
	switch(event.EventType)
	{
	case EET_GUI_EVENT:
		if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
		{
			Dragging = false;
		}
		else
		if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
		{
			if (event.GUIEvent.Caller == this && Parent)
			{
				Parent->bringToFront(this);
			}
		}
		else
		if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
		{
			if (event.GUIEvent.Caller == CloseButton)
			{
				if (Parent)
				{
					// send close event to parent
					SEvent e;
					e.EventType = EET_GUI_EVENT;
					e.GUIEvent.Caller = this;
					e.GUIEvent.Element = 0;
					e.GUIEvent.EventType = EGET_ELEMENT_CLOSED;

					// if the event was not absorbed
					if (!Parent->OnEvent(e))
					{
						remove();
					}
					return true;

				}
				else
				{
					remove();
					return true;
				}
			}
		}
		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;
			if (!Environment->hasFocus(this))
			{
				Environment->setFocus(this);
				if (Parent)
					Parent->bringToFront(this);
			}
			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<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
				DragStart.X = event.MouseInput.X;
				DragStart.Y = event.MouseInput.Y;
				return true;
			}
			break;
		default:
			break;
		}
	default:
		break;
	}

	return IGUIElement::OnEvent(event);
}

//! Updates the absolute position.
void CGUISlotWindow::updateAbsolutePosition()
{
	IGUIElement::updateAbsolutePosition();
}



//! draws the element and its children
void CGUISlotWindow::draw()
{
	if (!IsVisible)
		return;

	IGUISkin* skin = Environment->getSkin();

	core::rect<s32> rect = AbsoluteRect;
	core::rect<s32> *cl = &AbsoluteClippingRect;

	// draw body fast
	rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER),
		AbsoluteRect, &AbsoluteClippingRect);

	if (Text.size())
	{
		rect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
		rect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y);
		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, cl);
	}

	IGUIElement::draw();
}



//! Returns pointer to the close button
IGUIButton* CGUISlotWindow::getCloseButton() const
{
	return CloseButton;
}



//! Returns pointer to the minimize button
IGUIButton* CGUISlotWindow::getMinimizeButton() const
{
	return MinButton;
}



//! Returns pointer to the maximize button
IGUIButton* CGUISlotWindow::getMaximizeButton() const
{
	return RestoreButton;
}

//! adds a bring-up button
CGUIBringUpSlotWindowButton* CGUISlotWindow::createBringUpButton(core::rect<s32> rectangle, IGUIElement* parent,
                                                              s32 id, const wchar_t* text,
                                                              const wchar_t* tooltip)
{
    if(!parent)
        parent = Environment->getRootGUIElement();

    CGUIBringUpSlotWindowButton* button = new CGUIBringUpSlotWindowButton(Device, parent, id, rectangle, this);

    if(text)
        button->setText(text);

    if(tooltip)
        button->setToolTipText(tooltip);

    return button;
}

//! adds a slot array to the window
core::array<IGUIElement*> CGUISlotWindow::addSlotArray(core::rect<s32> slotRect, video::ITexture* texture,
                                                        IGUIElement* parent, s32 id ,
                                                        core::position2d<s32> relPos,
                                                        core::dimension2d<s32> arrayDim,
                                                        core::dimension2d<s32> spacing)
{
    if(!parent)
        parent = this;

    //create the array
    core::array<IGUIElement*> slotArray;
    for(s32 x = 0; x < arrayDim.Width; x++)
    {
        for(s32 y = 0; y < arrayDim.Height; y++)
        {
            CGUIIconSlot* slot = new CGUIIconSlot(Environment, parent, id, slotRect);
            slot->setImage(texture);
            slot->setRelativePosition(core::rect<s32>(relPos.X + x*(spacing.Width + slotRect.LowerRightCorner.X),
                                                      relPos.Y + y*(spacing.Height + slotRect.LowerRightCorner.Y),
                                                      slotRect.LowerRightCorner.X + (relPos.X + x*(spacing.Width + slotRect.LowerRightCorner.X)),
                                                      slotRect.LowerRightCorner.Y +(relPos.Y + y*(spacing.Height + slotRect.LowerRightCorner.Y))));
            slotArray.push_back(slot);
            slot->drop();
        }
    }

    return slotArray;
}

}//end namespace gui
}//end namespace irr


These are modifications to CIcon class:

Code: Select all


#include "CGUIIcon.h"
#include "CGUIIconSlot.h"

namespace irr
{
namespace gui
{

//! Constructor
CGUIIcon::CGUIIcon(gui::IGUIEnvironment* environment, gui::IGUIElement* parent, s32 id, core::rect<s32> rectangle)
    : IGUIElement(gui::EGUIET_ELEMENT , environment, parent, id, rectangle), Texture(0),
    Moveable(true), CanBeOutsideSlot(false), Slot(0), Dragging(false) {
	
		UsableSlots.clear();
	}

//! Destructor
CGUIIcon::~CGUIIcon()
{
    if(Texture)
        Texture->drop();
}


//! Sets an image which should be displayed as the icon
void CGUIIcon::setImage(video::ITexture *img)
{
    if(Texture)
        Texture->drop();

    Texture = img;

    if(Texture)
        Texture->grab();
}

//! draws the element and its children
void CGUIIcon::draw()
{
    if (!IsVisible)
        return;

    irr::video::IVideoDriver* driver = Environment->getVideoDriver();

    if (Texture)
    {
        driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner,
            core::rect<s32>(core::position2d<s32>(0,0), Texture->getOriginalSize()));

        IGUIElement::draw();
    }
}

//! called if an event happened.
bool CGUIIcon::OnEvent(const SEvent& event)
{
	switch(event.EventType)
	{
	case EET_GUI_EVENT:
		if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
		{
			Dragging = false;
		}
		else
		if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
		{
			if (event.GUIEvent.Caller == this && Parent)
			{
				Parent->bringToFront(this);
			}
		}
		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 = Moveable;
			if (!Environment->hasFocus(this))
			{
				Environment->setFocus(this);
				if (Parent)
				{
					Parent->bringToFront(this);

                    //if the icon is in a slot (if the parent isn't the gui root element)
                    if(!(Parent == Environment->getRootGUIElement()))
                    {
                        //make the icon a child of the root element (removing it from the slot)
                        Environment->getRootGUIElement()->addChild(this);
                        //the current position
                        core::rect<s32> currPos = getAbsolutePosition();
                        //move the icon the the right position (ready for dragging)
                        move(core::position2d<s32>(event.MouseInput.X - (event.MouseInput.X-currPos.UpperLeftCorner.X),
                                                    event.MouseInput.Y - (event.MouseInput.Y-currPos.UpperLeftCorner.Y)));
                    }
				}
			}
			return true;
		case EMIE_LMOUSE_LEFT_UP:
			{
				Dragging = false;
				bool movedToSlot = false;
				//is the icon droped in a useable slot's rect
				u32 size = UsableSlots.size();
				IGUIElement *slot = 0;
				for(u32 i = 0; i < size; i++)
				{
					//get the slot
					slot = UsableSlots[i];

					if(slot)
					{
						//get the slot rect
						core::rect<s32> slotRect = slot->getAbsolutePosition();

						//if the position the icon is dropped in, is inside the rect
						if(slotRect.isPointInside(DragStart))
						{
							//move the icon to the slot
							moveToSlot(slot);
							movedToSlot = true;
						}
					}
				}
				//if the icon is dropped outside a slot, and it's not supposed to
				if(!movedToSlot && !CanBeOutsideSlot)
				{
					if(Slot)
					{
						//move it back to where it came from
						moveToSlot(Slot);
					}
				}
			}
			return true;
		case EMIE_MOUSE_MOVED:
			if (Dragging)
			{
				move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
				DragStart.X = event.MouseInput.X;
				DragStart.Y = event.MouseInput.Y;
				return true;
			}
			break;
		default:
			break;
		}
	default:
		break;
	}

	return IGUIElement::OnEvent(event);

}//end function OnEvent

//! Sets whether the icon can be moved
void CGUIIcon::setMoveable(bool state)
{
    Moveable = state;
}

//! Sets whether the icon can be dropped outside a slot
void CGUIIcon::setCanBeOutsideSlot(bool state)
{
    CanBeOutsideSlot = state;
}

//! Adds a single slot to the usable slots
void CGUIIcon::addUsableSlot(IGUIElement* slot)
{
    UsableSlots.push_back(slot);
}

//! Adds the slots in the array to the usable slots
void CGUIIcon::addUsableSlotArray(const core::array<IGUIElement*>& slotArray)
{
    s32 arraySize = slotArray.size();
    for(s32 i = 0; i < arraySize; i++)
    {
        UsableSlots.push_back(slotArray[i]);
    }

}

//! Moves the icon to the passed slot
void CGUIIcon::moveToSlot(IGUIElement* slot)
{
    //check if the slot is usable
    bool usable = false;
    u32 size = UsableSlots.size();
    for(u32 i = 0; i < size; i++)
    {
        if(UsableSlots[i] == slot)
            usable = true;
    }

    //if the slot is not usable - make it usable
    if(!usable)
        UsableSlots.push_back(slot);

    //if the slot is in use (if the slot has a children)
    if(slot->getChildren().getSize())
    {
        /* get the icon from the slot. Gets the last child of the child list,
        asuming that this is the only child the slot has,
        and that this child is an CGUIIcon */
        CGUIIcon* icon = (CGUIIcon*)(*slot->getChildren().getLast());
        //move the icon to where the currently moving icon came from
        //if(Slot)
        //{
        //    icon->moveToSlot(Slot);
        //}
    }

    //add the currently moving icon to the slot
    slot->addChild(this);

    //save the slot
    Slot = slot;

    //set the relative position
    setRelativePosition(core::rect<s32>(core::position2d<s32>(0,0), Texture->getOriginalSize()));
}

//! Gets the slot the icon is in
IGUIElement* CGUIIcon::getSlot()
{
    return Slot;
}

}//end namespace gui
}//end namespace irr

And use addUsableSlotArray instead of setUsableSlotArray to avoid global variable error...
doqkhanh
Posts: 158
Joined: Sat Mar 01, 2008 3:14 am
Location: Tokyo, Japan
Contact:

Post by doqkhanh »

We have a 1.4.1 runable version too.

http://code.google.com/p/fosengine/source/browse

Copyright notice file: http://fosengine.googlecode.com/svn/tru ... me-GUI.txt

Source code files:

http://fosengine.googlecode.com/svn/tru ... Button.cpp 10.5 KB r245 Jun 20, 2008 doqkhanh

http://fosengine.googlecode.com/svn/tru ... owButton.h 4.2 KB r245 Jun 20, 2008 doqkhanh

http://fosengine.googlecode.com/svn/tru ... UIIcon.cpp 8.8 KB r310 Jul 01 (6 days ago) doqkhanh

http://fosengine.googlecode.com/svn/tru ... CGUIIcon.h[/url] 1.9 KB r300 Jun 29, 2008 doqkhanh


http://fosengine.googlecode.com/svn/tru ... IconSlot.h 1.3 KB r300 Jun 29, 2008 doqkhanh

http://fosengine.googlecode.com/svn/tru ... Window.cpp 8.5 KB r301 Jun 29, 2008 doqkhanh

http://fosengine.googlecode.com/svn/tru ... otWindow.h 2.8 KB r246 Jun 21, 2008 doqkhanh
full_newbie
Posts: 27
Joined: Mon Apr 05, 2010 7:33 am

Post by full_newbie »

Please help! I am getting errors:

Code: Select all

CGUISlotWindow.cpp:233: error: cannot allocate an object of type `irr::gui::CGUIBringUpSlotWindowButton'
CGUISlotWindow.cpp:233: error:   because the following virtual functions are abstract:
IGUIButton.h:128: error:  virtual void irr::gui::IGUIButton::setScaleImage(bool)
IGUIButton.h:131: error:  virtual bool irr::gui::IGUIButton::isScalingImage() const
What happens?
Sorry, my english is very bad. | I use minGW+CodeBlocks+Irrlicht 1.7.1(1.6,1.5)
Post Reply