Tutorial: Hello World
Build your first Horizon Lattice application.
What You’ll Learn
- Creating an Application instance
- Showing a Window
- Adding a Label widget
- Understanding the basic structure
Prerequisites
- Rust installed (1.89+)
- A new Cargo project
Project Setup
Create a new Rust project:
cargo new hello-lattice
cd hello-lattice
Add Horizon Lattice to Cargo.toml:
[dependencies]
horizon-lattice = "1.0"
Step 1: The Minimal Application
Every Horizon Lattice application starts with creating an Application. This initializes the event loop, graphics context, and platform integration.
Replace src/main.rs with:
use horizon_lattice::Application;
fn main() -> Result<(), horizon_lattice::LatticeError> {
// Initialize the application (must be first)
let app = Application::new()?;
// Run the event loop (blocks until quit)
app.run()
}
This compiles and runs, but does nothing visible because there’s no window.
Step 2: Create a Window
Windows are top-level containers for your UI. Import the Window widget and create one:
use horizon_lattice::Application;
use horizon_lattice::widget::widgets::Window;
fn main() -> Result<(), horizon_lattice::LatticeError> {
let app = Application::new()?;
// Create a window with title and size
let mut window = Window::new("Hello, World!")
.with_size(400.0, 300.0);
// Show the window
window.show();
app.run()
}
Now when you run the application, you’ll see an empty window titled “Hello, World!” that’s 400x300 pixels.
Window Properties
Windows support many properties via the builder pattern:
use horizon_lattice::widget::widgets::WindowFlags;
let mut window = Window::new("My App")
.with_size(800.0, 600.0) // Width x Height
.with_position(100.0, 100.0) // X, Y position
.with_minimum_size(320.0, 240.0) // Minimum allowed size
.with_flags(WindowFlags::DEFAULT);
Step 3: Add a Label
Labels display text. Let’s add one to our window:
use horizon_lattice::prelude::*;
fn main() -> Result<(), horizon_lattice::LatticeError> {
let app = Application::new()?;
// Create a window
let mut window = Window::new("Hello, World!")
.with_size(400.0, 300.0);
// Create a label
let label = Label::new("Hello, World!");
// Set the label as the window's content widget
window.set_content_widget(label.object_id());
window.show();
app.run()
}
Run this and you’ll see “Hello, World!” displayed in the window.
Step 4: Style the Label
Labels support various styling options:
use horizon_lattice::prelude::*;
use horizon_lattice::render::HorizontalAlign;
fn main() -> Result<(), horizon_lattice::LatticeError> {
let app = Application::new()?;
let mut window = Window::new("Hello, World!")
.with_size(400.0, 300.0);
// Create a styled label
let label = Label::new("Hello, World!")
.with_horizontal_align(HorizontalAlign::Center)
.with_text_color(Color::from_rgb8(50, 100, 200));
window.set_content_widget(label.object_id());
window.show();
app.run()
}
Now the text is centered and colored blue.
Label Options
Labels support many display options:
use horizon_lattice::widget::widgets::{Label, ElideMode};
// Word wrapping for long text
let wrapped = Label::new("This is a very long text that will wrap to multiple lines")
.with_word_wrap(true);
// Text elision (truncation with "...")
let elided = Label::new("very_long_filename_that_doesnt_fit.txt")
.with_elide_mode(ElideMode::Right); // Shows "very_long_filen..."
// Rich text with HTML
let rich = Label::from_html("Hello <b>bold</b> and <i>italic</i>!");
Complete Example
Here’s the complete Hello World application:
use horizon_lattice::prelude::*;
use horizon_lattice::render::HorizontalAlign;
fn main() -> Result<(), horizon_lattice::LatticeError> {
// Initialize the application
let app = Application::new()?;
// Create the main window
let mut window = Window::new("Hello, World!")
.with_size(400.0, 300.0);
// Create a centered, styled label
let label = Label::new("Hello, Horizon Lattice!")
.with_horizontal_align(HorizontalAlign::Center)
.with_text_color(Color::from_rgb8(50, 100, 200));
// Set up the window
window.set_content_widget(label.object_id());
window.show();
// Run until window is closed
app.run()
}
Understanding the Code
Application Singleton
let app = Application::new()?;
The Application is a singleton - only one can exist per process. It:
- Initializes the graphics system (wgpu)
- Sets up the event loop (winit)
- Registers the main thread for thread-safety checks
- Creates the global object registry
Window Lifecycle
let mut window = Window::new("Title")
.with_size(400.0, 300.0);
window.show();
Windows are created hidden by default. Call show() to make them visible. The builder pattern (with_* methods) allows fluent configuration.
Content Widget
window.set_content_widget(label.object_id());
Each window has a content widget that fills its content area. You pass the widget’s ObjectId (obtained via object_id()). For more complex UIs, you’ll set a ContainerWidget with a layout as the content widget.
Event Loop
app.run()
This starts the event loop, which:
- Processes user input (mouse, keyboard)
- Dispatches signals
- Redraws widgets as needed
- Handles window management
The function blocks until all windows are closed (or Application::quit() is called).
Run It
cargo run
You should see a window with centered blue text saying “Hello, Horizon Lattice!”.
Next Steps
- Button Clicks - Add interactivity with buttons and signals
- Forms and Validation - Build input forms with layouts
- Basic Concepts - Learn about the widget system in depth