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

Sidebar Layout Structure and Design in the Weather App

The sidebar in the Weather App acts as the navigation layer of the application.

Its responsibility is not to display weather data. Instead, it manages:

  • Searching for cities
  • Adding new cities
  • Displaying saved cities
  • Showing an empty state when no cities exist

The sidebar is built as a vertical layout container.

Creating the Sidebar Container

In the Weather App, the sidebar is defined as:

#![allow(unused)]
fn main() {
let sidebar = gtk::Box::new(gtk::Orientation::Vertical, 12);
set_margins(&sidebar, 12);
}

A vertical Box is used because the elements must appear from top to bottom:

  1. Search row
  2. Empty state or city list

The spacing (12) ensures visual separation between elements. Margins improve readability and follow GNOME spacing guidelines.

Search Row (Search + Add Button)

At the top of the sidebar, a horizontal layout is created:

#![allow(unused)]
fn main() {
let search_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);

let search = gtk::SearchEntry::new();
search.set_hexpand(true);

let add_city_btn = gtk::Button::from_icon_name("list-add-symbolic");
}

This row groups:

  • A SearchEntry
  • A “+” button

The search field expands horizontally, while the add button stays compact.

Placing them together improves usability because:

  • Search and add actions are conceptually related
  • Users immediately understand where to interact The append calls also make the widget hierarchy explicit. They show that both controls belong to the same top interaction row inside the sidebar.

Empty State Using StatusPage

When no cities are stored, the sidebar displays a StatusPage:

#![allow(unused)]
fn main() {
let sidebar_empty = StatusPage::new();
sidebar_empty.set_title("Add first city");
sidebar_empty.set_description(Some(
    "Hit '+' to add a city to display the weather"
));
}

This prevents the sidebar from appearing blank.

Instead of showing an empty list, the app guides the user.

The empty state is toggled using logic like:

#![allow(unused)]
fn main() {
empty_page.set_visible(is_empty);
scroller.set_visible(!is_empty);
}

This ensures that only one of the following is visible:

  • StatusPage (when empty)
  • City list (when cities exist)

This improves clarity and prevents confusion.

City List Container

Saved cities are displayed inside a ListBox:

#![allow(unused)]
fn main() {
let city_list = gtk::ListBox::new();
city_list.set_selection_mode(gtk::SelectionMode::None);
}

Each city becomes an ActionRow:

#![allow(unused)]
fn main() {
let row = ActionRow::new();
row.set_title(city);
row.set_subtitle("Tap to view weather");
}

Using ActionRow provides:

  • Clean GNOME styling
  • Built-in title/subtitle layout
  • Easy click handling

The list is placed inside a scrollable container:

#![allow(unused)]
fn main() {
let scroller = gtk::ScrolledWindow::new();
scroller.set_child(Some(&city_list));
}

This ensures the sidebar remains usable even with many cities.

Dynamic Sidebar Updates

Whenever cities change, the sidebar rebuilds:

#![allow(unused)]
fn main() {
clear_listbox(&city_list);
}

Then it re-adds rows from the updated state.

This keeps the UI consistent with stored data.

The sidebar does not directly manage weather logic. It only triggers actions when a city is selected.

Design Decisions

The sidebar follows a clear design structure:

  • Top section → interaction (search + add)
  • Middle section → dynamic content (empty or list)
  • Scrollable list for scalability
  • No duplicated add buttons
  • Clear empty-state guidance

This separation makes the code easier to maintain.

It also teaches beginners:

  • How to structure UI layers
  • How to toggle visibility properly
  • How to separate navigation from content logic

Architectural Role

Within the application hierarchy:

NavigationSplitView
    ├── Sidebar (Navigation)
    └── Content (Weather)

The sidebar acts purely as a navigation controller.

It does not fetch weather data itself. It signals which city should be displayed.

This separation improves modularity and onboarding clarity.