GUIs

Started by
10 comments, last by Synex 18 years, 10 months ago
Im starting to write a GUI for my DirectX project and would like to bounce a couple of things around. 1. I have decided to implement a system wherebye every control on the screen, like buttons and the like, inherit from this baseclass:

#ifndef	G_CONTROL_H
#define	G_CONTROL_H

#include <vector>
#include <string>

class g_control
{
public:
	g_control( g_control* pParent );
	~g_control();

	void		AddChild( g_control*	pChild, std::string& name );
		
	void		IntersectThis( DInputData&	inputData );
	void		IntersectChildren( DInputData&	inputData );

private:

	g_control*			m_parent;
	std::vector< g_control* >	m_children;
};


#endif

Every control can have children controls. For example a message box would have children buttons. 2. To test for intersection the mouse coordinates are passed down the control hierarchy to see whether anything has been intersected using the two intersect functions. 3. A problem im having trouble thinking of a solution to is how, once a control has been intersected, it 'does something' to the rest of my engine. Now i could have a system wherebye i have a global message handler written in straight C or something. This way i could have a header file that has a list of possible messages that the intersected control can trigger. The message handling code could have a global that holds the last message triggered and when a message has been set, it would deal with it and make what ever changes necessary to the system. How does this sound. If anyone has any comments and/or suggestions please reply. thanks, ace
Advertisement
When I wrote a GUI I had member functions in the window base class, one for each message type. Each message was then propagated up or down the chain depending on message type. OnMouseEnter was for example propagated down (to the childs) while OnButtonClicked was propagated up (to the parents). There were some issues with this design but overall it worked out pretty good.
Well, in an ideal world you wouldn't even need that header. You could just have the control post a message, and if the message was invalid, it'll get tossed by the message handler.

I had a similar construct in my last project, using the parent/children tree. I though stored the activation info in functors bound to "on click, on right click" and so on. It worked okay, but largely required things to be public. It also required the programmer to be a bit careful about the design so that if something was destroyed, any controls for it also got destroyed. [It's also a little tricky if a control's action will destroy itself!]

My current project will likely move towards a messaging system, to eliminate those downsides. I imagine the functors will still be around, but they're more likely to generate the messages for the system rather than do the work themselves.
Ok. I understand that concept. But once that message has been defined within the GUI coding, like you said it propogates up and down, how should the gui interact with the rest of the engine.

I suppose that each class, like gamestate, font engine, switching loop etc, could provide global functions as friends. The global functions could alted the friend class members as necessary.

Ace
The GUI should interact with the engine through the engine's interface. To say how the engines interface should look like is however impossible.

If you need to use an object from alot of different places in the code it might be handy to use a global for that object. I don't see why you need to create global wrapper functions for all your objects.
By the engines interface do you mean the public methods in all the class that the engine is compoesed of. If so, wouldn't the object wanting to use the interface need to have references to the objects used in the system?

ace
Hi Ace,

(edit: am I slow as hell?)

Quote:Original post by ace_lovegrove
Im starting to write a GUI for my DirectX project and would like to bounce a couple of things around.

1. I have decided to implement a system wherebye every control on the screen, like buttons and the like, inherit from this baseclass:
*** Source Snippet Removed ***


Looks like you are appying the Composite pattern too fast, because...

Quote:Original post by ace_lovegrove
Every control can have children controls. For example a message box would have children buttons.

... a label don't have any child - thus you are wrong in this case.

I'd suggest you to have a basic g_control and inherit a g_composite_control which can contain any number of g_control.

Quote:Original post by ace_lovegrove
2. To test for intersection the mouse coordinates are passed down the control hierarchy to see whether anything has been intersected using the two intersect functions.

3. A problem im having trouble thinking of a solution to is how, once a control has been intersected, it 'does something' to the rest of my engine. Now i could have a system wherebye i have a global message handler written in straight C or something. This way i could have a header file that has a list of possible messages that the intersected control can trigger. The message handling code could have a global that holds the last message triggered and when a message has been set, it would deal with it and make what ever changes necessary to the system. How does this sound.

Once a control is interected, it fires a message on this control. It is simple as hell:

class g_control{  virtual bool isOver(const DInputData& data);protected:  virtual void process(const DInputData& data) = 0;public:  void processOver(const DInputData& data);};void g_control::processOver(const DInputData& data){  if (isOver(data))  {      process(data);  }}bool g_control::isOver(const DInputData& data){  if (isMouseInControl(data)) return true;  return false;}// composite...bool g_composite_control::isOver(const DInputData& data){  for each subControl    if (subControl->isOver(data)) return false;  if (isMouseInControl(data)) return true;  return false;}


Process can do whatever you want. You don't have to write it in C - a C++ virtual member function can do the work since you as for the intersected control to do the job.

I suggest you to have to look to the following [GoF] patterns: decorator, composite, proxy, bridge, command. All of them can be used to create a GUI system.

HTH,
Maybe this will be helpful for getting some ideas from?

http://www.codeproject.com/library/DWinLib.asp

David
In my system each control has a function pointer that is set in the contructor. When a control detects that it has been clicked, then it calls the function pointer.

Graham.
Go on an Intense Rampage
Quote:Original post by Graham
In my system each control has a function pointer that is set in the contructor. When a control detects that it has been clicked, then it calls the function pointer.

Graham.


This is a possible solution. Using OO programming, a function pointer can be replaced by a policy object (an object with a virtual function)
class g_clickpolicy{public:  virtual void process() = 0;};class g_control{  g_clickpolicy *m_clickpolicy;  void onClick()  {    m_clickpolicy->process();  }private:public:  void setOnClickPolicy(g_clickpolicy *poliy) { m_clickpolicy = policy; }};

In fact, you can have a g_eventpolicy which process every even and dispatch then to g_clickpolicy or g_mousemovepolicy and so on.

I have to add policy (strategy) to ths list of GoF pattern I cited in my previous post :)

HTH,

This topic is closed to new replies.

Advertisement