use winrt_xaml::error::Result;
use winrt_xaml::xaml_native::*;
use windows::core::*;
use windows::Win32::Foundation::*;
use windows::Win32::System::Com::*;
use windows::Win32::System::LibraryLoader::*;
use windows::Win32::UI::WindowsAndMessaging::*;
const WINDOW_WIDTH: i32 = 500;
const WINDOW_HEIGHT: i32 = 600;
fn main() -> Result<()> {
unsafe {
CoInitializeEx(None, COINIT_APARTMENTTHREADED).ok()?;
}
let _xaml_manager = XamlManager::new()?;
let hwnd = create_host_window("Scrollable List Demo", WINDOW_WIDTH, WINDOW_HEIGHT)?;
let mut xaml_source = XamlSource::new()?;
let island_hwnd = xaml_source.attach_to_window(hwnd)?;
unsafe {
ShowWindow(island_hwnd, SW_SHOW);
}
create_scrollable_list(&xaml_source)?;
unsafe {
ShowWindow(hwnd, SW_SHOW);
}
println!("\n╔═══════════════════════════════════════════════════════════════╗");
println!("║ 📜 SCROLLABLE LIST EXAMPLE 📜 ║");
println!("╚═══════════════════════════════════════════════════════════════╝");
println!("");
println!("✨ FEATURES:");
println!(" • ScrollViewer with vertical scrolling");
println!(" • 30 styled items in a list");
println!(" • Automatic scrollbar when content overflows");
println!(" • Modern dark theme design");
println!("");
println!("🖱️ USE:");
println!(" • Scroll with mouse wheel or drag scrollbar");
println!(" • Content is taller than window");
println!("");
println!("🎬 Close window to exit\n");
unsafe {
let mut msg = MSG::default();
while GetMessageW(&mut msg, None, 0, 0).as_bool() {
let _ = TranslateMessage(&msg);
DispatchMessageW(&msg);
}
CoUninitialize();
}
Ok(())
}
fn create_scrollable_list(xaml_source: &XamlSource) -> Result<()> {
let container = XamlStackPanel::new()?;
container.set_vertical(true)?;
container.set_spacing(0.0)?;
container.set_background(0xFF1A1A1A)?; container.set_padding(0.0, 0.0, 0.0, 0.0)?;
let title_panel = XamlStackPanel::new()?;
title_panel.set_vertical(true)?;
title_panel.set_background(0xFF0078D4)?; title_panel.set_padding(25.0, 20.0, 25.0, 20.0)?;
let title = XamlTextBlock::new()?;
title.set_text("📜 Scrollable Item List")?;
title.set_font_size(28.0)?;
title.set_font_weight(700)?; title.set_foreground(0xFFFFFFFF)?; title_panel.add_child(&title.as_uielement())?;
let subtitle = XamlTextBlock::new()?;
subtitle.set_text("Scroll down to see all 30 items")?;
subtitle.set_font_size(14.0)?;
subtitle.set_foreground(0xFFE0E0E0)?; subtitle.set_margin(0.0, 5.0, 0.0, 0.0)?;
title_panel.add_child(&subtitle.as_uielement())?;
container.add_child(&title_panel.as_uielement())?;
let scroll_viewer = XamlScrollViewer::new()?;
scroll_viewer.set_vertical_scroll_mode(ScrollMode::Enabled)?;
scroll_viewer.set_horizontal_scroll_mode(ScrollMode::Disabled)?;
scroll_viewer.set_vertical_scrollbar_visibility(ScrollBarVisibility::Auto)?;
let content_panel = XamlStackPanel::new()?;
content_panel.set_vertical(true)?;
content_panel.set_spacing(8.0)?;
content_panel.set_padding(20.0, 20.0, 20.0, 20.0)?;
content_panel.set_background(0xFF1A1A1A)?;
let colors = vec![
(0xFF00D4FF, "Cyan"),
(0xFF00FF9F, "Green"),
(0xFFFF8C00, "Orange"),
(0xFFE74856, "Red"),
(0xFF0078D4, "Blue"),
(0xFFB4009E, "Purple"),
];
for i in 1..=30 {
let item_panel = XamlStackPanel::new()?;
item_panel.set_vertical(false)?;
item_panel.set_spacing(15.0)?;
item_panel.set_background(0xFF2D2D2D)?; item_panel.set_padding(18.0, 15.0, 18.0, 15.0)?;
item_panel.set_corner_radius(10.0)?;
let color_index = (i - 1) % colors.len();
let (badge_color, _color_name) = colors[color_index];
let badge = XamlTextBlock::new()?;
badge.set_text(&format!("{}", i))?;
badge.set_font_size(20.0)?;
badge.set_font_weight(700)?;
badge.set_foreground(badge_color)?;
badge.set_margin(0.0, 0.0, 10.0, 0.0)?;
item_panel.add_child(&badge.as_uielement())?;
let item_text = XamlTextBlock::new()?;
item_text.set_text(&format!("List Item #{} - This is a scrollable item", i))?;
item_text.set_font_size(16.0)?;
item_text.set_foreground(0xFFFFFFFF)?; item_panel.add_child(&item_text.as_uielement())?;
content_panel.add_child(&item_panel.as_uielement())?;
}
scroll_viewer.set_content(&content_panel.as_uielement())?;
container.add_child(&scroll_viewer.as_uielement())?;
xaml_source.set_content_element(&container.as_uielement())?;
Ok(())
}
fn create_host_window(title: &str, width: i32, height: i32) -> Result<HWND> {
unsafe {
let class_name = w!("WinRTXamlHostWindow");
let h_instance = HINSTANCE(GetModuleHandleW(None).unwrap_or_default().0);
let wc = WNDCLASSW {
lpfnWndProc: Some(window_proc),
hInstance: h_instance,
lpszClassName: class_name,
hCursor: LoadCursorW(None, IDC_ARROW).unwrap_or_default(),
..Default::default()
};
RegisterClassW(&wc);
let hwnd = CreateWindowExW(
WINDOW_EX_STYLE::default(),
class_name,
&HSTRING::from(title),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
None,
None,
h_instance,
None,
)?;
Ok(hwnd)
}
}
unsafe extern "system" fn window_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
match msg {
WM_DESTROY => {
PostQuitMessage(0);
LRESULT(0)
}
_ => DefWindowProcW(hwnd, msg, wparam, lparam),
}
}