Advertisement

Custom GUI source/design docs/articles/whatever.

Started by July 01, 2000 07:02 AM
16 comments, last by Staffan 24 years, 5 months ago
I just finished whipping up a simple GUI and frankly, I''m not sure if I''m quite satisfied with the way I''m doing it. So, perhaps some of you know where I can find the (C++, not C, please) source code/design spec. to a custom GUI? Or even an article (not the one on GameDev). I tried a search on AltaVista with no luck. "Paranoia is the belief in a hidden order behind the visible." - Anonymous
how are you doing it? (theres not much point searching for a better implementation if yours is good).
Advertisement
Uh..please don''t make me paste all the source code! I''m just looking for something to compare with and get some ideas.

"Paranoia is the belief in a hidden order behind the visible." - Anonymous
IIRC there was an article about GUI here on gdnet, checkout the features
If you read my post you would have seen I asked for anything but that article.

"Paranoia is the belief in a hidden order behind the visible." - Anonymous
I''m not sure how you''re doing it but here is how I do it (just the prettying it up part atleast). I usually build the interfaces in a 3d modeling program and render them out, that way all the shadows and such are true. And the texturing and level of detail is unlimited. Load it into a surface with a color alpha''d out for your window into the game below it, and off you go. Go by mouse posistion on the screen for menu clicks. I hope this helps, and if not maybe you got an idea.
anyway, Goodluck;

Prairie
"Climb down off the cross, ''cause we could use the wood" - Tom Waits
Advertisement
I was kinda more looking for the implementation specific details. The programming part of the coin, not the graphics.

"Paranoia is the belief in a hidden order behind the visible." - Anonymous
okay, i hope i understand what you are asking for...

i don''t actually have any source published on it, but i can tell you what i did...


class gguiWnd {
public:
gguiWnd* get_parent() {return pParent;}
void AddWindow(gguiWnd* pWnd);
void RemoveWindow(gguiWnd* pWnd);

virtual void OnDraw(); // Draw this window
protected:
gguiWnd* pParent;
APriorityList children;
BOOL bShown;
BOOL bTransparent;
BOOL bLocked;
BOOL bOwnSurface;

int pos_x;
int pos_y;
int pos_w;
int pos_h;
};


now, i use bShown to determine if the window is shown or not.
bTransparent indicates what the drawing order should be. if the window is transparent then the windows below are drawn first. (i use a clipping algorithm so that i don''t redraw the screen when not needed). also, the bOwnSurface flag determines the drawing method.

oh, and bLocked is used to lock a window, which is needed for when a modal child is created:
int gguiWnd::IsLocked() {
if (bLocked) return TRUE;
if (pParent) return pParent->IsLocked();
return FALSE;
}

okay, i have cut a lot of stuff out... anything specific?
Staffan,

I''m in the midsts of doing this myself, and I have sorted out a system I''m quite happy with.

I have on base object CGUIObject.

It has protected member variables:

CGUIObject *m_children[MAX_CHILDREN]; // a linked list is better
CGUIObject *m_pParent;
StateFields m_stateFields; // bit field of the states

It has protected member functions:

// these are never overridden
Create();
Draw();
LeftButtonDown(POINT *point);
LeftButtonUp(POINT *point);
MouseMove(POINT *point);
VKDown(VK_Type vk);
Destroy();

and protected virtual member functions

// almost always overridden
virtual ERROR_Type OnCreate();
virtual ERROR_Type OnDraw();
virtual ERROR_Type OnLeftButtonDown(POINT *point);
virtual ERROR_Type OnLeftButtonUp(POINT *point);
virtual ERROR_Type OnMouseMove(POINT *point);
virtual ERROR_Type OnVKDown(VK_Type vk);
virtual ERROR_Type OnDestroy();


Here''s the function Draw():

[PRE]
ERROR_Type Draw()
{
int i;
for (i = 0;i < MAX_CHILDREN; i++) // should be linked list
{
if (m_children) // check if allocated
m_children->Draw();<br> }<br><br> // call this object''s OnDraw()<br> return OnDraw();<br>}<br>[/PRE]<br><br>Each of the Create, Draw, Destroy functions call the On<xxx> function.<br><br>I have children of CGUIObject:<br><br>CGUIButton<br>CGUIWindow<br>CGUITextEdit<br><br>and most importantly<br><br>CGUIDesktop<br><br><br>When I make an application, I create a CGUIDesktop. I then create windows:<br><br>[PRE]<br>pGUIDesktop = new CGUIDesktop;<br>CGUIDesktop->Create(NULL /* no parent */);<br><br>pNewWindow = new CGUIWindow;<br>pNewWindow->Create(pGUIDesktop); // child of the desktop<br>pNewWindow->SetRect(100,100,400,400);<br><br>… later on<br><br>pNewWindow->Destroy(); // deletes its children and removes from desktop<br>delete pNewWindow;<br>[/PRE]<br><br>The desktop object is the root object - although everything decends from CGUIObject, the main access point is through CGUIDesktop.<br><br>New objects overide the On<xxx> functions to change functionality, not the <nnn> functions. To change the way something looks, you rewrite OnDraw() not Draw().<br><br>Let me know if you have any more questions. </i>
Ok, I guess I might as well throw in the GUI I'm working on
I'm cutting a few things out to make it smaller/more readable, but this is the general jist of it:

        class GDXWindow : public GDXGraphicsError{protected:	GDXWindow *m_pWndParent;	GDXSurface *m_pSurface;	vector<GDXWindow *> m_listChildWnd;	queue<SWindow_Msg> m_listMessages;	char m_szCaption[128];	// Sizes	CRect m_rectClient;	// Coordinates of the upper-left corner are (0,0)	CRect m_rectWindow;	// Relative to its parent wnd	CRect m_rectRepaint;	// Client rect that needs to be repainted.	CRect m_TitleBarRect;	DWORD m_dwStyle;	// STYLE_VISIBLE, STYLE_BORDER, etcpublic:	GDXWindow();	~GDXWindow();	virtual BOOL Create(GDXWindow *pWndParent, const CRect ▭, char *szCaption = "", DWORD dwStyle = STYLE_VISIBLE / STYLE_BORDER / STYLE_CAPTION);		virtual void PrePaint();	// Initial drawing/drawing onto the windows source surface	virtual void Paint();		// Blt onto the backbuffer	virtual BOOL Destroy();	void ProcessMessage(SWindow_Msg msg);	// Processes the message passed	void Update();			// Cycles through the queue and processes all waiting messages		BOOL AddChildWindow(GDXWindow *pWindow);	BOOL RemoveChildWindow(GDXWindow *pWindow);	void MessageChildren(DWORD dwMsg, DWORD dwParam1 = 0, DWORD dwParam2 = 0);	GDXWindow *ChildWindowFromPoint(CPoint pt);	virtual void InvalidateRect(CRect *pRect);	// NULL invalidates the entire window	void ShowWindow();	void HideWindow();	BOOL IsVisible() { return m_dwStyle & STYLE_VISIBLE; }	BOOL IsEnabled() { return !(m_dwStyle & STYLE_DISABLED); }	void PostMessage(DWORD dwMsg, DWORD dwParam1 = 0, DWORD dwParam2 = 0);	// Places a message in the window’s message queue	void SendMessage(DWORD dwMsg, DWORD dwParam1 = 0, DWORD dwParam2 = 0);	// Sends the specified message to this window	BOOL SetBitmap(const char *szFilename, DWORD dwFlags = STRETCH_BITMAP);	// Sets the background to the specified bitmap	void MoveWindow(int x, int y);	void ClientToScreen(CPoint *pPoint);	void ScreenToClient(CPoint *pPoint);	void ClientToScreen(CRect *pRect);	void ScreenToClient(CRect *pRect);	CRect GetClientRect() { return m_rectClient; };	CRect GetWindowRect() { return m_rectWindow; };	GDXWindow *GetParent() { return m_pWndParent; };	GDXSurface *GetSurface() { return m_pSurface; };	GDXDesktop *GetDesktop() { return m_pDesktop; };	// Messaging functions	virtual void OnMouseMove(CPoint point) {};	virtual void OnButtwhenclickedoned(DWORD dwButtonID) {};	virtual void OnInitialize(DWORD dwParam1 = 0, DWORD dwParam2 = 0) {};	virtual void OnPaint(DWORD dwParam1 = 0, DWORD dwParam2 = 0) {};	virtual void OnDestroy(DWORD dwParam1 = 0, DWORD dwParam2 = 0) {};	virtual void OnKeyDown(DWORD dwParam1 = 0, DWORD dwParam2 = 0) {};	virtual void OnKeyUp(DWORD dwParam1 = 0, DWORD dwParam2 = 0) {};	virtual void OnRButtonDown(CPoint point) {};	virtual void OnRButtonUp(CPoint point) {};	virtual void OnLButtonDown(CPoint point) {};	virtual void OnLButtonUp(CPoint point) {};	virtual void OnMWheelDown(CPoint point) {};	virtual void OnMWheelUp(CPoint point) {};};        



Basically, it's the same as the other two that was posted above me. I have a GDXDesktop derived from GDXWindow, and it's the root window. Instead of processing all messages right away I store them in a queue. Calling Update actually processes all messages in the queue (I actually call Update for all windows every frame, but storing them makes it easier for me to implement threads and callback functions for windows messages (ala Windows), if I needed).

Windows are only redrawn if they need to be. The main program would call the desktop's InvalidateRect with the region (the size of mouse pointer, for example) that needs to be redrawn, and it checks its child windows and if the rect falls on part of a window it calls its InvalidateRect passing the rectangle converted to the child windows coordinates. The child then redraws the needed rect, and checks to see if the rect falls into any of its child windows, rather, rinse, repeat.

The rest is pretty self explanatory, so I'm not going to get into the details unless someone has a specific question. I'd like to see other peoples implementation actually, because I myself wondered whether I was doing it the best way...

Edited by - Houdini on July 5, 2000 5:04:19 PM
- Houdini

This topic is closed to new replies.

Advertisement