MogreBetaGUI
From Ogre Wiki
Contents |
About
MogreBetaGUI is a port of BetaGUI. It's using overlays, therefore no external libraries are needed except Mogre itself.
The BetaGUI is intended to be a very short example how to create a GUI. It is NOT intended to be a fully operational GUI supporting a lot of different controls and features. For a full GUI check out the other GUI systems available for Mogre.
For questions etc. use this forum thread.
The talk about the original Ogre add-on BetaGUI is in this thread.
Features
- Creating a Window
- Resizing the window via a bottom-right button.
- Moving the window around via a top bar button.
- Creating a push button in a window with a inactive and active material state.
- Calling back to a function or class to report when that button has been "pushed"
- Creating a functional text gadget on a window to accept textual input to n characters.
- Creating a static piece of text on a window.
A video demonstrating the features 1.26Mb, playable in VLC.
Foreword of the porter
Here's a couple of hours (and then some) work attempting to do a "direct" port of BetaGUI (v015) to Mogre. As it turned out, it's not 100% similar, but it's currently working for me with the following differences:
- All OverlayElements are put inside an extra OverlayContainer; I just couldn't figure out how to do that particular casting trick with C#; this introduces foreach-loops when setting the (dis-)activated material for buttons, textinputs. If you're interested in fixing this, check out GUI.createOverlay.
- Added a keyDelay timer, because it was handy for me.
- Some extra checks for validity here and there (backspace handling).
- I didn't need the type=1 callbacks, so they're left out for the moment; if your needs differ, look at C# delegates.
- Maybe something else, but I've got a GUI now; using Mogre 0.2.0 & Visual Studio 2005 EE. Thanks again for Betajaen, his code is brilliant ^^
Usage instructions are as with the C++ version (here), but see bottom of page.
Cheers,
funguine (forums) / ketarax (#ogre3d)
Differences to Ogre version
- All OverlayElements are put inside an extra OverlayContainer; I just couldn't figure out how to do that particular casting trick with C#; this introduces foreach-loops when setting the (dis-)activated material for buttons, textinputs. If you're interested in fixing this, check out GUI.createOverlay.
- Added a keyDelay timer.
- Some extra checks for validity here and there (backspace handling).
- No "type=1" callbacks, so they're left out for the moment; if your needs differ, look at C# delegates.
Main source code
The Mogre port is related to BetaGUI revision 015 (also called 1.0'15).
/// Betajaen's GUI 015 Uncompressed
/// Originally written by Robin "Betajaen" Southern 07-Nov-2006, http://www.ogre3d.org/wiki/index.php/BetaGUI
/// This code is under the Whatevar! licence. Do what you want; but keep the original copyright header.
/// This code is not meant to be readable, if you base your future source on this, I will laugh at you.
using Mogre;
using System;
using System.Collections.Generic;
namespace BetaGUI
{
enum wt
{
NONE = 0,
MOVE = 1,
RESIZE = 2,
RESIZE_AND_MOVE = 3
};
public class GUI
{
public uint wc, bc, tc, oc;
public Overlay mO, mMPo;
public List<Window> WN = new List<Window>();
public Window mXW;
public OverlayContainer mMP;
public String mFont;
public uint mFontSize;
public Timer keyDelay = null;
public GUI(String font, uint fontSize)
{
mXW = null;
mMP = null;
mFont = font;
mFontSize = fontSize;
wc = 0;
bc = 0;
tc = 0;
oc = 0;
mO = OverlayManager.Singleton.Create("BetaGUI");
mO.Show();
}
public void hide()
{
for (int i = 0; i < WN.Count; i++)
WN[i].hide();
mMP.Hide();
}
public void show()
{
for (int i = 0; i < WN.Count; i++)
WN[i].show();
if ( mMP != null) mMP.Show();
}
public void killGUI()
{
for (int i = 0; i < WN.Count; i++)
WN[i].killWindow();
WN.Clear();
mMP.Hide();
foreach (OverlayContainer container in mO.Get2DElementsIterator())
{
foreach (OverlayElement element in container.GetChildIterator())
OverlayManager.Singleton.DestroyOverlayElement(element);
mO.Remove2D(container);
OverlayManager.Singleton.DestroyOverlayElement(container);
}
OverlayManager.Singleton.Destroy(mO);
foreach ( OverlayContainer container in mMPo.Get2DElementsIterator())
{
foreach (OverlayElement element in container.GetChildIterator())
OverlayManager.Singleton.DestroyOverlayElement(element);
mMPo.Remove2D(container);
OverlayManager.Singleton.DestroyOverlayElement(container);
}
OverlayManager.Singleton.Destroy(mMPo);
mMP = null;
if (keyDelay != null) keyDelay.Dispose();
}
public bool injectMouse(uint x, uint y, bool LMB)
{
if (mMP != null)
mMP.SetPosition(x, y);
if (mXW != null)
{
int i = 0;
foreach (Window win in WN)
{
if (mXW == win)
{
mXW.killWindow();
WN.RemoveAt(i);
return false;
}
i++;
}
}
for (int i = 0; i < WN.Count; i++)
{
if (WN[i].check(x,y, LMB))
{
return true;
}
}
return false;
}
public bool injectKey(String key, uint x, uint y)
{
if (keyDelay == null)
keyDelay = new Timer();
if (keyDelay.Milliseconds > 150)
{
for (int i = 0; i < WN.Count; i++)
{
if (WN[i].checkKey(key, x, y))
return true;
}
}
return false;
}
public void injectBackspace(uint x, uint y) { injectKey("!b", x, y); }
public Window createWindow(Vector4 D, String M, int T, String C)
{
Window w = new Window(D, M, T, C, this);
WN.Add(w);
return w;
}
public void destroyWindow(Window w) { mXW = w; }
public OverlayContainer createOverlay(String N, Vector2 P, Vector2 D,
String M, String C, bool A)
{
String t = "Panel";
if (C != "")
t = "TextArea";
OverlayElement e = OverlayManager.Singleton.CreateOverlayElement(t, N);
e.MetricsMode = GuiMetricsMode.GMM_PIXELS;
e.SetDimensions(D.x, D.y);
e.SetPosition(0, 0);
//if (M != "")
// e.MaterialName = M;
if (C != "")
{
e.Caption = C;
e.SetParameter("font_name", mFont);
e.SetParameter("char_height", StringConverter.ToString(mFontSize));
}
OverlayContainer c = (OverlayContainer)OverlayManager.Singleton.CreateOverlayElement("Panel", "ContainerHack" + (oc++).ToString());
c.MetricsMode = GuiMetricsMode.GMM_PIXELS;
c.SetDimensions(D.x, D.y);
c.SetPosition(P.x, P.y);
if (M != "")
c.MaterialName = M;
c.AddChild(e);
if (A)
{
mO.Add2D(c);
c.Show();
}
return c;
}
public OverlayContainer createMousePointer(Vector2 d, String m)
{
mMPo = OverlayManager.Singleton.Create("BetaGUI.MP");
mMPo.ZOrder = 649;
mMP = createOverlay("bg.mp", new Vector2(0, 0), d, m, "", false);
mMPo.Add2D(mMP);
mMPo.Show();
mMP.Show();
return mMP;
}
} // class GUI
public class Button
{
public OverlayContainer mO, mCP;
public String mmn, mma;
public Callback callback;
public uint x, y, w, h;
public Button(Vector4 D, String M, String T, Callback C, Window P)
{
x = (uint)D.x;
y = (uint)D.y;
w = (uint)D.z;
h = (uint)D.w;
mmn = M;
mma = M;
ResourcePtr ma = MaterialManager.Singleton.GetByName(mmn + ".active");
if (ma != null)
{
mma += ".active";
}
mO = P.mGUI.createOverlay(P.mO.Name + "b" +
StringConverter.ToString(P.mGUI.bc++),
new Vector2(x, y), new Vector2(w, h), M, "", false);
mCP = P.mGUI.createOverlay(mO.Name + "c",
new Vector2(4, (h - P.mGUI.mFontSize) / 2),
new Vector2(w, h), "", T, false);
P.mO.AddChild(mO);
mO.Show();
mO.AddChild(mCP);
mCP.Show();
callback = C;
}
public void killButton()
{
foreach (OverlayContainer container in mO.GetChildContainerIterator())
foreach (OverlayElement element in container.GetChildIterator())
OverlayManager.Singleton.DestroyOverlayElement(element);
foreach (OverlayElement element in mO.GetChildIterator())
OverlayManager.Singleton.DestroyOverlayElement(element);
mO.Parent.RemoveChild(mO.Name);
OverlayManager.Singleton.DestroyOverlayElement(mO);
}
public void activate(bool a)
{
if (!a && mmn != "")
mO.MaterialName = mmn;
if (a && mma != "")
mO.MaterialName = mma;
}
public bool isin(uint mx, uint my, uint px, uint py)
{
return (!(mx >= x + px && my >= y + py)) || (!(mx <= x + px + w && my <= y + py + h));
}
}
public class TextInput
{
public OverlayContainer mO, mCP;
public String mmn, mma, value;
public uint x, y, w, h, length;
public String getValue() { return value; }
public void setValue(String v) { mO.Caption = value = v; } // mCP here if ...
public TextInput(Vector4 D, String M, String V, uint L, Window P)
{
x = (uint)D.x;
y = (uint)D.y;
w = (uint)D.z;
h = (uint)D.w;
value = V;
mmn = M;
mma = M;
length = L;
ResourcePtr ma = MaterialManager.Singleton.GetByName(mmn + ".active");
if ( ma != null)
mma += ".active";
mO = P.mGUI.createOverlay(P.mO.Name + "t" +
StringConverter.ToString(P.mGUI.tc++),
new Vector2(x, y), new Vector2(w, h), M, "", false);
mCP = P.mGUI.createOverlay(mO.Name + "c",
new Vector2(0, (h - P.mGUI.mFontSize) / 2),
new Vector2(w, h), "", V, false);
P.mO.AddChild(mO);
mO.Show();
mO.AddChild(mCP);
mCP.Show();
}
public void killTextInput()
{
foreach (OverlayContainer container in mO.GetChildContainerIterator())
foreach (OverlayElement element in container.GetChildIterator())
OverlayManager.Singleton.DestroyOverlayElement(element);
foreach (OverlayElement element in mO.GetChildIterator())
OverlayManager.Singleton.DestroyOverlayElement(element);
mO.Parent.RemoveChild(mO.Name);
OverlayManager.Singleton.DestroyOverlayElement(mO);
}
public void activate(bool a)
{
if (!a && mmn != "")
mO.MaterialName = mmn;
if (a && mma != "")
mO.MaterialName = mma;
}
public bool isin(uint mx, uint my, uint px, uint py)
{
return (!(mx >= x + px && my >= y + py)) || (!(mx <= x + px + w && my <= y + py + h));
}
}
public class Window
{
public TextInput mATI;
public Button mRZ, mAB, mTB; // resize, activebutton, titlebar
public uint x, y, w, h;
public GUI mGUI;
public OverlayContainer mO;
public List<Button> mB = new List<Button>();
public List<TextInput> mT = new List<TextInput>();
public Button createButton(Vector4 D, String M, String T, Callback C)
{
Button x = new Button(D, M, T, C, this);
mB.Add(x);
return x;
}
public TextInput createTextInput(Vector4 D, String M, String V, uint L)
{
TextInput x = new TextInput(D, M, V, L, this);
mT.Add(x);
return x;
}
public void createStaticText(Vector4 D, String T)
{
OverlayContainer x = mGUI.createOverlay(mO.Name +
StringConverter.ToString(mGUI.tc++),
new Vector2(D.x, D.y), new Vector2(D.z, D.w), "", T, false);
mO.AddChild(x);
x.Show();
}
public void hide() { mO.Hide(); }
public void show() { mO.Show(); }
public bool isVisible() { return mO.IsVisible; }
public Window(Vector4 D, String M, int t, String C, GUI G)
{
x = (uint) D.x;
y = (uint) D.y;
w = (uint) D.z;
h = (uint) D.w;
mGUI = G;
mTB = null;
mRZ = null;
mATI = null;
mAB = null;
mO = G.createOverlay("BetaGUI.w" + StringConverter.ToString(G.wc++),
new Vector2(D.x, D.y),
new Vector2(D.z, D.w), M, C, true);
if (t >= 2)
{
Callback c = new Callback();
c.t = 4;
mRZ = createButton(new Vector4(D.z - 16, D.w - 16, 16, 16), M + ".resize", "", c);
}
if (t == 1 || t == 3)
{
Callback c = new Callback();
c.t = 3;
mTB = createButton(new Vector4(0, 0, D.z, 22), M + ".titlebar", C, c);
}
}
public void killWindow()
{
for (int i = 0; i < mB.Count; i++)
mB[i].killButton();
for (int i = 0; i < mT.Count; i++)
mT[i].killTextInput();
}
public bool check(uint px, uint py, bool LMB)
{
if (!mO.IsVisible)
return false;
if (!(px >= x && py >= y) || !(px <= x + w && py <= y + h))
{
if (mAB != null)
mAB.activate(false);
return false;
}
if (mAB != null)
mAB.activate(false);
for (int i = 0; i < mB.Count; i++)
{
if (mB[i].isin(px, py, x, y))
continue;
if (mAB != null )
mAB.activate(false);
mAB = mB[i];
mAB.activate(true);
if (mATI != null)
{
mATI.activate(false);
mATI = null;
}
if (!LMB) return true;
switch (mAB.callback.t)
{
default:
return true;
case 1:
//mAB.callback.fp(mAB); // FIX / what is this
return true;
case 2:
mAB.callback.LS.onButtonPress(mAB);
return true;
case 3:
mO.SetPosition(x = px - (mAB.w / 2), y = py - (mAB.h / 2));
return true;
case 4:
mO.SetDimensions(w = px - x + 8, h = py - y + 8);
mRZ.mO.SetPosition(mRZ.x = w - 16, mRZ.y = h - 16);
if (mTB != null)
{
mTB.mO.Width = mTB.w = w;
}
return true;
}
}
if (!LMB)
return true;
for (int i = 0; i < mT.Count; i++)
{
if (mT[i].isin(px, py, x, y))
continue;
mATI = mT[i];
mATI.activate(true);
return true;
}
if (mATI != null)
{
mATI.activate(false);
mATI = null;
}
return true;
}
public bool checkKey(String k, uint px, uint py)
{
if (mATI == null)
return false;
if (!mO.IsVisible)
return false;
if (!(px >= x && py >= y) || !(px <= x + w && py <= y + h))
return false;
if (k == "!b" && mATI.value.Length > 0)
{
mATI.setValue(mATI.value.Substring(0, mATI.value.Length - 1));
foreach (OverlayElement element in mATI.mCP.GetChildIterator())
element.Caption = mATI.value;
mGUI.keyDelay.Reset();
return true;
}
if (mATI.value.Length >= mATI.length)
return true;
if ( k != "!b")
mATI.value += k;
foreach ( OverlayElement element in mATI.mCP.GetChildIterator() ) // take from mCP if ...
element.Caption = mATI.value;
mGUI.keyDelay.Reset();
return true;
}
}
public interface BetaGUIListener
{
void onButtonPress(Button referer);
}
public class Callback
{
public uint t;
public BetaGUIListener LS;
public Callback() { t=0; }
public Callback (BetaGUIListener L) { t=2; LS=L; }
}
}
Usage
- Add a link to the MOIS.dll library (see MOIS)
- Add the Betajaen's GUI Resources
- Add :BetaGUIListener inheritence to your Scene() class definition
Here's the creation of a simple user interface:
Button single;
Button lanmulti;
Button netmulti;
GUI mGui = new GUI("StarWars", 24);
mGui.createMousePointer(new Vector2(30, 30), "bgui.pointer");
BetaGUI.Window window = mGui.createWindow(new Vector4(viewport.ActualWidth/4,
viewport.ActualHeight/4, viewport.ActualWidth/2, viewport.ActualHeight/2),
"bgui.window", (int)BetaGUI.wt.RESIZE_AND_MOVE, "Select game mode");
Callback cc = new Callback(this); // remember to give your program the BetaGUIListener interface
single = window.createButton(new Vector4(0, 30, viewport.ActualWidth/2, 30), "bgui.button", "Single Player", cc);
lanmulti = window.createButton(new Vector4(0, 60, viewport.ActualWidth/2, 30), "bgui.button", "LAN Multiplay", cc);
netmulti = window.createButton(new Vector4(0, 90, viewport.ActualWidth/2, 30), "bgui.button", "Internet Multiplay", cc);
window.createTextInput(new Vector4(0, 120, viewport.ActualWidth / 2, 30), "bgui.textinput", "testing", 20);
window.show();
Then the BetaGUIListener callback (the buttons single, lanmulti and netmulti as well as mGui are globally accessible):
The enumeration PlayMode doesn't really exist, it's just for demonstration purposes.
public void onButtonPress(Button butt)
{
if (butt == single)
{
Console.WriteLine("Play solo!");
}
else if (butt == lanmulti)
{
Console.WriteLine("Play in LAN!");
}
else if (butt == netmulti)
{
Console.WriteLine("Play in Internet!");
}
else
{
Console.WriteLine("*Some* button was pressed!");
}
mGui.hide();
}
And an amazingly crude delivery of user input to the gui; I do this in frameStarted():
Note: This is just an example, you have to implement your own keycodes to support more keys.
if (mGui != null)
{
MOIS.MouseState_NativePtr mouseState = inputMouse.MouseState;
uint screenx = (uint)(viewport.ActualWidth * ((float)mouseState.X.abs / 50f));
uint screeny = (uint)(viewport.ActualHeight * ((float)mouseState.Y.abs / 50f));
if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_BACK))
{
//mGui.injectBackspace(screenx, screeny);
mGui.injectKey("!b", screenx, screeny);
}
if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_1))
{
mGui.injectKey("1", screenx, screeny);
}
if (mouseState.ButtonDown(MOIS.MouseButtonID.MB_Left))
{
mGui.injectMouse(screenx, screeny, true);
}
else
{
mGui.injectMouse(screenx, screeny, false);
}
}
Documentation?
No class member is documented and many names are cryptical at the moment.
It would be great, if someone could add XML descriptions to important members!
Maybe also rename variable / method / attribute names?
On changing the code please tell it in wiki log.
See also
- BetaGUI
- MOIS (key and mouse interaction)
- MQuickGUI (an other GUI system for Mogre)
- Mogre CEGUI
- Overlays (the basic 2D elements in Ogre)
- Source code to extend MogreBetaGUI with alterable overlays


