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

Weather Panel and Forecast List

The Weather Panel is the right side of the Weather App. It displays the weather information for the city selected in the sidebar.

This panel has two responsibilities:

  • Show the current weather conditions
  • Show the 7-day forecast list

However, when the application first starts, no city is selected, so no weather data should be visible.

To handle this situation cleanly, the Weather App uses a state-based UI layout.

Managing Panel States with GtkStack

The weather panel uses a GtkStack to switch between two states.

#![allow(unused)]
fn main() {
let content_stack = gtk::Stack::new();
content_stack.set_hexpand(true);
content_stack.set_vexpand(true);
}

The stack contains two pages:

#![allow(unused)]
fn main() {
content_stack.add_named(&right_empty, Some("empty"));
content_stack.add_named(&content, Some("weather"));
content_stack.set_visible_child_name("empty");
}

These represent two possible UI states.

StateMeaning
emptyNo city has been selected
weatherWeather data is available

When the application starts, the empty page is shown. After weather data is successfully fetched, the UI switches to the weather page.

Building the Weather Layout

Inside the weather page, the interface is built using a vertical layout container.

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

This container organizes the weather widgets in a vertical order.

The layout contains:

  • Weather icon
  • City title
  • Weather description
  • Current temperature
  • Forecast heading
  • Forecast list

Each component has a specific role in presenting the weather information.

Displaying the City Name

The selected city name is shown using a label.

#![allow(unused)]
fn main() {
let city_title = gtk::Label::new(Some(""));
city_title.add_css_class("title-1");
city_title.set_halign(gtk::Align::Center);
}

When weather data is applied, the label is updated dynamically:

#![allow(unused)]
fn main() {
city_title.set_text(&format!("Weather in {name}"));
}

This demonstrates how UI elements react to updated application data.

Showing Current Weather

The current weather is displayed using a combination of an icon, a description label, and a temperature label.

For example, the temperature label is created as follows:

#![allow(unused)]
fn main() {
let now_temp = gtk::Label::new(Some(""));
now_temp.add_css_class("title-4");
now_temp.set_halign(gtk::Align::Center);
}

When the weather fetch completes, the UI updates:

#![allow(unused)]
fn main() {
now_temp.set_text(&format!("Now: {:.1} °C", now));
}

The weather condition code returned by the API is converted into a text description and icon before being displayed.

This ensures the UI shows user-friendly information rather than raw numeric codes.

Forecast List

Below the current temperature, the Weather App displays the 7-day forecast.

The forecast is implemented using a ListBox.

#![allow(unused)]
fn main() {
let forecast_list = gtk::ListBox::new();
forecast_list.add_css_class("boxed-list");
forecast_list.set_selection_mode(gtk::SelectionMode::None);
}

The ListBox widget is suitable for this purpose because it allows multiple rows stacked vertically with GNOME styling.

Rows are not interactive, so selection mode is disabled.

Rebuilding the Forecast List

Each time new weather data is fetched, the forecast list is rebuilt.

First, existing rows are removed:

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

This step is important because it prevents previous forecast entries from remaining visible.

After clearing the list, new rows are created for each forecast day.

A simplified version of the row creation looks like this:

#![allow(unused)]
fn main() {
let row = ActionRow::new();
row.set_title(&date);
row.set_subtitle(&format!(
    "{}  •  Max {:.1}°C  Min {:.1}°C",
    weather_text,
    max,
    min
));

forecast_list.append(&row);
}

Each row represents one forecast day and displays:

  • the forecast date
  • the weather description
  • the maximum temperature
  • the minimum temperature

An icon corresponding to the weather condition is also added to the row.

Where the Forecast Data Comes From

The forecast list receives its data from the weather fetch function.

The function returns structured forecast information in the form:

#![allow(unused)]
fn main() {
Vec<(String, f64, f64, i32)>
}

Each tuple contains:

  • the forecast date
  • the maximum temperature
  • the minimum temperature
  • the weather code

The UI layer simply loops through this data and creates a row for each day.

This design ensures that the UI only displays data and does not calculate it.

Applying Weather Data to the Panel

When the background fetch completes successfully, the weather panel is updated.

First, the panel switches from the empty state to the weather state.

#![allow(unused)]
fn main() {
content_stack.set_visible_child_name("weather");
}

Then the labels and forecast list are updated using the returned data.

This dynamic update ensures that the UI always reflects the latest weather information.

Handling Errors in the Panel

If an error occurs during the weather request, the panel displays an informative message.

For example:

#![allow(unused)]
fn main() {
now_temp.set_text("No city found. Try another spelling.");
forecast_label.set_visible(false);
forecast_list.set_visible(false);
}

This ensures that:

  • the user sees a clear error message
  • outdated forecast rows are hidden
  • the interface remains consistent

Handling errors visually is an important part of creating a user-friendly application.

Expected Behavior

When the Weather App runs, the user should observe the following behavior.

At startup:

  • the weather panel shows an empty state

After selecting a city:

  • the city name appears
  • the current temperature appears
  • the weather description and icon appear
  • the 7-day forecast list appears

If an invalid city is entered:

  • a message is shown instead of weather data

This confirms that the panel correctly reacts to changes in application state.