Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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