TX2D 3.0.0.0 GUIBitmapButton resource
by Jason Cahill · 07/14/2009 (11:06 pm) · 3 comments
Description:
This is a new GUI control for a bitmap-based button with text. GUIButton is strictly a rectangle/border with text. As with all GUI controls, there is a Style class and the actual GUIBitmapButton. The Style is meant to be shared across multiple buttons in the same UI. I put the image loading code into the Style, so it is easily shared across a set of buttons.
How to build:
Copy and paste this source code into a new file TorqueCoreGUIGUIBitmapButton.cs. Rebuild your engine.
Things to know:
Basically, you three things: A GUIBitmapButtonStyle, a GUIBitmapButton control, and a bitmap image that conforms to the following rule: the image is assumed to contain 4 equal heighted chunks: normal, selected, pushed, and not active. So, if you have a button image for your normal state that is 200x100, you need to supply an image that is 200x400 with pixels (0,0)-(199,99) for normal, (0,100)-(199,199) for selected, (0,200)-(199,299) for pushed, and (0,300)-(199,399) for not active. You can have an optional border and text with text colors. Here is a sample usage of the control:
Here's the full source code for the control. I grant free use of this code to anyone for any purpose, indie or commercial. I grant GarageGames full, royalty free use of this source code for inclusion in a future release of Torque X.
Also in TorqueCore\Core\Xml\TorqueSceneData.cs, add the following lines beneath GUISplashStyle (line 297):
This is a new GUI control for a bitmap-based button with text. GUIButton is strictly a rectangle/border with text. As with all GUI controls, there is a Style class and the actual GUIBitmapButton. The Style is meant to be shared across multiple buttons in the same UI. I put the image loading code into the Style, so it is easily shared across a set of buttons.
How to build:
Copy and paste this source code into a new file TorqueCoreGUIGUIBitmapButton.cs. Rebuild your engine.
Things to know:
Basically, you three things: A GUIBitmapButtonStyle, a GUIBitmapButton control, and a bitmap image that conforms to the following rule: the image is assumed to contain 4 equal heighted chunks: normal, selected, pushed, and not active. So, if you have a button image for your normal state that is 200x100, you need to supply an image that is 200x400 with pixels (0,0)-(199,99) for normal, (0,100)-(199,199) for selected, (0,200)-(199,299) for pushed, and (0,300)-(199,399) for not active. You can have an optional border and text with text colors. Here is a sample usage of the control:
<GUIBitmapButtonStyle name="MyBitmapButtonStyle">
<FontType>Arial22</FontType>
<HasBorder>true</HasBorder>
<IsOpaque>true</IsOpaque>
<Active>false</Active>
<Focusable>true</Focusable>
<BorderColors>
<ColorBase><X>255</X><Y>255</Y><Z>255</Z><W>255</W></ColorBase>
<ColorHL><X>0</X><Y>255</Y><Z>0</Z><W>255</W></ColorHL>
<ColorSEL><X>128</X><Y>128</Y><Z>128</Z><W>255</W></ColorSEL>
<ColorNA><X>0</X><Y>0</Y><Z>255</Z><W>255</W></ColorNA>
</BorderColors>
<FillColors>
<Color><X>0</X><Y>0</Y><Z>255</Z><W>255</W></Color>
</FillColors>
<TextColors>
<ColorBase><X>255</X><Y>255</Y><Z>255</Z><W>255</W></ColorBase>
<ColorHL><X>254</X><Y>194</Y><Z>43</Z><W>255</W></ColorHL>
<ColorSEL><X>0</X><Y>0</Y><Z>0</Z><W>255</W></ColorSEL>
<ColorNA><X>0</X><Y>0</Y><Z>0</Z><W>255</W></ColorNA>
</TextColors>
<Alignment>JustifyCenter</Alignment>
<SizeToText>true</SizeToText>
<Bitmap>dataimagesbutton</Bitmap>
</GUIBitmapButtonStyle>
<GUIBitmapButton name="button1">
<Style nameRef="MyBitmapButtonStyle"/>
<ButtonText>Two</ButtonText>
<Active>true</Active>
<Position>
<X>503</X>
<Y>317</Y>
</Position>
<Size>
<X>277</X>
<Y>94</Y>
</Size>
<HorizSizing>Left</HorizSizing>
<VertSizing>Top</VertSizing>
</GUIBitmapButton>Here's the full source code for the control. I grant free use of this code to anyone for any purpose, indie or commercial. I grant GarageGames full, royalty free use of this source code for inclusion in a future release of Torque X.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using GarageGames.Torque.Core;
using GarageGames.Torque.GFX;
using GarageGames.Torque.Sim;
using GarageGames.Torque.MathUtil;
using GarageGames.Torque.Platform;
using GarageGames.Torque.Util;
using System.Xml.Serialization;
namespace GarageGames.Torque.GUI
{
/// <summary>
/// The style properties for the GUIBitmapButton control.
/// </summary>
public class GUIBitmapButtonStyle : GUIStyle
{
//======================================================
#region Public properties, operators, constants, and enums
/// <summary>
/// Whether the GUIBitmapButton control should resize itself to the same
/// dimensions of the specified bitmap.
/// </summary>
public bool SizeToBitmap
{
get { return _sizeToBitmap; }
set { _sizeToBitmap = value; }
}
/// <summary>
/// The font resource used when rendering the text. The font resource
/// contains glyph information and is used by the FontRenderer. The
/// font resource is created when the FontType property is specified.
/// </summary>
public Resource<SpriteFont> Font
{
get
{
if (_font.IsInvalid)
_font = ResourceManager.Instance.LoadFont(_fontType);
return _font;
}
}
/// <summary>
/// The font to use for rendering the text. The default engine fonts are
/// specified in the project TorqueEngineData.
/// <example>style.FontType = "Arial16";</example>
/// </summary>
public string FontType
{
get { return _fontType; }
set
{
_fontType = value;
if (_fontType != String.Empty)
_font = ResourceManager.Instance.LoadFont(_fontType);
}
}
/// <summary>
/// The color of the text when rendered.
/// </summary>
public ColorCollection TextColor
{
get { return _textColor; }
}
/// <summary>
/// Defines the horizontal text justification.
/// </summary>
public TextAlignment Alignment
{
get { return _textAlignment; }
set { _textAlignment = value; }
}
/// <summary>
/// The image file to render to the screen.
/// </summary>
public string Bitmap
{
get { return _bitmapName; }
set
{
_bitmapName = value;
if (_bitmapName != String.Empty)
{
if (_material != null)
_material.Dispose();
_material = new Materials.SimpleMaterial();
_material.TextureFilename = _bitmapName;
_material.IsTranslucent = true;
_material.IsColorBlended = true;
// rdbnote: the render material should really handle this for me
Resource<Texture> res = ResourceManager.Instance.LoadTexture(_material.TextureFilename);
Texture2D texture = (Texture2D)res.Instance;
_bitmapSize = new Vector2(texture.Width, texture.Height);
// invalidate the temp. resource
res.Invalidate();
}
else
{
if (_material != null)
_material.Dispose();
_material = null;
}
}
}
public Materials.SimpleMaterial Material
{
get { return _material; }
}
public Vector2 BitmapSize
{
get { return _bitmapSize; }
}
#endregion
//======================================================
#region Public methods
public override void OnLoaded()
{
base.OnLoaded();
for (int i = 0; i < _textColorAsVector4.Count; i++)
{
TextColor[(CustomColor)i] = new Color(_textColorAsVector4[i] / 255.0f);
}
}
#endregion
//======================================================
#region Private, protected, internal fields
string _fontType;
Resource<SpriteFont> _font;
// This is an image made up of four evenly sized chunks: normal, selected, pushed, and not active
string _bitmapName = String.Empty;
Materials.SimpleMaterial _material = null;
Vector2 _bitmapSize;
ColorCollection _textColor = new ColorCollection();
TextAlignment _textAlignment = TextAlignment.JustifyLeft;
bool _sizeToBitmap = true;
[XmlElement(ElementName = "TextColors")]
[TorqueXmlDeserializeInclude]
protected List<Vector4> _textColorAsVector4 = new List<Vector4>();
#endregion
}
/// <summary>
/// Renders a skinnable button.
/// </summary>
public class GUIBitmapButton : GUIControl
{
//======================================================
#region Constructors
public GUIBitmapButton()
{
int gamepadId = InputManager.Instance.FindDevice("gamepad0");
int keyboardId = InputManager.Instance.FindDevice("keyboard0");
InputMap.BindCommand(gamepadId, (int)XGamePadDevice.GamePadObjects.A, SetButtonPushed, SetButtonSelected);
InputMap.BindCommand(keyboardId, (int)Keys.Enter, SetButtonPushed, SetButtonSelected);
}
#endregion
//======================================================
#region Public properties, operators, constants, and enums
/// <summary>
/// Defines the various states of a button.
/// </summary>
public enum ButtonState
{
Normal = 0, // regular look
Selected, // has focus
Pushed, // receiving input
NumStates
}
/// <summary>
/// The string to render on the button.
/// </summary>
public string ButtonText
{
get { return _buttonText; }
set { _buttonText = value; }
}
/// <summary>
/// This delegate is called when the button is selectd.
/// </summary>
public OnButtonSelected OnSelectedDelegate
{
get { return _selectedDelegate; }
set { _selectedDelegate = value; }
}
#endregion
//======================================================
#region Public methods
public override void OnRender(Vector2 offset, RectangleF updateRect)
{
Profiler.Instance.StartBlock("GUIBitmapButton.OnRender");
bool highlight = _buttonState == ButtonState.Selected;
bool depressed = _buttonState == ButtonState.Pushed;
// clear bitmap modulation
DrawUtil.ClearBitmapModulation();
RectangleF ctrlRect = new RectangleF(offset, _bounds.Extent);
int imageIndex;
CustomColor colorIndex;
if (!Active)
{
imageIndex = 3;
colorIndex = CustomColor.ColorNA;
}
else
{
if (depressed)
{
imageIndex = 2;
colorIndex = CustomColor.ColorSEL;
}
else if (highlight)
{
imageIndex = 1;
colorIndex = CustomColor.ColorHL;
}
else
{
imageIndex = 0;
colorIndex = CustomColor.ColorBase;
}
}
if (_style.Material != null)
{
RectangleF srcRegion = new RectangleF();
RectangleF dstRegion = new RectangleF();
srcRegion.X = 0;
srcRegion.Y = imageIndex * (_style.BitmapSize.Y / 4);
srcRegion.Width = _style.BitmapSize.X;
srcRegion.Height = (_style.BitmapSize.Y / 4);
dstRegion.X = offset.X;
dstRegion.Y = offset.Y;
dstRegion.Width = _bounds.Extent.X;
dstRegion.Height = _bounds.Extent.Y;
DrawUtil.BitmapStretchSR(_style.Material, dstRegion, srcRegion, BitmapFlip.None);
}
//// Fill in if appropriate
//if (Style.IsOpaque)
// DrawUtil.RectFill(ctrlRect, Style.FillColor[colorIndex]);
// Draw the border if appopriate
if (Style.HasBorder)
DrawUtil.Rect(ctrlRect, Style.BorderColor[colorIndex]);
// render justified text
Vector2 textPos = new Vector2(0.0f, 0.0f);
if (_buttonState == ButtonState.Pushed)
textPos += new Vector2(1.0f, 1.0f);
DrawUtil.JustifiedText(_style.Font, textPos, _bounds.Extent, _style.Alignment, _style.TextColor[colorIndex], _buttonText);
Profiler.Instance.EndBlock("GUIBitmapButton.OnRender");
}
public override bool OnInputEvent(ref TorqueInputDevice.InputEventData data)
{
// an inactive button is a disabled button
if (Active)
{
if (_inputMap != null)
{
if (_inputMap.ProcessInput(data))
{
if (data.EventAction == TorqueInputDevice.Action.Make)
{
_buttonState = ButtonState.Pushed;
}
else if (data.EventAction == TorqueInputDevice.Action.Break)
{
if (GUICanvas.Instance.GetFocusControl() == this)
_buttonState = ButtonState.Selected;
else
_buttonState = ButtonState.Normal;
}
return true;
}
}
// if the button is currently pushed, eat input until it is released
if (_buttonState == ButtonState.Pushed)
return false;
}
// if we got here, this control didn't handle the input,
// pass it up to the parent if we have one
return (Parent != null ? Parent.OnInputEvent(ref data) : false);
}
public override void OnGainFocus(GUIControl oldFocusCtrl)
{
base.OnGainFocus(oldFocusCtrl);
// only change state if the button is in normal mode
if (_buttonState == ButtonState.Normal)
_buttonState = ButtonState.Selected;
}
public override void OnLoseFocus(GUIControl newFocusCtrl)
{
base.OnLoseFocus(newFocusCtrl);
// only change state if the button is selected
if (_buttonState == ButtonState.Selected)
_buttonState = ButtonState.Normal;
}
public void SetButtonPushed()
{
_buttonState = ButtonState.Pushed;
}
public void SetButtonSelected()
{
_buttonState = ButtonState.Selected;
if (_selectedDelegate != null)
_selectedDelegate();
}
public override void CopyTo(TorqueObject obj)
{
base.CopyTo(obj);
GUIBitmapButton obj2 = (GUIBitmapButton)obj;
obj2.ButtonText = ButtonText;
obj2.OnSelectedDelegate = OnSelectedDelegate;
}
#endregion
//======================================================
#region Private, protected, internal methods
protected override bool _OnNewStyle(GUIStyle style)
{
_style = (style as GUIBitmapButtonStyle);
Assert.Fatal(_style != null, "GUIBitmapButton._OnNewStyle - control was assigned an invalid style!");
if (_style == null || !base._OnNewStyle(style))
return false;
return true;
}
#endregion
//======================================================
#region Private, protected, internal fields
string _buttonText = String.Empty;
ButtonState _buttonState = ButtonState.Normal;
GUIBitmapButtonStyle _style = null;
OnButtonSelected _selectedDelegate;
#endregion
}
}Also in TorqueCore\Core\Xml\TorqueSceneData.cs, add the following lines beneath GUISplashStyle (line 297):
_defaultTypeMap.Add("GUIBitmapButton", typeof(Torque.GUI.GUIBitmapButton));
_defaultTypeMap.Add("GUIBitmapButtonStyle", typeof(Torque.GUI.GUIBitmapButtonStyle));
#2
Can you explain how to work this if you don't have the source code?
08/05/2009 (11:25 am)
Quote:Also in TorqueCore\Core\Xml\TorqueSceneData.cs, add the following lines beneath GUISplashStyle (line 297):
_defaultTypeMap.Add("GUIBitmapButton", typeof(Torque.GUI.GUIBitmapButton)); _defaultTypeMap.Add("GUIBitmapButtonStyle", typeof(Torque.GUI.GUIBitmapButtonStyle));
Can you explain how to work this if you don't have the source code?
#3
03/14/2010 (7:48 am)
Yeah, it seems that if you don't, you are just at GarageGames' mercy until they decide to add it in :/
Torque Owner Brian Bond
Brian