Game Development Community

dev|Pro Game Development Curriculum

Movable guiBitmapCtrl

by James Laker (BurNinG) · 01/03/2008 (9:45 am) · 9 comments

Download Code File

I wasn't happy with the guiWindowCtrl, so I decided the easiest way to create a window was using the guiBitmapCtrl. The only thing I needed for it to act as a window was to make it movable. This is what this resource will do.

In the private section of guiBitmapCtrl.h add:
//JL - Movable Bitmaps
	bool mCanMove;
	bool mMouseMovingWin;
	Point2I mMouseDownPosition;

	RectI mOrigBounds;
	//JL - Movable Bitmaps

Add the following to public methods to guiBitmapCtrl.h:
// JL - Movable bitmap
   GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1);

   void onMouseDown(const GuiEvent &event);
   void onMouseDragged(const GuiEvent &event);
	void onMouseUp(const GuiEvent &event);

   void selectWindow(void);
	// JL - Movable bitmap

On to the guiBitmapCtrl.cpp file add the following to the includes:
#include "gui/core/guiCanvas.h"

In the contructor (GuiBitmapCtrl::GuiBitmapCtrl(void)) add:
//JL - Moveable Bitmaps
	mCanMove = true;
   mMouseMovingWin = false;
	//JL - Moveable Bitmaps

Then I add the following to initPersistFields(). This will allow you to turn it the movability on and off in the GUI editor.
addField("canMove",           TypeBool,         Offset(mCanMove, GuiBitmapCtrl)); //JL - Movable Bitmaps

Then at the bottom of the guiBitmapCtrl.cpp file I paste the following methods/functions:
GuiControl* GuiBitmapCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
{
	return Parent::findHitControl(pt, initialLayer);
}

void GuiBitmapCtrl::selectWindow(void)
{
   //first make sure this window is the front most of its siblings
   GuiControl *parent = getParent();
   if (parent)
   {
      parent->pushObjectToBack(this);
   }

   //also set the first responder to be the one within this window
   setFirstResponder(mFirstResponder);
}

void GuiBitmapCtrl::onMouseDown(const GuiEvent &event)
{
   setUpdate();

   mOrigBounds = mBounds;

   mMouseDownPosition = event.mousePoint;
   Point2I localPoint = globalToLocalCoord(event.mousePoint);

   //select this window - move it to the front, and set the first responder
   //selectWindow();

   GuiControl *ctrl = findHitControl(localPoint);
	if (ctrl && ctrl != this){
		mMouseMovingWin = false;
      ctrl->onMouseDown(event);
	}
	else {
		mMouseMovingWin = mCanMove;
		mouseLock();
	}

}

void GuiBitmapCtrl::onMouseDragged(const GuiEvent &event)
{
   GuiControl *parent = getParent();
   GuiCanvas *root = getRoot();
   if (!root) return;

   Point2I deltaMousePosition = event.mousePoint - mMouseDownPosition;

   Point2I newPosition = mBounds.point;
   Point2I newExtent = mBounds.extent;
	bool update = false;

   if (mMouseMovingWin && parent)
   {
      newPosition.x = getMax(0, getMin(parent->mBounds.extent.x - mBounds.extent.x, mOrigBounds.point.x + deltaMousePosition.x));
      newPosition.y = getMax(0, getMin(parent->mBounds.extent.y - mBounds.extent.y, mOrigBounds.point.y + deltaMousePosition.y));
      
		update = true;
   }

	if (update)
	{
		Point2I pos = parent->localToGlobalCoord(mBounds.point);
		root->addUpdateRegion(pos, mBounds.extent);
      Parent::resize(newPosition, newExtent);
	}

}

void GuiBitmapCtrl::onMouseUp(const GuiEvent &event)
{

   event;
   mouseUnlock();

   mMouseMovingWin = false;

}

Known Bugs: With the SelectWindow(); function uncommented it seems to loose everything when you dont click on the Image since it's bringing the Back to the front over everything. Not sure how to get around it.


It's pretty simple, I hope you find it usefull. Here's an example of the kind of "Windows" you can have (from Solar Battles) :
burningza.googlepages.com/DisplaySettings.png

#1
11/30/2007 (11:16 am)
Handy James, thank you. Regarding the bug.. Could I get a little more info on it. I'm really not a coder and although I think I understand what you are saying I am not sure on the exact trigger for the bug.. If I dont use the SelectWindow(); function I am ok?

Having a more flexible GUI would be cool for all of our games. Infact, once I implement this I think it would be a piece of cake to save the positional variables of all of the moveable controls to a user file so that it remembers the users preferences when they start the game again.

Nice stuff.
#2
12/01/2007 (5:00 am)
Hi, yes, you'll see in the code above the call to SelectWindow(); is commented out in GuiBitmapCtrl::onMouseDown. When you put that back and click outside the guiBitmapCtrl bounds, it seems that all the controls are lost/invisible. The SelectWindow is used to bring a ctrl to the front. So I think the parent should always be pushed to the back. So I'm not 100% sure how to fix it. But there is no known bugs with SelectWindow(); commented out. I was just hoping someone can come up with a solution, since it will be a nice-to-have.
#3
12/27/2008 (7:37 pm)
Great resource. Makes creating great looking windows quick and easy. Simple port to TGEA 1.7.1 too.
#4
03/09/2009 (5:27 am)
Does this work in TGEA 1.8.1?
#5
03/09/2009 (6:04 am)
I have not tested this. I don't see any reason for it not to work though.
#6
03/17/2009 (1:48 am)
I am not sure if anyone has AFX, but I am trying to make my health bars movable and when I click on the health or energy portion my game crashes. Does anyone know the reason for this?
#7
08/09/2010 (6:41 pm)
Will this work in T3D?
#8
10/17/2010 (5:40 pm)
TGE 1.8.2 Version: Download File

The selectWindow() bug is no longer present. I also fixed it where you can drag the control off of the screen just as you can the normal window control.

I guess I should also note that I made it a whole new control all in itself. As I did not like the idea of having the canMove functionality on my normal guiBitmapCtrl. I placed the two above files in gui/containers and recompiled. After that you can add the new control by adding a guiBitmapWindowCtrl.
#9
12/02/2011 (8:28 pm)
I want to do this same thing with T3D. 1) is it possible? 2)Ware exactly do I imploment this in t3d