Expand description
§banished-ui
A reimplementation of Banished’s interface system (UI::Element and the classes around it, in
Runtime-steam-x64.dll). The game ships its windows as resources (Dialog/*.rsc): trees of
elements with sprite sheets, fonts and string tables. This crate builds those trees, sizes and
places the elements as the original does, handles the pointer and the keyboard, and produces a
list of textured quads that a renderer draws.
- Sizes are computed bottom-up and positions top-down, as
ComputeSizeandComputeLayoutdo. - Text layout follows
UI::Font::ComputeStringLayout; documents with markup (the help and the tutorials) followDocumentTextElement. - The controls are the original’s: buttons, check boxes, lists, combo boxes, sliders, edit boxes, tables, graphs, tooltips.
- The crate contains no rules of the game. A dialog’s controllers (the code behind a window) are the application’s; the crate tells the application which controller is attached to which element.
- It does not draw.
banished-gfxdraws its quads with wgpu.
§Use it
[dependencies]
banished-ui = { path = "crates/ui" }
banished-formats = { path = "crates/formats" }§Show a dialog
use std::rc::Rc;
use banished_formats::pkg::Archive;
use banished_ui::{Quad, Ui};
fn main_menu(archive: Rc<Archive>) -> Option<Vec<Quad>> {
let mut ui = Ui::new(archive);
ui.screen = [1280, 720];
// Build the element tree of a packaged dialog.
let dialog = ui.instantiate_dialog("Dialog/MainMenu.rsc:resource")?;
// Size the elements and place the dialog by its alignment on a 1280 × 720 screen.
ui.layout_dialog(dialog.root, [0, 0, 1280, 720]);
// Find an element by the name it has in the resource.
let new_game = ui.find(dialog.root, "buttonNew")?;
println!("New Game is at {:?}", ui.node(new_game).rect);
// The quads to draw, in order.
Some(ui.draw(dialog.root))
}Each Quad has a texture (a sprite sheet, or an application texture), a rectangle in pixels,
texture coordinates, a colour, an optional clip rectangle and a rotation.
§Handle input
use banished_ui::{Event, NodeId, Ui};
fn click(ui: &mut Ui, root: NodeId, x: i32, y: i32) {
ui.pointer_move(x, y, root);
ui.pointer_button(true, root);
// The click event is returned on release; other events are queued.
if let Some(Event::Clicked(id)) = ui.pointer_button(false, root) {
println!("clicked {}", ui.node(id).name);
}
for event in ui.drain_events() {
println!("{event:?}");
}
}Event is Clicked, Selected (a list item), Changed (a check box, slider or edit box),
Submitted (Enter in an edit box) or Link (a link in a document). ui.key(root, key) passes a
key press; banished_ui::Key lists the keys.
§Change what a dialog shows
use banished_ui::{NodeId, Ui};
fn fill(ui: &mut Ui, root: NodeId) {
if let Some(title) = ui.find(root, "textTitle") {
ui.set_text(title, "Hello");
}
if let Some(list) = ui.find(root, "listSaves") {
ui.set_list_items(list, vec!["Town one".into(), "Town two".into()]);
ui.list_select(list, Some(0));
}
}Other helpers: set_visible, set_icon, select_combo_item, set_list_icons, and the
control accessors in controls.rs. Strings come from the string tables through
ui.res.string(table, key); sprites through ui.res.sprite(sheet, name).
§Controllers
A DialogInstance lists its bindings: which controller type is attached to which element, with
its configuration. The application implements the controllers. DialogInstance::dispatch
delivers an event to every controller on the element or on one of its parents.
§Source files
| File | What it contains |
|---|---|
src/lib.rs | Ui, Node, Kind, Quad, Event; instantiation, layout, drawing |
src/dialog.rs | DialogInstance and Binding: template substitution and controllers |
src/controls.rs | The stateful controls and their helpers |
src/input.rs | The pointer, the keyboard, focus and tooltips |
src/text.rs | Text layout |
src/document.rs | Documents with markup |
src/resources.rs | A cache of sprite sheets, fonts, element descriptions and strings |
§Tests
cargo test --release -p banished-uitests/controls.rs checks the controls with your game data, and skips without it.
§The API
The full API documentation is at https://tanepiper.github.io/unbanished/api/banished_ui/index.html.
§Related documents
Modules§
- tooltip_
controller - The type ids (CRC-32 of the class name) of the game’s tooltip controllers that the interface handles itself.
Structs§
- Binding
- A controller attached to an element of a dialog.
- Dialog
Instance - A dialog made from its resource: the element tree and its controllers.
- Edit
Data - The state of an edit box.
- Element
Info - What a query reports about one element.
- List
Data - The rows of a list.
- Loaded
Font - A loaded font.
- Loaded
Sheet - A loaded sprite sheet.
- Node
- One element of the interface tree.
- Quad
- One textured rectangle to draw.
Ui::drawreturns them in drawing order. - Query
- A parsed query: its steps, in order.
- Resources
- The resource cache.
- Slider
Data - The state of a slider.
- Sprite
Ref - One sprite: its sheet, its size and its place on the sheet.
- Text
Data - The text of a text element or a label, with its font and the result of its layout.
- Text
Layout - Laid-out text: each glyph’s place, and the size of the whole.
- Ui
- The interface: the element tree, the resources it uses, and the state of the pointer and the keyboard.
Enums§
- Control
- A control and its state.
- Event
- Something the player did to an element.
- Key
- A key the interface reacts to.
- Kind
- What an element is, with the state of its class.
- Step
- One step of a query.
- Texture
- What a quad samples from.
Type Aliases§
- FontId
- The index of a font in
Resources::fonts. - NodeId
- The index of an element in
Ui::nodes. - SheetId
- Index of a sprite sheet in
Resources::sheets.