Files
owlry/src/ui/result_row.rs
vikingowl a582f0181c feat: bundle Weather Icons via GResources
Replace emoji icons with proper SVG icons loaded from GResources:

- Add Weather Icons (Erik Flowers) for weather conditions
- Add music note icon for media player widget
- Add tomato icon for pomodoro timer
- Create GResource manifest and build.rs for compilation
- Update providers to use resource paths for icons
- Image::from_resource() loads icons from compiled bundle

This ensures icons display consistently regardless of user's
installed icon theme. Weather icons are OFL licensed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 19:45:33 +01:00

139 lines
5.0 KiB
Rust

use crate::providers::LaunchItem;
use gtk4::prelude::*;
use gtk4::{Box as GtkBox, Image, Label, ListBoxRow, Orientation, Widget};
#[allow(dead_code)]
pub struct ResultRow {
row: ListBoxRow,
}
impl ResultRow {
pub fn new(item: &LaunchItem) -> ListBoxRow {
let row = ListBoxRow::builder()
.selectable(true)
.activatable(true)
.build();
row.add_css_class("owlry-result-row");
let hbox = GtkBox::builder()
.orientation(Orientation::Horizontal)
.spacing(12)
.margin_top(8)
.margin_bottom(8)
.margin_start(12)
.margin_end(12)
.build();
// Icon - handle GResource paths, file paths, icon names, and fallbacks
let icon_widget: Widget = if let Some(icon_path) = &item.icon {
let img = if icon_path.starts_with("/org/owlry/launcher/icons/") {
// GResource path - load from bundled resources
Image::from_resource(icon_path)
} else if icon_path.starts_with('/') {
// Absolute file path
Image::from_file(icon_path)
} else {
// Icon theme name
Image::from_icon_name(icon_path)
};
img.set_pixel_size(32);
img.add_css_class("owlry-result-icon");
img.upcast()
} else {
// Default icon based on provider type
let default_icon = match item.provider {
crate::providers::ProviderType::Application => "application-x-executable",
crate::providers::ProviderType::Bookmarks => "user-bookmarks",
crate::providers::ProviderType::Calculator => "accessories-calculator",
crate::providers::ProviderType::Clipboard => "edit-paste",
crate::providers::ProviderType::Command => "utilities-terminal",
crate::providers::ProviderType::Dmenu => "view-list-symbolic",
crate::providers::ProviderType::Emoji => "face-smile",
crate::providers::ProviderType::Files => "folder",
crate::providers::ProviderType::Scripts => "application-x-executable",
crate::providers::ProviderType::Ssh => "network-server",
crate::providers::ProviderType::System => "system-shutdown",
crate::providers::ProviderType::Uuctl => "system-run",
crate::providers::ProviderType::WebSearch => "web-browser",
// Widget providers now have icons set, but keep fallbacks
crate::providers::ProviderType::Weather => "weather-clear-symbolic",
crate::providers::ProviderType::MediaPlayer => "media-playback-start-symbolic",
crate::providers::ProviderType::Pomodoro => "alarm-symbolic",
};
let img = Image::from_icon_name(default_icon);
img.set_pixel_size(32);
img.add_css_class("owlry-result-icon");
img.upcast()
};
// Text container
let text_box = GtkBox::builder()
.orientation(Orientation::Vertical)
.hexpand(true)
.valign(gtk4::Align::Center)
.build();
// Name label
let name_label = Label::builder()
.label(&item.name)
.halign(gtk4::Align::Start)
.ellipsize(gtk4::pango::EllipsizeMode::End)
.build();
name_label.add_css_class("owlry-result-name");
// Description label
if let Some(desc) = &item.description {
let desc_label = Label::builder()
.label(desc)
.halign(gtk4::Align::Start)
.ellipsize(gtk4::pango::EllipsizeMode::End)
.build();
desc_label.add_css_class("owlry-result-description");
text_box.append(&name_label);
text_box.append(&desc_label);
} else {
text_box.append(&name_label);
}
// Tag badges (show first 3 tags)
if !item.tags.is_empty() {
let tags_box = GtkBox::builder()
.orientation(Orientation::Horizontal)
.spacing(4)
.halign(gtk4::Align::Start)
.build();
for tag in item.tags.iter().take(3) {
let tag_label = Label::builder()
.label(tag)
.build();
tag_label.add_css_class("owlry-tag-badge");
tags_box.append(&tag_label);
}
text_box.append(&tags_box);
}
// Provider badge
let badge = Label::builder()
.label(&item.provider.to_string())
.halign(gtk4::Align::End)
.valign(gtk4::Align::Center)
.build();
badge.add_css_class("owlry-result-badge");
badge.add_css_class(&format!("owlry-badge-{}", item.provider));
hbox.append(&icon_widget);
hbox.append(&text_box);
hbox.append(&badge);
row.set_child(Some(&hbox));
row
}
}