XBox:Framework:Widgets
From MadoxLabs
|
Edit Downloads:XBox (http://madox.ca/mediawiki2/index.php?title=Template:Downloads:XBox&action=edit)
|
Added Container and Label widgets to the UI today.
The current UI object hierarchy is as follows:
- Placeable - an object that has a location and size. This is both componants and widgets
- ComponantLink - this is a placeholder for a UI skin componant. It defines the place on the screen that the sprite goes.
- Widget - A basic object that is composed of any number of componantlinks. Widgets can be active/inactive and have a fg/bg color
- ParentWidget - This is a widget that can be composed of both ComponantLinks and other widgets.
A Container is simply a parentwidget that has specially defined componants to make it look like a window. In C++ a container is the only object that supports free floating child widgets that can be dragged around. It can also be resized. Both of these are not so relavent in XBox.
A Label is a special widget that uses text componants as its componant links. It supports colors and wrapping. The label's text must come from a DataWrapper that was published via the Library. Fonts are implemented as a skin with each letter in the font defined as a componant. An example is:
Componant MyFont_? 348 63 16 47 Componant MyFont_@ 8 118 27 47 Componant MyFont_A 43 118 20 47 Componant MyFont_B 71 118 18 47 Componant MyFont_C 97 118 19 47 Componant MyFont_D 124 118 20 47 Componant MyFont_E 152 118 18 47
Each componant is prefixed with the font name. Each font is fixed size since they are defined by the related texture.
Entering in all those componant is a giant pain, so I modified the XNA tff2bmp tool to generate skin files for use with MxLTools.
Update 2010-10-10
The UI library is fully completed. It is features fully skinnable widgets that are definable with a script. Available widgets include buttons, sliders, scrollbars, tab controls and dropdowns.
Since the XBox doesn't have a keyboard or mouse, I also added the idea of having a focus that the players move around. The widget being focused on receives the commands from the controller. The UI can also define commands using a sequence of key or button strokes. When the command is stroked, an event is fired.
Here is some excerpts from the documentation, which has more information:
The User Interface component is made up of a number of elements that are used to draw a 2d interactive set of widgets.
- Widgets respond to controller inputs and display a graphic from a skin. Widgets can also provide a commandConfig to the player interacting with it. - Skins are stored in the mxSkinManager. Some skins can get their image from a live rendering. - The UI graphic is created by mxUISurface, which also hold the widgets in the current UI. - mxUIManager drives the mxUISurface and handles the linkage between the UI and the Players.
The mxUIManager manages the player focuses. The UI can display distinct focus elements for each Player, or have all players share a focus. When a certain widget gains focus, the player(s) with the focus can gain extra command configs that are only valid within that widget. Widgets can also provide command configs to all players, regardless of focus, as long as they are visible.
Typically, the result of generating a UI texture via mxUISurface is used as a fullscreen overlay with transparency.
Theoretically, the result of generating a UI texture via mxUISurface can itself be used as a live texture for use in other UIs, or used as a texture in the core engine to display UIs on oblique surfaces in game. In the latter case, we still need a system that projects screen clicks to a click on the in game surface.
mxSkin.cs
mxSkin gets auto-created using Content.Load() and the builtin content parsers. mxSkin contains a texture and a set of named rectangle areas. Widgets access graphic data from the skin using the names to get that portion of the image. mxSkin can also represent an animated texture, containing an array of frames of aniamtions. The skin itself can only contain a single componant the size of a frame of animation. The skin manager will blt frames as needed from the skin and make the current frame available in the baked texture. If a skin is getting its image from a live render instead of a texture, mxLiveSkin is used instead. It is meant to be derived from and overloaded to do any dynamic rendering is needed. It contains a surface to render to and a Render() call. Render() should set refresh to false if the call did not actually create a new rendering. This lets the skin manager optimize performance.
mxSkinManager.cs
mxSkinManager is the repository of all mxSkin objects and handles giving out the rectangle regions. It is a singleton object. The skin manager takes all active mxSkins and bakes them into a single texture that contains all the skins. The various rectangle regions are converted into mxComponants. Theoretically, the result of the baking could be multiple textures, but currently a single texture is the result. For animated and live skins, the new frames are copied to the baked texture everytime a new frame is available. mxComponant holds the baked-skin id, rectangle and name for the region. A componant can also be set to stretch to fill a space, or tile. The default is to tile. Live skin componants will default to stretch.
BinSorter.cs
This is used by the Skin Manager to take the collection of active skins and
arrange them together so that the total area they take up is as small as
possible. This arrangement is then used to create the baked texture and the
skin textures are blted onto the baked texture.
mxLayout.cs
This file contains classes that are used to position UI elements relative to
each other. Anything that is able to be placed on screen uses the class
mxLayoutDef. This defines that layout position of the element. mxLayoutDef
contains the object and the positions of the topleft and bottomright corners.
Corners are defined by mxCorner. Each corner can be positioned relative to
another element or placed absolutely. The X and Y locations are set using
values from mxPlace. Not all mxPlace values are valid for all corner X and Ys.
Objects that contain other objects that get positioned should use or derive
from the mxLayout class. The Arrange() function will operate on all the
elements to be positioned and set their position in the UI using their Place()
function.
Corner definitions:
TopLeft
X
LeftOf - this is adjacent to the relative's left side
Fixed - this is placed absolutely
LeftAlign - the left edge is aligned with the relative's left edge
RightOf - this is adjacent to the relative's right side
RightAlign - the right edge is aligned with the relative's right edge
Center - this's center is equal to the relative's center
CenterAlign - this's left edge is equal to the relative's center
Y
Below - this is adjacent to the relative's bottom side
BottomAlign - the bottom edge is aligned with the relative's bottom edge
Above - this is adjacent to the relative's top side
TopAlign - the top edge is aligned with the relative's top edge
Fixed - this is placed absolutely
Center - this's center is equal to the relative's center
CenterAlign - this's left edge is equal to the relative's center
BottomRight
X
CenterAlign - this's width is aligned with the relative's center
LeftAlign - this's width is aligned with the relative's left edge
RightAlign - this's width is aligned with the relative's right edge
Fixed - this's width is placed absolutely
Y
CenterAlign - this's height is aligned with the relative's center
TopAlign - this's height is aligned with the relative's top edge
BottomAlign - this's height is aligned with the relative's bottom edge
Fixed - this's height is placed absolutely
When placing objects relative to other objects, the arrangement will fail if the objects are processed in the wrong order. Always make sure objects being referenced are processed before objects referencing them. Also, widgets will process child widgets before processing skin componants. Sometimes multiple calls to Arrange() are needed if you can not get the objects in a good enough order for one call.
mxUIManager.cs
mxUIManager contains the mxUISurface and is the link between the game, the UI and the mxPlayer objects. It also contains a list of all widgets, focus and shift objects. The currently actuve focus definition is tracked, and the UI Manager is able to publish strings for use in widgets, and provide widget ID numbers for auto- created child widgets. The main job of the UI manager is linking actions from Player objects to the widgets in the UI. This is done using the Focus and Shift objects. The Focus is a definition of a visual element that the player can move around in the UI. It represents the widget that the player is focused on. One of more focuses can be active simultaneouly and multiple players and move a common focus around. A Focus can also provide certain CommandConfigs to the players the focus is assigned to. The Shift is a definition of the paths that a Focus can move along. It is a chain of widgets linked together by direction. A focus can move from one widget to another as long as the widgets are linked by a direction. A Shift can restrict different players to different paths if needed. A Focus typically assigns a special CommandConfig to its players which grants them the commands to move up/down/left/right. The UI Manager handles these commands and drives the OnFocusIn() and OnFocusOut() events on widgets. When a widget gains or loses focus, it adds or removes the visual element of the focus from itself. The UI Manager also handles any commands that are targetting a widget and forwards them on. Most widget commands are assumed to be targetting the currently focused widget, but some widgets can have global commands that do not need them to be focused on. There are also commands that hide/show widgets, assign/remove command configs and change the current Focus definition.
mxUISurface.cs
mxUISurface contains the DirectX surface that the UI is being rendered to. It creates the vertex and index buffers by examining the widgets, then renders the whole mess.
mxFocus.cs
This contains the classes that make up the mxFocus and mxShift collection of classes.
These are described in the mxUIManager section above.
mxWidget.cs
This file contains all the base classes that are used to represent UI elements. There are different base classes depending on the nature of the element that is needed. mxPlaceable is needed by any element that is able to be placed in the UI. This is all of them. mxPlaceable is used exclusively by mxLayout to call Place() in order to position the element. mxPlaceable holds the rectangle that defines the position. mxComponantLink is a type of mxPlaceable used to represent a certain mxComponant from the baked skin. If you want to place a non-interactive graphical element in the UI, that is the job of mxComponantLink. It links a mxComponant to the UI. A mxComponantLink can be set to stretch or tile to fill its position, and can also be skipped by the renderer if needed. mxWidget is the base class of all the more complex widgets. A widget is a UI element that is composed of many mxComponantLinks, which are positioned using a mxLayout. A mxWidget can be visible or not, has foreground and background colours, and has a cliprect. The cliprect is the area that is considered inside the widget where its componants are. An mxWidget will usually assign a new commandConfig to any players with focus on the widget. This is to add controls for button press, scrolling, opening dropdowns etc mxParentWidget is a mxWidget that is able to have other mxWidgets placed inside it. mxParentWidget has a layout for child widgets as well as the mxComponantLink layout. It also has an offset to shift the child widgets so they can be scrolled.
mxLabel.cs
mxLabel is a widget that displays a text string using a certain font. The mxLabel
doesn't do a lot since it is the mxUISurface that does the text drawing. Note that
the size of the mxLabel can not be dependant on the size of the text string.
Fonts are just ordinary skins that get baked with all the other skins. The texture
and skin definition should contain all the characters needed to draw text. A font
has a fixed style and pointsize. Font skin files can be created using the modified
ttf2bmp tool. This tool will output the texture containing the desired letters as
well as the skin file containing the rectangles for each letter.
mxContainer.cs
mxContainer is a mxParentWidget that has visible edges, like a window. It automatically defines a set of mxComponantLinks depending on the border setting. The components used can be altered to get custom looking windows.
mxButton.cs
mxButton is a mxParentWidget that acts as an image button or a text button. The componants used to draw the button are fully definable. The button can be set to be a checkbox, or can be a part of a radio button group. When pressed, the button can trigger an event. It also publishes its state.
mxSlider.cs
mxSlider is a horizontal slider widget that moves by increments between a minimum
and maximum value. The Slider is skinnable like other widgets and publishes
its current position.
mxTabControl.cs
mxTabControl is a special control that manages a set of containers. Only one container can
be visible at any one time. The tab control also has a set of title widgets, one for each
container. When a container is visible, the matching title widget is also visible. Finally,
the tab control also contains two buttons that are used to move from container to
container, selecting the visible one.
mxScrollbar.cs
mxScrollbar affects the offset of the container widget it is a child of. The UISurface uses
the parent's clip rect and offset to render the proper part of the container. The scrollbar
is unaffected by the offset. THe scrollbar's docsize must be set to the height of the
container's content, not the height of the visible area on the container.
mxScrollbar publishes the thumb position in pixels.
mxDropdown.cs
mxDropdown allows for multiple choice from a published array of values. It has a skinnable button that opens and closes a scrollable container of choices.