Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/LiveSplit/livesplit-core/llms.txt

Use this file to discover all available pages before exploring further.

Overview

LayoutEditor (exposed in Rust as layout::Editor) wraps a Layout and provides a safe, interactive editing API. It guarantees that all structural invariants of the layout are upheld regardless of which operations are applied — for example, you cannot remove the last remaining top-level component. All components, including those nested inside Group and Carousel containers, are presented through a single flat list. Each entry carries an indentation level that conveys its depth in the component tree. Operations such as selection, addition, removal, and movement all use flat indices into this unified view. The editor tracks a selected component at all times. Most mutation operations act on the currently selected component.

Construction & Finalization

Editor::new(layout: Layout) -> Result<Editor, Error>

Creates a new LayoutEditor for the given layout. Returns an error (Error::EmptyLayout) if the layout contains no components, because the editor requires at least one component to be selected at all times.
use livesplit_core::layout::Editor;

let editor = Editor::new(layout).expect("Layout must not be empty");

Editor::close(self) -> Layout

Finalizes editing and returns the modified Layout. To implement a Cancel button, simply drop the returned Layout instead of using it.
let modified_layout = editor.close();
// or, to cancel:
drop(editor.close());

Inspecting Editor State

state(image_cache: &mut ImageCache, lang: Lang) -> State

Returns the current LayoutEditor state as a layout::editor::State value. This describes the flat component list, indentation levels, which actions are currently available (the Buttons sub-struct), the currently selected component index, and the settings descriptions for both the selected component and the general layout. Renderers should call this after every mutation to refresh their UI.
let editor_state = editor.state(&mut image_cache, lang);
// editor_state.components — Vec<String> of component names
// editor_state.selected_component — flat index of the selection
// editor_state.buttons.can_remove — whether remove is available
// editor_state.component_settings — SettingsDescription for selected component
// editor_state.general_settings — SettingsDescription for layout-wide settings

layout_state(image_cache: &mut ImageCache, timer: &Snapshot, lang: Lang) -> LayoutState

Calculates the live LayoutState as it would appear to a runner, while the layout is still being edited. The currently selected component is highlighted via selected_component in the returned state.
let preview = editor.layout_state(&mut image_cache, &timer.snapshot(), lang);

update_layout_state(state: &mut LayoutState, image_cache: &mut ImageCache, timer: &Snapshot, lang: Lang)

In-place variant of layout_state. Reuses an existing LayoutState allocation.

Component Selection

select(index: usize)

Selects the component at the given flat index. The selection controls which component is affected by remove_component, move_component_up, move_component_down, duplicate_component, and the settings accessors. Providing an index beyond the end of the flat list has no effect.
editor.select(2); // select the third entry in the flat list

Component Management

add_component<C: Into<Component>>(component: C)

Adds a component to the layout. If the currently selected entry is an empty-group placeholder, the new component is inserted as the first child of that group. Otherwise, the component is inserted as a sibling immediately after the currently selected component (and after all of its children, in the case of a group or carousel). The newly added component becomes the selected component.
use livesplit_core::component::Timer;

editor.add_component(Timer::new());

remove_component()

Removes the currently selected component and all its children (when it is a group or carousel). At the top level, at least one component must always remain; the operation is silently ignored if it would violate that constraint, or if a placeholder is selected. After removal, the next sibling becomes selected; if there is none, the previous sibling is selected instead.
editor.remove_component();

can_remove_component() -> bool

Returns true if the currently selected component can be removed.

move_component_up() / move_component_down()

Swaps the selected component with its previous or next sibling within the same parent. The selection follows the component. Has no effect if the component is already at the first or last position, or if a placeholder is selected.
editor.move_component_up();
editor.move_component_down();

can_move_component_up() -> bool / can_move_component_down() -> bool

Predicate versions that tell you whether the corresponding move is possible.

move_component(dst_flat_index: usize)

Moves the selected component to an arbitrary position in the flat list, potentially crossing group boundaries. Moving a component into its own subtree is not allowed. If the destination is an empty-group placeholder, the component is inserted as the first child of that group.
editor.move_component(0); // move to the top of the list

duplicate_component()

Creates a deep clone of the selected component and inserts it immediately after the original. The duplicate becomes the new selection. Placeholders cannot be duplicated.
editor.duplicate_component();

can_duplicate_component() -> bool

Returns true if the currently selected component can be duplicated.

Settings

set_component_settings_value(index: usize, value: Value)

Sets a setting of the selected component by its index in the SettingsDescription. The types must be compatible; mismatched types or out-of-bounds indices will panic. Has no effect when a placeholder is selected.
use livesplit_core::settings::Value;

editor.set_component_settings_value(0, Value::from("My Label"));

set_general_settings_value(index: usize, value: Value, image_cache: &ImageCache)

Sets a general layout setting (background, fonts, colors, direction) by its index in the general SettingsDescription.
editor.set_general_settings_value(0, Value::from(my_background), &image_cache);

Full Example

use livesplit_core::{Layout, layout::Editor, component::{Timer, Splits, Title}};
use livesplit_core::settings::ImageCache;

// Open a layout for editing (must have at least one component)
let layout = Layout::default_layout(Default::default());
let mut editor = Editor::new(layout).unwrap();

// Add more components
editor.add_component(Timer::new());

// Select the first component and move it down
editor.select(0);
editor.move_component_down();

// Remove the currently selected component
editor.remove_component();

// Inspect the editor's state for rendering
let mut image_cache = ImageCache::new();
let state = editor.state(&mut image_cache, Default::default());
println!("Components: {:?}", state.components);

// Finalize and get the modified layout back
let modified_layout = editor.close();

C API

C functionRust equivalent
LayoutEditor_new(layout)Editor::new(layout)
LayoutEditor_close(this)editor.close()
LayoutEditor_state(this, image_cache, lang)editor.state(...)
LayoutEditor_state_as_json(this, image_cache, lang)JSON-encoded editor state
LayoutEditor_layout_state_as_json(this, image_cache, timer, lang)JSON-encoded layout preview
LayoutEditor_update_layout_state(this, state, image_cache, timer, lang)editor.update_layout_state(...)
LayoutEditor_update_layout_state_as_json(this, state, image_cache, timer, lang)In-place update + JSON
LayoutEditor_select(this, index)editor.select(index)
LayoutEditor_add_component(this, component)editor.add_component(component)
LayoutEditor_remove_component(this)editor.remove_component()
LayoutEditor_move_component_up(this)editor.move_component_up()
LayoutEditor_move_component_down(this)editor.move_component_down()
LayoutEditor_move_component(this, dst_index)editor.move_component(dst_index)
LayoutEditor_duplicate_component(this)editor.duplicate_component()
LayoutEditor_set_component_settings_value(this, index, value)editor.set_component_settings_value(...)
LayoutEditor_set_general_settings_value(this, index, value, image_cache)editor.set_general_settings_value(...)

Build docs developers (and LLMs) love