Add main window with sidebar navigation
AdwNavigationSplitView with six sidebar items (Log, History, Charts, Budgets, Recurring, Settings) and placeholder StatusPage content that switches via crossfade transition on selection.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
mod window;
|
||||
|
||||
use adw::prelude::*;
|
||||
use adw::Application;
|
||||
|
||||
@@ -13,12 +15,6 @@ fn main() {
|
||||
}
|
||||
|
||||
fn build_ui(app: &Application) {
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.title("Outlay")
|
||||
.default_width(900)
|
||||
.default_height(600)
|
||||
.build();
|
||||
|
||||
window.present();
|
||||
let main_window = window::MainWindow::new(app);
|
||||
main_window.window.present();
|
||||
}
|
||||
|
||||
122
outlay-gtk/src/window.rs
Normal file
122
outlay-gtk/src/window.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use adw::prelude::*;
|
||||
|
||||
pub struct MainWindow {
|
||||
pub window: adw::ApplicationWindow,
|
||||
pub split_view: adw::NavigationSplitView,
|
||||
pub content_stack: gtk::Stack,
|
||||
}
|
||||
|
||||
struct SidebarItem {
|
||||
id: &'static str,
|
||||
label: &'static str,
|
||||
icon: &'static str,
|
||||
}
|
||||
|
||||
const SIDEBAR_ITEMS: &[SidebarItem] = &[
|
||||
SidebarItem { id: "log", label: "Log", icon: "list-add-symbolic" },
|
||||
SidebarItem { id: "history", label: "History", icon: "document-open-recent-symbolic" },
|
||||
SidebarItem { id: "charts", label: "Charts", icon: "utilities-system-monitor-symbolic" },
|
||||
SidebarItem { id: "budgets", label: "Budgets", icon: "wallet2-symbolic" },
|
||||
SidebarItem { id: "recurring", label: "Recurring", icon: "view-refresh-symbolic" },
|
||||
SidebarItem { id: "settings", label: "Settings", icon: "emblem-system-symbolic" },
|
||||
];
|
||||
|
||||
impl MainWindow {
|
||||
pub fn new(app: &adw::Application) -> Self {
|
||||
let content_stack = gtk::Stack::new();
|
||||
content_stack.set_transition_type(gtk::StackTransitionType::Crossfade);
|
||||
|
||||
for item in SIDEBAR_ITEMS {
|
||||
let page = adw::StatusPage::builder()
|
||||
.title(item.label)
|
||||
.icon_name(item.icon)
|
||||
.build();
|
||||
content_stack.add_named(&page, Some(item.id));
|
||||
}
|
||||
|
||||
let sidebar_list = gtk::ListBox::new();
|
||||
sidebar_list.set_selection_mode(gtk::SelectionMode::Single);
|
||||
sidebar_list.add_css_class("navigation-sidebar");
|
||||
|
||||
for item in SIDEBAR_ITEMS {
|
||||
let row = Self::make_sidebar_row(item);
|
||||
sidebar_list.append(&row);
|
||||
}
|
||||
|
||||
let content_stack_ref = content_stack.clone();
|
||||
sidebar_list.connect_row_selected(move |_, row| {
|
||||
if let Some(row) = row {
|
||||
let idx = row.index() as usize;
|
||||
if idx < SIDEBAR_ITEMS.len() {
|
||||
content_stack_ref.set_visible_child_name(SIDEBAR_ITEMS[idx].id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Select the first row by default
|
||||
if let Some(first_row) = sidebar_list.row_at_index(0) {
|
||||
sidebar_list.select_row(Some(&first_row));
|
||||
}
|
||||
|
||||
let sidebar_scroll = gtk::ScrolledWindow::builder()
|
||||
.hscrollbar_policy(gtk::PolicyType::Never)
|
||||
.vexpand(true)
|
||||
.child(&sidebar_list)
|
||||
.build();
|
||||
|
||||
let sidebar_toolbar = adw::ToolbarView::new();
|
||||
sidebar_toolbar.add_top_bar(&adw::HeaderBar::new());
|
||||
sidebar_toolbar.set_content(Some(&sidebar_scroll));
|
||||
|
||||
let sidebar_page = adw::NavigationPage::builder()
|
||||
.title("Outlay")
|
||||
.child(&sidebar_toolbar)
|
||||
.build();
|
||||
|
||||
let content_toolbar = adw::ToolbarView::new();
|
||||
content_toolbar.add_top_bar(&adw::HeaderBar::new());
|
||||
content_toolbar.set_content(Some(&content_stack));
|
||||
|
||||
let content_page = adw::NavigationPage::builder()
|
||||
.title("Outlay")
|
||||
.child(&content_toolbar)
|
||||
.build();
|
||||
|
||||
let split_view = adw::NavigationSplitView::new();
|
||||
split_view.set_sidebar(Some(&sidebar_page));
|
||||
split_view.set_content(Some(&content_page));
|
||||
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.title("Outlay")
|
||||
.default_width(900)
|
||||
.default_height(600)
|
||||
.content(&split_view)
|
||||
.build();
|
||||
|
||||
MainWindow {
|
||||
window,
|
||||
split_view,
|
||||
content_stack,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_sidebar_row(item: &SidebarItem) -> gtk::ListBoxRow {
|
||||
let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 12);
|
||||
hbox.set_margin_top(8);
|
||||
hbox.set_margin_bottom(8);
|
||||
hbox.set_margin_start(12);
|
||||
hbox.set_margin_end(12);
|
||||
|
||||
let icon = gtk::Image::from_icon_name(item.icon);
|
||||
let label = gtk::Label::new(Some(item.label));
|
||||
label.set_halign(gtk::Align::Start);
|
||||
|
||||
hbox.append(&icon);
|
||||
hbox.append(&label);
|
||||
|
||||
let row = gtk::ListBoxRow::new();
|
||||
row.set_child(Some(&hbox));
|
||||
row
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user